Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (revision 23669) +++ apps/plugins/CATEGORIES (working copy) @@ -55,6 +55,7 @@ mp3_encoder,apps mpegplayer,viewers nim,games +nofrendo,viewers oscilloscope,demos pacbox,games pdbox,viewers Index: apps/plugins/SUBDIRS =================================================================== --- apps/plugins/SUBDIRS (revision 23669) +++ apps/plugins/SUBDIRS (working copy) @@ -24,6 +24,7 @@ sudoku reversi goban +nofrendo #ifdef HAVE_LCD_COLOR png #endif Index: apps/plugins/viewers.config =================================================================== --- apps/plugins/viewers.config (revision 23669) +++ apps/plugins/viewers.config (working copy) @@ -1,3 +1,4 @@ +nes,viewers/nofrendo,6 ch8,viewers/chip8,0 txt,viewers/viewer,1 nfo,viewers/viewer,1 Index: apps/plugins/nofrendo/vrcvisnd.c =================================================================== --- apps/plugins/nofrendo/vrcvisnd.c (revision 0) +++ apps/plugins/nofrendo/vrcvisnd.c (revision 0) @@ -0,0 +1,278 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** vrcvisnd.c +** +** VRCVI sound hardware emulation +** $Id: vrcvisnd.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +typedef struct vrcvirectangle_s +{ + int enabled; + + uint8 reg[3]; + + float accum; + uint8 adder; + + int32 freq; + int32 volume; + uint8 duty_flip; +} vrcvirectangle_t; + +typedef struct vrcvisawtooth_s +{ + int enabled; + + uint8 reg[3]; + + float accum; + uint8 adder; + uint8 output_acc; + + int32 freq; + uint8 volume; +} vrcvisawtooth_t; + +typedef struct vrcvisnd_s +{ + vrcvirectangle_t rectangle[2]; + vrcvisawtooth_t saw; + float incsize; +} vrcvisnd_t; + + +static vrcvisnd_t vrcvi; + +/* VRCVI rectangle wave generation */ +static int32 vrcvi_rectangle(vrcvirectangle_t *chan) +{ + /* reg0: 0-3=volume, 4-6=duty cycle + ** reg1: 8 bits of freq + ** reg2: 0-3=high freq, 7=enable + */ + + chan->accum -= vrcvi.incsize; /* # of clocks per wave cycle */ + while (chan->accum < 0) + { + chan->accum += chan->freq; + chan->adder = (chan->adder + 1) & 0x0F; + } + + /* return if not enabled */ + if (0 == chan->enabled) + return 0; + + if (chan->adder < chan->duty_flip) + return -(chan->volume); + else + return chan->volume; +} + +/* VRCVI sawtooth wave generation */ +static int32 vrcvi_sawtooth(vrcvisawtooth_t *chan) +{ + /* reg0: 0-5=phase accumulator bits + ** reg1: 8 bits of freq + ** reg2: 0-3=high freq, 7=enable + */ + + chan->accum -= vrcvi.incsize; /* # of clocks per wav cycle */ + while (chan->accum < 0) + { + chan->accum += chan->freq; + chan->output_acc += chan->volume; + + chan->adder++; + if (7 == chan->adder) + { + chan->adder = 0; + chan->output_acc = 0; + } + } + + /* return if not enabled */ + if (0 == chan->enabled) + return 0; + + return (chan->output_acc >> 3) << 9; +} + +/* mix vrcvi sound channels together */ +static int32 vrcvi_process(void) +{ + int32 output; + + output = vrcvi_rectangle(&vrcvi.rectangle[0]); + output += vrcvi_rectangle(&vrcvi.rectangle[1]); + output += vrcvi_sawtooth(&vrcvi.saw); + + return output; +} + +/* write to registers */ +static void vrcvi_write(uint32 address, uint8 value) +{ + int chan = (address >> 12) - 9; + + switch (address & 0xB003) + { + case 0x9000: + case 0xA000: + vrcvi.rectangle[chan].reg[0] = value; + vrcvi.rectangle[chan].volume = (value & 0x0F) << 8; + vrcvi.rectangle[chan].duty_flip = (value >> 4) + 1; + break; + + case 0x9001: + case 0xA001: + vrcvi.rectangle[chan].reg[1] = value; + vrcvi.rectangle[chan].freq = ((vrcvi.rectangle[chan].reg[2] & 0x0F) << 8) + value + 1; + break; + + case 0x9002: + case 0xA002: + vrcvi.rectangle[chan].reg[2] = value; + vrcvi.rectangle[chan].freq = ((value & 0x0F) << 8) + vrcvi.rectangle[chan].reg[1] + 1; + vrcvi.rectangle[chan].enabled = (value & 0x80) ? 1 : 0; + break; + + case 0xB000: + vrcvi.saw.reg[0] = value; + vrcvi.saw.volume = value & 0x3F; + break; + + case 0xB001: + vrcvi.saw.reg[1] = value; + vrcvi.saw.freq = (((vrcvi.saw.reg[2] & 0x0F) << 8) + value + 1) << 1; + break; + + case 0xB002: + vrcvi.saw.reg[2] = value; + vrcvi.saw.freq = (((value & 0x0F) << 8) + vrcvi.saw.reg[1] + 1) << 1; + vrcvi.saw.enabled = (value & 0x80) ? 1 : 0; + break; + + default: + break; + } +} + +/* reset state of vrcvi sound channels */ +static void vrcvi_reset(void) +{ + int i; + apu_t apu; + + /* get the phase period from the apu */ + apu_getcontext(&apu); + vrcvi.incsize = apu.cycle_rate; + + /* preload regs */ + for (i = 0; i < 3; i++) + { + vrcvi_write(0x9000 + i, 0); + vrcvi_write(0xA000 + i, 0); + vrcvi_write(0xB000 + i, 0); + } +} + +static apu_memwrite vrcvi_memwrite[] = +{ + { 0x9000, 0x9002, vrcvi_write }, /* vrc6 */ + { 0xA000, 0xA002, vrcvi_write }, + { 0xB000, 0xB002, vrcvi_write }, + { -1, -1, NULL } +}; + +apuext_t vrcvi_ext = +{ + NULL, /* no init */ + NULL, /* no shutdown */ + vrcvi_reset, + vrcvi_process, + NULL, /* no reads */ + vrcvi_memwrite +}; + +/* +** $Log: vrcvisnd.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/05 22:21:00 matt +** help me! +** +** Revision 1.1 2000/10/24 12:20:00 matt +** changed directory structure +** +** Revision 1.17 2000/10/10 13:58:18 matt +** stroustrup squeezing his way in the door +** +** Revision 1.16 2000/10/03 11:56:20 matt +** better support for optional sound ext routines +** +** Revision 1.15 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.14 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.13 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.12 2000/07/30 04:32:59 matt +** no more apu_getcyclerate hack +** +** Revision 1.11 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.10 2000/07/06 11:42:41 matt +** forgot to remove FDS register range +** +** Revision 1.9 2000/07/04 04:51:41 matt +** cleanups +** +** Revision 1.8 2000/07/03 02:18:53 matt +** much better external module exporting +** +** Revision 1.7 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.6 2000/06/20 00:08:58 matt +** changed to driver based API +** +** Revision 1.5 2000/06/09 16:49:02 matt +** removed all floating point from sound generation +** +** Revision 1.4 2000/06/09 15:12:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_apu.h =================================================================== --- apps/plugins/nofrendo/nes_apu.h (revision 0) +++ apps/plugins/nofrendo/nes_apu.h (revision 0) @@ -0,0 +1,349 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_apu.h +** +** NES APU emulation header file +** $Id: nes_apu.h,v 1.1 2001/04/27 12:54:40 neil Exp $ +*/ + +#ifndef _NES_APU_H_ +#define _NES_APU_H_ + + +/* define this for realtime generated noise */ +#define REALTIME_NOISE + +#define APU_WRA0 0x4000 +#define APU_WRA1 0x4001 +#define APU_WRA2 0x4002 +#define APU_WRA3 0x4003 +#define APU_WRB0 0x4004 +#define APU_WRB1 0x4005 +#define APU_WRB2 0x4006 +#define APU_WRB3 0x4007 +#define APU_WRC0 0x4008 +#define APU_WRC2 0x400A +#define APU_WRC3 0x400B +#define APU_WRD0 0x400C +#define APU_WRD2 0x400E +#define APU_WRD3 0x400F +#define APU_WRE0 0x4010 +#define APU_WRE1 0x4011 +#define APU_WRE2 0x4012 +#define APU_WRE3 0x4013 + +#define APU_SMASK 0x4015 + +/* length of generated noise */ +#define APU_NOISE_32K 0x7FFF +#define APU_NOISE_93 93 + +#define APU_BASEFREQ 1789772.7272727272727272 + + +/* channel structures */ +/* As much data as possible is precalculated, +** to keep the sample processing as lean as possible +*/ + +typedef struct rectangle_s +{ + uint8 regs[4]; + + int enabled; + + float accum; + int32 freq; + int32 output_vol; + int fixed_envelope; + int holdnote; + uint8 volume; + + int32 sweep_phase; + int32 sweep_delay; + int sweep_on; + uint8 sweep_shifts; + uint8 sweep_length; + int sweep_inc; + + /* this may not be necessary in the future */ + int32 freq_limit; + int32 env_phase; + int32 env_delay; + uint8 env_vol; + + int vbl_length; + uint8 adder; + int duty_flip; +} rectangle_t; + +typedef struct triangle_s +{ + uint8 regs[3]; + + int enabled; + + float accum; + int32 freq; + int32 output_vol; + + uint8 adder; + + int holdnote; + int counter_started; + /* quasi-hack */ + int write_latency; + + int vbl_length; + int linear_length; +} triangle_t; + + +typedef struct noise_s +{ + uint8 regs[3]; + + int enabled; + + float accum; + int32 freq; + int32 output_vol; + + int32 env_phase; + int32 env_delay; + uint8 env_vol; + int fixed_envelope; + int holdnote; + + uint8 volume; + + int vbl_length; + +#ifdef REALTIME_NOISE + uint8 xor_tap; +#else + int short_sample; + int cur_pos; +#endif /* REALTIME_NOISE */ +} noise_t; + +typedef struct dmc_s +{ + uint8 regs[4]; + + /* bodge for timestamp queue */ + int enabled; + + float accum; + int32 freq; + int32 output_vol; + + uint32 address; + uint32 cached_addr; + int dma_length; + int cached_dmalength; + uint8 cur_byte; + + int looping; + int irq_gen; + int irq_occurred; + +} dmc_t; + +enum +{ + APU_FILTER_NONE, + APU_FILTER_LOWPASS, + APU_FILTER_WEIGHTED +}; + +typedef struct +{ + uint32 min_range, max_range; + uint8 (*read_func)(uint32 address); +} apu_memread; + +typedef struct +{ + uint32 min_range, max_range; + void (*write_func)(uint32 address, uint8 value); +} apu_memwrite; + +/* external sound chip stuff */ +typedef struct apuext_s +{ + int (*init)(void); + void (*shutdown)(void); + void (*reset)(void); + int32 (*process)(void); + apu_memread *mem_read; + apu_memwrite *mem_write; +} apuext_t; + + +typedef struct apu_s +{ + rectangle_t rectangle[2]; + triangle_t triangle; + noise_t noise; + dmc_t dmc; + uint8 enable_reg; + + void *buffer; /* pointer to output buffer */ + int num_samples; + + uint8 mix_enable; + int filter_type; + + double base_freq; + float cycle_rate; + + int sample_rate; + int sample_bits; + int refresh_rate; + + void (*process)(void *buffer, int num_samples); + void (*irq_callback)(void); + uint8 (*irqclear_callback)(void); + + /* external sound chip */ + apuext_t *ext; +} apu_t; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Function prototypes */ +extern void apu_setcontext(apu_t *src_apu); +extern void apu_getcontext(apu_t *dest_apu); + +extern void apu_setparams(double base_freq, int sample_rate, int refresh_rate, int sample_bits); +extern apu_t *apu_create(double base_freq, int sample_rate, int refresh_rate, int sample_bits); +extern void apu_destroy(apu_t **apu); + +extern void apu_process(void *buffer, int num_samples); +extern void apu_reset(void); + +extern void apu_setext(apu_t *apu, apuext_t *ext); +extern void apu_setfilter(int filter_type); +extern void apu_setchan(int chan, int enabled); + +extern uint8 apu_read(uint32 address); +extern void apu_write(uint32 address, uint8 value); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _NES_APU_H_ */ + +/* +** $Log: nes_apu.h,v $ +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.3 2000/12/08 02:36:14 matt +** bye bye apu queue (for now) +** +** Revision 1.2 2000/10/28 15:20:59 matt +** irq callbacks in nes_apu +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.28 2000/10/17 11:56:42 matt +** selectable apu base frequency +** +** Revision 1.27 2000/10/10 13:58:18 matt +** stroustrup squeezing his way in the door +** +** Revision 1.26 2000/09/28 23:20:58 matt +** bye bye, fixed point +** +** Revision 1.25 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.24 2000/09/18 02:12:55 matt +** more optimizations +** +** Revision 1.23 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.22 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.21 2000/08/11 02:27:21 matt +** general cleanups, plus apu_setparams routine +** +** Revision 1.20 2000/07/30 04:32:59 matt +** no more apu_getcyclerate hack +** +** Revision 1.19 2000/07/27 02:49:50 matt +** eccentricity in sweeping hardware now emulated correctly +** +** Revision 1.18 2000/07/25 02:25:15 matt +** safer apu_destroy +** +** Revision 1.17 2000/07/23 15:10:54 matt +** hacks for win32 +** +** Revision 1.16 2000/07/23 00:48:15 neil +** Win32 SDL +** +** Revision 1.15 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.14 2000/07/11 02:39:26 matt +** added setcontext() routine +** +** Revision 1.13 2000/07/10 05:29:34 matt +** moved joypad/oam dma from apu to ppu +** +** Revision 1.12 2000/07/04 04:54:48 matt +** minor changes that helped with MAME +** +** Revision 1.11 2000/07/03 02:18:53 matt +** much better external module exporting +** +** Revision 1.10 2000/06/26 05:00:37 matt +** cleanups +** +** Revision 1.9 2000/06/23 03:29:28 matt +** cleaned up external sound inteface +** +** Revision 1.8 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.7 2000/06/20 00:07:35 matt +** added convenience members to apu_t struct +** +** Revision 1.6 2000/06/09 16:49:02 matt +** removed all floating point from sound generation +** +** Revision 1.5 2000/06/09 15:12:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/intro.h =================================================================== --- apps/plugins/nofrendo/intro.h (revision 0) +++ apps/plugins/nofrendo/intro.h (revision 0) @@ -0,0 +1,53 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** intro.h +** +** Nofrendo intro -- 6502 code +** $Id: intro.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _INTRO_H_ +#define _INTRO_H_ + +#include + +extern void intro_get_header(rominfo_t *rominfo); +extern int intro_get_rom(rominfo_t *rominfo); + +#endif /* !_INTRO_H_ */ + +/* +** $Log: intro.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.3 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.2 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.1 2000/07/30 04:29:11 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/vrcvisnd.h =================================================================== --- apps/plugins/nofrendo/vrcvisnd.h (revision 0) +++ apps/plugins/nofrendo/vrcvisnd.h (revision 0) @@ -0,0 +1,70 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** vrcvisnd.h +** +** VRCVI (Konami MMC) sound hardware emulation header +** $Id: vrcvisnd.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _VRCVISND_H_ +#define _VRCVISND_H_ + +#include + +extern apuext_t vrcvi_ext; + +#endif /* _VRCVISND_H_ */ + +/* +** $Log: vrcvisnd.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:00 matt +** changed directory structure +** +** Revision 1.10 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.9 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.8 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.6 2000/06/20 00:08:58 matt +** changed to driver based API +** +** Revision 1.5 2000/06/09 16:49:02 matt +** removed all floating point from sound generation +** +** Revision 1.4 2000/06/09 15:12:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nesinput.c =================================================================== --- apps/plugins/nofrendo/nesinput.c (revision 0) +++ apps/plugins/nofrendo/nesinput.c (revision 0) @@ -0,0 +1,212 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nesinput.c +** +** Event handling system routines +** $Id: nesinput.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* TODO: make a linked list of inputs sources, so they +** can be removed if need be +*/ + +static nesinput_t *nes_input[MAX_CONTROLLERS]; +static int active_entries = 0; + +/* read counters */ +static int pad0_readcount, pad1_readcount, ppad_readcount, ark_readcount; + + +static int retrieve_type(int type) +{ + int i, value = 0; + + for (i = 0; i < active_entries; i++) + { + ASSERT(nes_input[i]); + + if (type == nes_input[i]->type) + value |= nes_input[i]->data; + } + + return value; +} + +static uint8 get_pad0(void) +{ + uint8 value; + + value = (uint8) retrieve_type(INP_JOYPAD0); + + /* mask out left/right simultaneous keypresses */ + if ((value & INP_PAD_UP) && (value & INP_PAD_DOWN)) + value &= ~(INP_PAD_UP | INP_PAD_DOWN); + + if ((value & INP_PAD_LEFT) && (value & INP_PAD_RIGHT)) + value &= ~(INP_PAD_LEFT | INP_PAD_RIGHT); + + /* return (0x40 | value) due to bus conflicts */ + return (0x40 | ((value >> pad0_readcount++) & 1)); +} + +static uint8 get_pad1(void) +{ + uint8 value; + + value = (uint8) retrieve_type(INP_JOYPAD1); + + /* mask out left/right simultaneous keypresses */ + if ((value & INP_PAD_UP) && (value & INP_PAD_DOWN)) + value &= ~(INP_PAD_UP | INP_PAD_DOWN); + + if ((value & INP_PAD_LEFT) && (value & INP_PAD_RIGHT)) + value &= ~(INP_PAD_LEFT | INP_PAD_RIGHT); + + /* return (0x40 | value) due to bus conflicts */ + return (0x40 | ((value >> pad1_readcount++) & 1)); +} + +static uint8 get_zapper(void) +{ + return (uint8) (retrieve_type(INP_ZAPPER)); +} + +static uint8 get_powerpad(void) +{ + int value; + uint8 ret_val = 0; + + value = retrieve_type(INP_POWERPAD); + + if (((value >> 8) >> ppad_readcount) & 1) + ret_val |= 0x10; + if (((value & 0xFF) >> ppad_readcount) & 1) + ret_val |= 0x08; + + ppad_readcount++; + + return ret_val; +} + +static uint8 get_vsdips0(void) +{ + return (retrieve_type(INP_VSDIPSW0)); +} + +static uint8 get_vsdips1(void) +{ + return (retrieve_type(INP_VSDIPSW1)); +} + +static uint8 get_arkanoid(void) +{ + uint8 value = retrieve_type(INP_ARKANOID); + + if ((value >> (7 - ark_readcount++)) & 1) + return 0x02; + else + return 0; +} + +/* return input state for all types indicated (can be ORed together) */ +uint8 input_get(int types) +{ + uint8 value = 0; + + if (types & INP_JOYPAD0) + value |= get_pad0(); + if (types & INP_JOYPAD1) + value |= get_pad1(); + if (types & INP_ZAPPER) + value |= get_zapper(); + if (types & INP_POWERPAD) + value |= get_powerpad(); + if (types & INP_VSDIPSW0) + value |= get_vsdips0(); + if (types & INP_VSDIPSW1) + value |= get_vsdips1(); + if (types & INP_ARKANOID) + value |= get_arkanoid(); + + return value; +} + +/* register an input type */ +void input_register(nesinput_t *input) +{ + if (NULL == input) + return; + + nes_input[active_entries] = input; + active_entries++; +} + +void input_event(nesinput_t *input, int state, int value) +{ + ASSERT(input); + + if (state == INP_STATE_MAKE) + input->data |= value; /* OR it in */ + else /* break state */ + input->data &= ~value; /* mask it out */ +} + +void input_strobe(void) +{ + pad0_readcount = 0; + pad1_readcount = 0; + ppad_readcount = 0; + ark_readcount = 0; +} + +/* +** $Log: nesinput.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.9 2000/09/10 23:25:03 matt +** minor changes +** +** Revision 1.8 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.7 2000/07/23 15:11:45 matt +** removed unused variables +** +** Revision 1.6 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.5 2000/07/04 04:56:50 matt +** include changes +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/config.c =================================================================== --- apps/plugins/nofrendo/config.c (revision 0) +++ apps/plugins/nofrendo/config.c (revision 0) @@ -0,0 +1,464 @@ +/* Nofrendo Configuration Braindead Sample Implementation +** +** $Id: config.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "plugin.h" + +typedef struct myvar_s +{ + struct myvar_s *less, *greater; + char *group, *key, *value; +} myvar_t; + +static myvar_t *myVars = NULL; +static int mySaveNeeded = 0; + + +static void my_destroy(myvar_t **var) +{ + ASSERT(*var); + + if ((*var)->group) + free((*var)->group); + if ((*var)->key) + free((*var)->key); + if ((*var)->value) + free((*var)->value); + free(*var); +} + +static myvar_t *my_create(const char *group, const char *key, const char *value) +{ + myvar_t *var; + + var = malloc(sizeof(*var)); + if (NULL == var) + { + return 0; + } + + var->less = var->greater = NULL; + var->group = var->key = var->value = NULL; + + if ((var->group = malloc(strlen(group) + 1)) + && (var->key = malloc(strlen(key) + 1)) + && (var->value = malloc(strlen(value) + 1))) + { + strcpy(var->group, group); + strcpy(var->key, key); + strcpy(var->value, value); + return var; + } + + my_destroy(&var); + return NULL; +} + +static myvar_t *my_lookup(const char *group, const char *key) +{ + int cmp; + myvar_t *current = myVars; + + while (current + && ((cmp = strcasecmp(group, current->group)) + || (cmp = strcasecmp(key, current->key)))) + { + if (cmp < 0) + current = current->less; + else + current = current->greater; + } + + return current; +} + +static void my_insert(myvar_t *var) +{ + int cmp; + myvar_t **current = &myVars; + + while (*current + && ((cmp = strcasecmp(var->group, (*current)->group)) + || (cmp = strcasecmp(var->key, (*current)->key)))) + { + current = (cmp < 0) ? &(*current)->less : &(*current)->greater; + } + + if (*current) + { + var->less = (*current)->less; + var->greater = (*current)->greater; + my_destroy(current); + } + else + { + var->less = var->greater = NULL; + } + + *current = var; +} + +static void my_save(int *stream, myvar_t *var, char **group) +{ + if (NULL == var) + return; + + my_save(stream, var->less, group); + + if (strcasecmp(*group, var->group)) + { +// fprintf(stream, "\n[%s]\n", var->group); + *group = var->group; + } + +// fprintf(stream, "%s=%s\n", var->key, var->value); + + my_save(stream, var->greater, group); +} + +static void my_cleanup(myvar_t *var) +{ + if (NULL == var) + return; + + my_cleanup(var->less); + my_cleanup(var->greater); + my_destroy(&var); +} + +static char *my_getline(int *stream) +{ + char buf[1024]; + char *dynamic = NULL; + + do + { +/* if (NULL == (fgets(buf, sizeof(buf), stream))) + { + if (dynamic) + free(dynamic); + return 0; + } +*/ + if (NULL == dynamic) + { + dynamic = malloc(strlen(buf) + 1); + if (NULL == dynamic) + { + return 0; + } + strcpy(dynamic, buf); + } + else + { + /* a mini-version of realloc that works with our memory manager */ + char *temp = NULL; + temp = malloc(strlen(dynamic) + strlen(buf) + 1); + if (NULL == temp) + return 0; + + strcpy(temp, dynamic); + free(dynamic); + dynamic = temp; + + strcat(dynamic, buf); + } + +/* if (feof(stream)) + { + return dynamic; + }*/ + } + while (dynamic[strlen(dynamic) - 1] != '\n'); + + return dynamic; +} + +/* load_config loads from the disk the saved configuration. */ +static int load_config(char *filename) +{ + int *config_file; + + if ((config_file = rb->open(filename, O_RDONLY))) + { + char *line; + char *group = NULL, *key = NULL, *value = NULL; + + mySaveNeeded = 1; + while ((line = my_getline(config_file))) + { + char *s; + + if ('\n' == line[strlen(line) - 1]) + line[strlen(line) - 1] = '\0'; + + s = line; + + do + { + /* eat up whitespace */ + while (isspace(*s)) + s++; + + switch (*s) + { + case ';': + case '#': + case '\0': + *s = '\0'; + break; + + case '[': + if (group) + free(group); + + group = ++s; + + s = strchr(s, ']'); + if (NULL == s) + { + log_printf("load_config: missing ']' after group\n"); + s = group + strlen(group); + } + else + { + *s++ = '\0'; + } + + if ((value = malloc(strlen(group) + 1))) + { + strcpy(value, group); + } + group = value; + break; + + default: + key = s; + s = strchr(s, '='); + if (NULL == s) + { + log_printf("load_config: missing '=' after key\n"); + s = key + strlen(key); + } + else + { + *s++ = '\0'; + } + + while (strlen(key) && isspace(key[strlen(key) - 1])) + key[strlen(key) - 1] = '\0'; + + while (isspace(*s)) + s++; + + while (strlen(s) && isspace(s[strlen(s) - 1])) + s[strlen(s) - 1]='\0'; + + { + myvar_t *var = my_create(group ? group : "", key, s); + if (NULL == var) + { + log_printf("load_config: my_create failed\n"); + return -1; + } + + my_insert(var); + } + s += strlen(s); + } + } while (*s); + + free(line); + } + + if (group) + free(group); + + rb->close(config_file); + } + + return 0; +} + +/* save_config saves the current configuration to disk.*/ +static int save_config(char *filename) +{ + int *config_file; + char *group = ""; + + config_file = rb->open(filename, O_WRONLY); + if (NULL == config_file) + { + log_printf("save_config failed\n"); + return -1; + } + + my_save(config_file, myVars, &group); + rb->close(config_file); + + return 0; +} + +static int open_config(void) +{ + return load_config(config.filename); +} + +static void close_config(void) +{ + if (1 == mySaveNeeded) + { + save_config(config.filename); + } + + my_cleanup(myVars); +} + +static void write_int(const char *group, const char *key, int value) +{ + char buf[24]; + static myvar_t *var; + +// sprintf(buf, "%d", value); + buf[sizeof(buf) - 1] = '\0'; + + var = my_create(group, key, buf); + if (NULL == var) + { + log_printf("write_int failed\n"); + return; + } + + my_insert(var); + mySaveNeeded = 1; +} + +/* read_int loads an integer from the configuration into "value" +** +** If the specified "key" does not exist, the "def"ault is returned +*/ +static int read_int(const char *group, const char *key, int def) +{ + static myvar_t *var; + + var = my_lookup(group, key); + if (NULL == var) + { + write_int(group, key, def); + + return def; + } + + return 0; //strtoul(var->value, 0, 0); +} + +static void write_string(const char *group, const char *key, const char *value) +{ + static myvar_t *var; + + var = my_create(group, key, value); + if (NULL == var) + { + log_printf("write_string failed\n"); + return; + } + + my_insert(var); + mySaveNeeded = 1; +} + +/* read_string copies a string from the configuration into "value" +** +** If the specified "key" does not exist, the "def"ault is returned +*/ +static const char *read_string(const char *group, const char *key, const char *def) +{ + static myvar_t *var; + + var = my_lookup(group, key); + if (NULL == var) + { + if (def != NULL) + write_string(group, key, def); + + return def; + } + + return var->value; +} + +/* interface */ +config_t config = +{ + open_config, + close_config, + read_int, + read_string, + write_int, + write_string, + CONFIG_FILE +}; + +/* +** $Log: config.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.14 2000/11/05 06:23:10 matt +** realloc was incompatible with memguard +** +** Revision 1.13 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.12 2000/09/20 01:13:28 matt +** damn tabs +** +** Revision 1.11 2000/08/04 12:41:04 neil +** current not a bug +** +** Revision 1.10 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.9 2000/07/24 04:30:42 matt +** slight cleanup +** +** Revision 1.8 2000/07/23 15:16:08 matt +** changed strcasecmp to stricmp +** +** Revision 1.7 2000/07/19 15:58:55 neil +** config file now configurable (ha) +** +** Revision 1.6 2000/07/18 03:28:32 matt +** help me! I'm a complete mess! +** +** Revision 1.5 2000/07/12 11:03:08 neil +** Always write a config, even if no defaults are changed +** +** Revision 1.4 2000/07/11 15:09:30 matt +** suppressed all warnings +** +** Revision 1.3 2000/07/11 14:59:27 matt +** minor cosmetics.. =) +** +** Revision 1.2 2000/07/11 13:35:38 bsittler +** Changed the config API, implemented config file "nofrendo.cfg". The +** GGI drivers use the group [GGI]. Visual= and Mode= keys are understood. +** +** Revision 1.1 2000/07/11 09:21:10 bsittler +** This is a skeletal configuration system. +** +*/ Index: apps/plugins/nofrendo/mmc5_snd.c =================================================================== --- apps/plugins/nofrendo/mmc5_snd.c (revision 0) +++ apps/plugins/nofrendo/mmc5_snd.c (revision 0) @@ -0,0 +1,447 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** mmc5_snd.c +** +** Nintendo MMC5 sound emulation +** $Id: mmc5_snd.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include "mmc5_snd.h" +#include + +/* TODO: encapsulate apu/mmc5 rectangle */ + +#define APU_OVERSAMPLE +#define APU_VOLUME_DECAY(x) ((x) -= ((x) >> 7)) + +/* look up table madness */ +static int32 decay_lut[16]; +static int vbl_lut[32]; + +/* various sound constants for sound emulation */ +/* vblank length table used for rectangles, triangle, noise */ +static const uint8 vbl_length[32] = +{ + 5, 127, 10, 1, 19, 2, 40, 3, 80, 4, 30, 5, 7, 6, 13, 7, + 6, 8, 12, 9, 24, 10, 48, 11, 96, 12, 36, 13, 8, 14, 16, 15 +}; + +/* ratios of pos/neg pulse for rectangle waves +** 2/16 = 12.5%, 4/16 = 25%, 8/16 = 50%, 12/16 = 75% +** (4-bit adder in rectangles, hence the 16) +*/ +static const int duty_lut[4] = +{ + 2, 4, 8, 12 +}; + + +#define MMC5_WRA0 0x5000 +#define MMC5_WRA1 0x5001 +#define MMC5_WRA2 0x5002 +#define MMC5_WRA3 0x5003 +#define MMC5_WRB0 0x5004 +#define MMC5_WRB1 0x5005 +#define MMC5_WRB2 0x5006 +#define MMC5_WRB3 0x5007 +#define MMC5_SMASK 0x5015 + +typedef struct mmc5rectangle_s +{ + uint8 regs[4]; + + int enabled; + + float accum; + int32 freq; + int32 output_vol; + int fixed_envelope; + int holdnote; + uint8 volume; + + int32 env_phase; + int32 env_delay; + uint8 env_vol; + + int vbl_length; + uint8 adder; + int duty_flip; +} mmc5rectangle_t; + +typedef struct mmc5dac_s +{ + int32 output; + int enabled; +} mmc5dac_t; + + +static struct +{ + float incsize; + uint8 mul[2]; + mmc5rectangle_t rect[2]; + mmc5dac_t dac; +} mmc5; + + +#define MMC5_RECTANGLE_OUTPUT chan->output_vol +static int32 mmc5_rectangle(mmc5rectangle_t *chan) +{ + int32 output; + +#ifdef APU_OVERSAMPLE + int num_times; + int32 total; +#endif /* APU_OVERSAMPLE */ + + /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle + ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on + ** reg2: 8 bits of freq + ** reg3: 0-2=high freq, 7-4=vbl length counter + */ + + APU_VOLUME_DECAY(chan->output_vol); + + if (0 == chan->enabled || 0 == chan->vbl_length) + return MMC5_RECTANGLE_OUTPUT; + + /* vbl length counter */ + if (0 == chan->holdnote) + chan->vbl_length--; + + /* envelope decay at a rate of (env_delay + 1) / 240 secs */ + chan->env_phase -= 4; /* 240/60 */ + while (chan->env_phase < 0) + { + chan->env_phase += chan->env_delay; + + if (chan->holdnote) + chan->env_vol = (chan->env_vol + 1) & 0x0F; + else if (chan->env_vol < 0x0F) + chan->env_vol++; + } + + if (chan->freq < 4) + return MMC5_RECTANGLE_OUTPUT; + + chan->accum -= mmc5.incsize; /* # of cycles per sample */ + if (chan->accum >= 0) + return MMC5_RECTANGLE_OUTPUT; + +#ifdef APU_OVERSAMPLE + num_times = total = 0; + + if (chan->fixed_envelope) + output = chan->volume << 8; /* fixed volume */ + else + output = (chan->env_vol ^ 0x0F) << 8; +#endif + + while (chan->accum < 0) + { + chan->accum += chan->freq; + chan->adder = (chan->adder + 1) & 0x0F; + +#ifdef APU_OVERSAMPLE + if (chan->adder < chan->duty_flip) + total += output; + else + total -= output; + + num_times++; +#endif + } + +#ifdef APU_OVERSAMPLE + chan->output_vol = total / num_times; +#else + if (chan->fixed_envelope) + output = chan->volume << 8; /* fixed volume */ + else + output = (chan->env_vol ^ 0x0F) << 8; + + if (0 == chan->adder) + chan->output_vol = output; + else if (chan->adder == chan->duty_flip) + chan->output_vol = -output; +#endif + + return MMC5_RECTANGLE_OUTPUT; +} + +static uint8 mmc5_read(uint32 address) +{ + uint32 retval; + + retval = (uint32) (mmc5.mul[0] * mmc5.mul[1]); + + switch (address) + { + case 0x5205: + return (uint8) retval; + + case 0x5206: + return (uint8) (retval >> 8); + + default: + return 0xFF; + } +} + +/* mix vrcvi sound channels together */ +static int32 mmc5_process(void) +{ + int32 accum; + + accum = mmc5_rectangle(&mmc5.rect[0]); + accum += mmc5_rectangle(&mmc5.rect[1]); + if (mmc5.dac.enabled) + accum += mmc5.dac.output; + + return accum; +} + +/* write to registers */ +static void mmc5_write(uint32 address, uint8 value) +{ + int chan; + + switch (address) + { + /* rectangles */ + case MMC5_WRA0: + case MMC5_WRB0: + chan = (address & 4) ? 1 : 0; + mmc5.rect[chan].regs[0] = value; + + mmc5.rect[chan].volume = value & 0x0F; + mmc5.rect[chan].env_delay = decay_lut[value & 0x0F]; + mmc5.rect[chan].holdnote = (value & 0x20) ? 1 : 0; + mmc5.rect[chan].fixed_envelope = (value & 0x10) ? 1 : 0; + mmc5.rect[chan].duty_flip = duty_lut[value >> 6]; + break; + + case MMC5_WRA1: + case MMC5_WRB1: + break; + + case MMC5_WRA2: + case MMC5_WRB2: + chan = (address & 4) ? 1 : 0; + mmc5.rect[chan].regs[2] = value; + if (mmc5.rect[chan].enabled) + mmc5.rect[chan].freq = (((mmc5.rect[chan].regs[3] & 7) << 8) + value) + 1; + break; + + case MMC5_WRA3: + case MMC5_WRB3: + chan = (address & 4) ? 1 : 0; + mmc5.rect[chan].regs[3] = value; + + if (mmc5.rect[chan].enabled) + { + mmc5.rect[chan].vbl_length = vbl_lut[value >> 3]; + mmc5.rect[chan].env_vol = 0; + mmc5.rect[chan].freq = (((value & 7) << 8) + mmc5.rect[chan].regs[2]) + 1; + mmc5.rect[chan].adder = 0; + } + break; + + case MMC5_SMASK: + if (value & 0x01) + { + mmc5.rect[0].enabled = 1; + } + else + { + mmc5.rect[0].enabled = 0; + mmc5.rect[0].vbl_length = 0; + } + + if (value & 0x02) + { + mmc5.rect[1].enabled = 1; + } + else + { + mmc5.rect[1].enabled = 0; + mmc5.rect[1].vbl_length = 0; + } + + break; + + case 0x5010: + if (value & 0x01) + mmc5.dac.enabled = 1; + else + mmc5.dac.enabled = 0; + break; + + case 0x5011: + mmc5.dac.output = (value ^ 0x80) << 8; + break; + + case 0x5205: + mmc5.mul[0] = value; + break; + + case 0x5206: + mmc5.mul[1] = value; + break; + + case 0x5114: + case 0x5115: + /* ???? */ + break; + + default: + break; + } +} + +/* reset state of vrcvi sound channels */ +static void mmc5_reset(void) +{ + int i; + apu_t apu; + + + /* get the phase period from the apu */ + apu_getcontext(&apu); + mmc5.incsize = apu.cycle_rate; + + for (i = 0x5000; i < 0x5008; i++) + mmc5_write(i, 0); + + mmc5_write(0x5010, 0); + mmc5_write(0x5011, 0); +} + +static int mmc5_init(void) +{ + int i, num_samples; + apu_t apu; + + apu_getcontext(&apu); + num_samples = apu.num_samples; + + /* lut used for enveloping and frequency sweeps */ + for (i = 0; i < 16; i++) + decay_lut[i] = num_samples * (i + 1); + + /* used for note length, based on vblanks and size of audio buffer */ + for (i = 0; i < 32; i++) + vbl_lut[i] = vbl_length[i] * num_samples; + + return 0; +} + +static apu_memread mmc5_memread[] = +{ + { 0x5205, 0x5206, mmc5_read }, + { -1, -1, NULL } +}; + +static apu_memwrite mmc5_memwrite[] = +{ + { 0x5000, 0x5015, mmc5_write }, + { 0x5114, 0x5115, mmc5_write }, + { 0x5205, 0x5206, mmc5_write }, + { -1, -1, NULL } +}; + +apuext_t mmc5_ext = +{ + mmc5_init, + NULL, /* no shutdown */ + mmc5_reset, + mmc5_process, + mmc5_memread, + mmc5_memwrite +}; + +/* +** $Log: mmc5_snd.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/13 00:57:08 matt +** doesn't look as nasty now +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.16 2000/10/17 11:56:42 matt +** selectable apu base frequency +** +** Revision 1.15 2000/10/10 14:04:29 matt +** make way for bjarne +** +** Revision 1.14 2000/10/10 13:58:18 matt +** stroustrup squeezing his way in the door +** +** Revision 1.13 2000/10/08 17:50:18 matt +** appears $5114/$5115 do something +** +** Revision 1.12 2000/10/03 11:56:20 matt +** better support for optional sound ext routines +** +** Revision 1.11 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.10 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.9 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.8 2000/07/30 04:32:59 matt +** no more apu_getcyclerate hack +** +** Revision 1.7 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.6 2000/07/04 04:51:41 matt +** cleanups +** +** Revision 1.5 2000/07/03 02:18:53 matt +** much better external module exporting +** +** Revision 1.4 2000/06/28 22:03:51 matt +** fixed stupid oversight +** +** Revision 1.3 2000/06/20 20:46:58 matt +** minor cleanups +** +** Revision 1.2 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.1 2000/06/20 00:06:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mmclist.c =================================================================== --- apps/plugins/nofrendo/mmclist.c (revision 0) +++ apps/plugins/nofrendo/mmclist.c (revision 0) @@ -0,0 +1,122 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** mmclist.c +** +** list of all mapper interfaces +** $Id: mmclist.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper interfaces */ +extern mapintf_t map0_intf; +extern mapintf_t map1_intf; +extern mapintf_t map2_intf; +extern mapintf_t map3_intf; +extern mapintf_t map4_intf; +extern mapintf_t map5_intf; +extern mapintf_t map7_intf; +extern mapintf_t map8_intf; +extern mapintf_t map9_intf; +extern mapintf_t map11_intf; +extern mapintf_t map15_intf; +extern mapintf_t map16_intf; +extern mapintf_t map18_intf; +extern mapintf_t map19_intf; +extern mapintf_t map21_intf; +extern mapintf_t map22_intf; +extern mapintf_t map23_intf; +extern mapintf_t map24_intf; +extern mapintf_t map25_intf; +extern mapintf_t map32_intf; +extern mapintf_t map33_intf; +extern mapintf_t map34_intf; +extern mapintf_t map40_intf; +extern mapintf_t map64_intf; +extern mapintf_t map65_intf; +extern mapintf_t map66_intf; +extern mapintf_t map70_intf; +extern mapintf_t map75_intf; +extern mapintf_t map78_intf; +extern mapintf_t map79_intf; +extern mapintf_t map85_intf; +extern mapintf_t map94_intf; +extern mapintf_t map99_intf; +extern mapintf_t map231_intf; + +/* implemented mapper interfaces */ +mapintf_t *mappers[] = +{ + &map0_intf, + &map1_intf, + &map2_intf, + &map3_intf, + &map4_intf, + &map5_intf, + &map7_intf, + &map8_intf, + &map9_intf, + &map11_intf, + &map15_intf, + &map16_intf, + &map18_intf, + &map19_intf, + &map21_intf, + &map22_intf, + &map23_intf, + &map24_intf, + &map25_intf, + &map32_intf, + &map33_intf, + &map34_intf, + &map40_intf, + &map64_intf, + &map65_intf, + &map66_intf, + &map70_intf, + &map75_intf, + &map78_intf, + &map79_intf, + &map85_intf, + &map94_intf, + &map99_intf, + &map231_intf, + NULL +}; + +/* +** $Log: mmclist.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.2 2000/10/10 13:05:30 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.1 2000/07/31 04:27:39 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_ppu.c =================================================================== --- apps/plugins/nofrendo/nes_ppu.c (revision 0) +++ apps/plugins/nofrendo/nes_ppu.c (revision 0) @@ -0,0 +1,1402 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_ppu.c +** +** NES PPU emulation +** $Id: nes_ppu.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include "nes6502.h" +#include +#include + +#include +#include +#include +#include + + +/* PPU access */ +#define PPU_MEM(x) ppu.page[(x) >> 10][(x)] + +/* Background (color 0) and solid sprite pixel flags */ +#define BG_TRANS 0x80 +#define SP_PIXEL 0x40 +#define BG_CLEAR(V) ((V) & BG_TRANS) +#define BG_SOLID(V) (0 == BG_CLEAR(V)) +#define SP_CLEAR(V) (0 == ((V) & SP_PIXEL)) + +/* Full BG color */ +#define FULLBG (ppu.palette[0] | BG_TRANS) + +/* the NES PPU */ +static ppu_t ppu; + + +void ppu_displaysprites(int display) +{ + ppu.drawsprites = display; +} + +void ppu_setcontext(ppu_t *src_ppu) +{ + int nametab[4]; + ASSERT(src_ppu); + ppu = *src_ppu; + + /* we can't just copy contexts here, because more than likely, + ** the top 8 pages of the ppu are pointing to internal PPU memory, + ** which means we need to recalculate the page pointers. + ** TODO: we can either get rid of the page pointing in the code, + ** or add more robust checks to make sure that pages 8-15 are + ** definitely pointing to internal PPU RAM, not just something + ** that some crazy mapper paged in. + */ + nametab[0] = (src_ppu->page[8] - src_ppu->nametab + 0x2000) >> 10; + nametab[1] = (src_ppu->page[9] - src_ppu->nametab + 0x2400) >> 10; + nametab[2] = (src_ppu->page[10] - src_ppu->nametab + 0x2800) >> 10; + nametab[3] = (src_ppu->page[11] - src_ppu->nametab + 0x2C00) >> 10; + + ppu.page[8] = ppu.nametab + (nametab[0] << 10) - 0x2000; + ppu.page[9] = ppu.nametab + (nametab[1] << 10) - 0x2400; + ppu.page[10] = ppu.nametab + (nametab[2] << 10) - 0x2800; + ppu.page[11] = ppu.nametab + (nametab[3] << 10) - 0x2C00; + ppu.page[12] = ppu.page[8] - 0x1000; + ppu.page[13] = ppu.page[9] - 0x1000; + ppu.page[14] = ppu.page[10] - 0x1000; + ppu.page[15] = ppu.page[11] - 0x1000; +} + +void ppu_getcontext(ppu_t *dest_ppu) +{ + int nametab[4]; + + ASSERT(dest_ppu); + *dest_ppu = ppu; + + /* we can't just copy contexts here, because more than likely, + ** the top 8 pages of the ppu are pointing to internal PPU memory, + ** which means we need to recalculate the page pointers. + ** TODO: we can either get rid of the page pointing in the code, + ** or add more robust checks to make sure that pages 8-15 are + ** definitely pointing to internal PPU RAM, not just something + ** that some crazy mapper paged in. + */ + nametab[0] = (ppu.page[8] - ppu.nametab + 0x2000) >> 10; + nametab[1] = (ppu.page[9] - ppu.nametab + 0x2400) >> 10; + nametab[2] = (ppu.page[10] - ppu.nametab + 0x2800) >> 10; + nametab[3] = (ppu.page[11] - ppu.nametab + 0x2C00) >> 10; + + dest_ppu->page[8] = dest_ppu->nametab + (nametab[0] << 10) - 0x2000; + dest_ppu->page[9] = dest_ppu->nametab + (nametab[1] << 10) - 0x2400; + dest_ppu->page[10] = dest_ppu->nametab + (nametab[2] << 10) - 0x2800; + dest_ppu->page[11] = dest_ppu->nametab + (nametab[3] << 10) - 0x2C00; + dest_ppu->page[12] = dest_ppu->page[8] - 0x1000; + dest_ppu->page[13] = dest_ppu->page[9] - 0x1000; + dest_ppu->page[14] = dest_ppu->page[10] - 0x1000; + dest_ppu->page[15] = dest_ppu->page[11] - 0x1000; +} + +ppu_t *ppu_create(void) +{ + static int pal_generated = 0; + ppu_t *temp; + + temp = malloc(sizeof(ppu_t)); + if (NULL == temp) + return NULL; + + memset(temp, 0, sizeof(ppu_t)); + + temp->latchfunc = NULL; + temp->vromswitch = NULL; + temp->vram_present = 0; + temp->drawsprites = 1; + + /* TODO: probably a better way to do this... */ + if (0 == pal_generated) + { + pal_generate(); + pal_generated = 1; + } + + ppu_setdefaultpal(temp); + + return temp; +} + +void ppu_destroy(ppu_t **src_ppu) +{ + if (*src_ppu) + { + free(*src_ppu); + *src_ppu = NULL; + } +} + +void ppu_setpage(int size, int page_num, uint8 *location) +{ + /* deliberately fall through */ + switch (size) + { + case 8: + ppu.page[page_num++] = location; + ppu.page[page_num++] = location; + ppu.page[page_num++] = location; + ppu.page[page_num++] = location; + case 4: + ppu.page[page_num++] = location; + ppu.page[page_num++] = location; + case 2: + ppu.page[page_num++] = location; + case 1: + ppu.page[page_num++] = location; + break; + } +} + +/* make sure $3000-$3F00 mirrors $2000-$2F00 */ +void ppu_mirrorhipages(void) +{ + ppu.page[12] = ppu.page[8] - 0x1000; + ppu.page[13] = ppu.page[9] - 0x1000; + ppu.page[14] = ppu.page[10] - 0x1000; + ppu.page[15] = ppu.page[11] - 0x1000; +} + +void ppu_mirror(int nt1, int nt2, int nt3, int nt4) +{ + ppu.page[8] = ppu.nametab + (nt1 << 10) - 0x2000; + ppu.page[9] = ppu.nametab + (nt2 << 10) - 0x2400; + ppu.page[10] = ppu.nametab + (nt3 << 10) - 0x2800; + ppu.page[11] = ppu.nametab + (nt4 << 10) - 0x2C00; + ppu.page[12] = ppu.page[8] - 0x1000; + ppu.page[13] = ppu.page[9] - 0x1000; + ppu.page[14] = ppu.page[10] - 0x1000; + ppu.page[15] = ppu.page[11] - 0x1000; +} + +/* bleh, for snss */ +uint8 *ppu_getpage(int page) +{ + return ppu.page[page]; +} + +static void mem_trash(uint8 *buffer, int length) +{ + int i; + + for (i = 0; i < length; i++) + buffer[i] = (uint8) rand(); +} + +/* reset state of ppu */ +void ppu_reset(int reset_type) +{ + if (HARD_RESET == reset_type) + mem_trash(ppu.oam, 256); + + ppu.ctrl0 = 0; + ppu.ctrl1 = PPU_CTRL1F_OBJON | PPU_CTRL1F_BGON; + ppu.stat = 0; + ppu.flipflop = 0; + ppu.vaddr = ppu.vaddr_latch = 0x2000; + ppu.oam_addr = 0; + ppu.tile_xofs = 0; + + ppu.latch = 0; + ppu.vram_accessible = 1; +} + +/* we render a scanline of graphics first so we know exactly +** where the sprite 0 strike is going to occur (in terms of +** cpu cycles), using the relation that 3 pixels == 1 cpu cycle +*/ +static void ppu_setstrike(int x_loc) +{ + if (0 == ppu.strikeflag) + { + ppu.strikeflag = 1; + + /* 3 pixels per cpu cycle */ + ppu.strike_cycle = nes6502_getcycles(0) + (x_loc / 3); + } +} + +static void ppu_oamdma(uint8 value) +{ + uint32 cpu_address; + uint8 oam_loc; + + cpu_address = (uint32) (value << 8); + + /* Sprite DMA starts at the current SPRRAM address */ + oam_loc = ppu.oam_addr; + do + { + ppu.oam[oam_loc++] = nes6502_getbyte(cpu_address++); + } + while (oam_loc != ppu.oam_addr); + + /* TODO: enough with houdini */ + cpu_address -= 256; + /* Odd address in $2003 */ + if ((ppu.oam_addr >> 2) & 1) + { + for (oam_loc = 4; oam_loc < 8; oam_loc++) + ppu.oam[oam_loc] = nes6502_getbyte(cpu_address++); + cpu_address += 248; + for (oam_loc = 0; oam_loc < 4; oam_loc++) + ppu.oam[oam_loc] = nes6502_getbyte(cpu_address++); + } + /* Even address in $2003 */ + else + { + for (oam_loc = 0; oam_loc < 8; oam_loc++) + ppu.oam[oam_loc] = nes6502_getbyte(cpu_address++); + } + + /* make the CPU spin for DMA cycles */ + nes6502_burn(513); + nes6502_release(); +} + +/* TODO: this isn't the PPU! */ +void ppu_writehigh(uint32 address, uint8 value) +{ + switch (address) + { + case PPU_OAMDMA: + ppu_oamdma(value); + break; + + case PPU_JOY0: + /* VS system VROM switching - bleh!*/ + if (ppu.vromswitch) + ppu.vromswitch(value); + + /* see if we need to strobe them joypads */ + value &= 1; + + if (0 == value && ppu.strobe) + input_strobe(); + + ppu.strobe = value; + break; + + case PPU_JOY1: /* frame IRQ control */ + nes_setfiq(value); + break; + + default: + break; + } +} + +/* TODO: this isn't the PPU! */ +uint8 ppu_readhigh(uint32 address) +{ + uint8 value; + + switch (address) + { + case PPU_JOY0: + value = input_get(INP_JOYPAD0); + break; + + case PPU_JOY1: + /* TODO: better input handling */ + value = input_get(INP_ZAPPER | INP_JOYPAD1 + /*| INP_ARKANOID*/ + /*| INP_POWERPAD*/); + break; + + default: + value = 0xFF; + break; + } + + return value; +} + +/* Read from $2000-$2007 */ +uint8 ppu_read(uint32 address) +{ + uint8 value; + + /* handle mirrored reads up to $3FFF */ + switch (address & 0x2007) + { + case PPU_STAT: + value = (ppu.stat & 0xE0) | (ppu.latch & 0x1F); + + if (ppu.strikeflag) + { + if (nes6502_getcycles(0) >= ppu.strike_cycle) + value |= PPU_STATF_STRIKE; + } + + /* clear both vblank flag and vram address flipflop */ + ppu.stat &= ~PPU_STATF_VBLANK; + ppu.flipflop = 0; + break; + + case PPU_VDATA: + /* buffered VRAM reads */ + value = ppu.latch = ppu.vdata_latch; + + /* VRAM only accessible during VBL */ + if ((ppu.bg_on || ppu.obj_on) && !ppu.vram_accessible) + { + ppu.vdata_latch = 0xFF; + log_printf("VRAM read at $%04X, scanline %d\n", + ppu.vaddr, nes_getcontextptr()->scanline); + } + else + { + uint32 addr = ppu.vaddr; + if (addr >= 0x3000) + addr -= 0x1000; + ppu.vdata_latch = PPU_MEM(addr); + } + + ppu.vaddr += ppu.vaddr_inc; + ppu.vaddr &= 0x3FFF; + break; + + case PPU_OAMDATA: + case PPU_CTRL0: + case PPU_CTRL1: + case PPU_OAMADDR: + case PPU_SCROLL: + case PPU_VADDR: + default: + value = ppu.latch; + break; + } + + return value; +} + +/* Write to $2000-$2007 */ +void ppu_write(uint32 address, uint8 value) +{ + /* write goes into ppu latch... */ + ppu.latch = value; + + switch (address & 0x2007) + { + case PPU_CTRL0: + ppu.ctrl0 = value; + + ppu.obj_height = (value & PPU_CTRL0F_OBJ16) ? 16 : 8; + ppu.bg_base = (value & PPU_CTRL0F_BGADDR) ? 0x1000 : 0; + ppu.obj_base = (value & PPU_CTRL0F_OBJADDR) ? 0x1000 : 0; + ppu.vaddr_inc = (value & PPU_CTRL0F_ADDRINC) ? 32 : 1; + ppu.tile_nametab = value & PPU_CTRL0F_NAMETAB; + + /* Mask out bits 10 & 11 in the ppu latch */ + ppu.vaddr_latch &= ~0x0C00; + ppu.vaddr_latch |= ((value & 3) << 10); + break; + + case PPU_CTRL1: + ppu.ctrl1 = value; + + ppu.obj_on = (value & PPU_CTRL1F_OBJON) ? 1 : 0; + ppu.bg_on = (value & PPU_CTRL1F_BGON) ? 1 : 0; + ppu.obj_mask = (value & PPU_CTRL1F_OBJMASK) ? 0 : 1; + ppu.bg_mask = (value & PPU_CTRL1F_BGMASK) ? 0 : 1; + break; + + case PPU_OAMADDR: + ppu.oam_addr = value; + break; + + case PPU_OAMDATA: + ppu.oam[ppu.oam_addr++] = value; + break; + + case PPU_SCROLL: + if (0 == ppu.flipflop) + { + /* Mask out bits 4 - 0 in the ppu latch */ + ppu.vaddr_latch &= ~0x001F; + ppu.vaddr_latch |= (value >> 3); /* Tile number */ + ppu.tile_xofs = (value & 7); /* Tile offset (0-7 pix) */ + } + else + { + /* Mask out bits 14-12 and 9-5 in the ppu latch */ + ppu.vaddr_latch &= ~0x73E0; + ppu.vaddr_latch |= ((value & 0xF8) << 2); /* Tile number */ + ppu.vaddr_latch |= ((value & 7) << 12); /* Tile offset (0-7 pix) */ + } + + ppu.flipflop ^= 1; + + break; + + case PPU_VADDR: + if (0 == ppu.flipflop) + { + /* Mask out bits 15-8 in ppu latch */ + ppu.vaddr_latch &= ~0xFF00; + ppu.vaddr_latch |= ((value & 0x3F) << 8); + } + else + { + /* Mask out bits 7-0 in ppu latch */ + ppu.vaddr_latch &= ~0x00FF; + ppu.vaddr_latch |= value; + ppu.vaddr = ppu.vaddr_latch; + } + + ppu.flipflop ^= 1; + + break; + + case PPU_VDATA: + if (ppu.vaddr < 0x3F00) + { + /* VRAM only accessible during scanlines 241-260 */ + if ((ppu.bg_on || ppu.obj_on) && !ppu.vram_accessible) + { + log_printf("VRAM write to $%04X, scanline %d\n", + ppu.vaddr, nes_getcontextptr()->scanline); + PPU_MEM(ppu.vaddr) = 0xFF; /* corrupt */ + } + else + { + uint32 addr = ppu.vaddr; + + if (0 == ppu.vram_present && addr >= 0x3000) + ppu.vaddr -= 0x1000; + + PPU_MEM(addr) = value; + } + } + else + { + if (0 == (ppu.vaddr & 0x0F)) + { + int i; + + for (i = 0; i < 8; i ++) + ppu.palette[i << 2] = (value & 0x3F) | BG_TRANS; + } + else if (ppu.vaddr & 3) + { + ppu.palette[ppu.vaddr & 0x1F] = value & 0x3F; + } + } + + ppu.vaddr += ppu.vaddr_inc; + ppu.vaddr &= 0x3FFF; + break; + + default: + break; + } +} + +/* Builds a 256 color 8-bit palette based on a 64-color NES palette +** Note that we set it up 3 times so that we flip bits on the primary +** NES buffer for priorities +*/ +static void ppu_buildpalette(ppu_t *src_ppu, rgb_t *pal) +{ + int i; + + /* Set it up 3 times, for sprite priority/BG transparency trickery */ + for (i = 0; i < 64; i++) + { + src_ppu->curpal[i].r = src_ppu->curpal[i + 64].r + = src_ppu->curpal[i + 128].r = pal[i].r; + src_ppu->curpal[i].g = src_ppu->curpal[i + 64].g + = src_ppu->curpal[i + 128].g = pal[i].g; + src_ppu->curpal[i].b = src_ppu->curpal[i + 64].b + = src_ppu->curpal[i + 128].b = pal[i].b; + } + + for (i = 0; i < GUI_TOTALCOLORS; i++) + { + src_ppu->curpal[i + 192].r = gui_pal[i].r; + src_ppu->curpal[i + 192].g = gui_pal[i].g; + src_ppu->curpal[i + 192].b = gui_pal[i].b; + } +} + +/* build the emulator specific palette based on a 64-entry palette +** input palette can be either nes_palette or a 64-entry RGB palette +** read in from disk (i.e. for VS games) +*/ +void ppu_setpal(ppu_t *src_ppu, rgb_t *pal) +{ + ppu_buildpalette(src_ppu, pal); + vid_setpalette(src_ppu->curpal); +} + +void ppu_setdefaultpal(ppu_t *src_ppu) +{ + ppu_setpal(src_ppu, nes_palette); +} + +void ppu_setlatchfunc(ppulatchfunc_t func) +{ + ppu.latchfunc = func; +} + +void ppu_setvromswitch(ppuvromswitch_t func) +{ + ppu.vromswitch = func; +} + +/* rendering routines */ +INLINE void draw_bgtile(uint8 *surface, uint8 pat1, uint8 pat2, + const uint8 *colors) +{ + uint32 pattern = ((pat2 & 0xAA) << 8) | ((pat2 & 0x55) << 1) + | ((pat1 & 0xAA) << 7) | (pat1 & 0x55); + + *surface++ = colors[(pattern >> 14) & 3]; + *surface++ = colors[(pattern >> 6) & 3]; + *surface++ = colors[(pattern >> 12) & 3]; + *surface++ = colors[(pattern >> 4) & 3]; + *surface++ = colors[(pattern >> 10) & 3]; + *surface++ = colors[(pattern >> 2) & 3]; + *surface++ = colors[(pattern >> 8) & 3]; + *surface = colors[pattern & 3]; +} + +INLINE int draw_oamtile(uint8 *surface, uint8 attrib, uint8 pat1, + uint8 pat2, const uint8 *col_tbl, int check_strike) +{ + int strike_pixel = -1; + uint32 color = ((pat2 & 0xAA) << 8) | ((pat2 & 0x55) << 1) + | ((pat1 & 0xAA) << 7) | (pat1 & 0x55); + + /* sprite is not 100% transparent */ + if (color) + { + uint8 colors[8]; + + /* swap pixels around if our tile is flipped */ + if (0 == (attrib & OAMF_HFLIP)) + { + colors[0] = (color >> 14) & 3; + colors[1] = (color >> 6) & 3; + colors[2] = (color >> 12) & 3; + colors[3] = (color >> 4) & 3; + colors[4] = (color >> 10) & 3; + colors[5] = (color >> 2) & 3; + colors[6] = (color >> 8) & 3; + colors[7] = color & 3; + } + else + { + colors[7] = (color >> 14) & 3; + colors[6] = (color >> 6) & 3; + colors[5] = (color >> 12) & 3; + colors[4] = (color >> 4) & 3; + colors[3] = (color >> 10) & 3; + colors[2] = (color >> 2) & 3; + colors[1] = (color >> 8) & 3; + colors[0] = color & 3; + } + + /* check for solid sprite pixel overlapping solid bg pixel */ + if (check_strike) + { + if (colors[0] && BG_SOLID(surface[0])) + strike_pixel = 0; + else if (colors[1] && BG_SOLID(surface[1])) + strike_pixel = 1; + else if (colors[2] && BG_SOLID(surface[2])) + strike_pixel = 2; + else if (colors[3] && BG_SOLID(surface[3])) + strike_pixel = 3; + else if (colors[4] && BG_SOLID(surface[4])) + strike_pixel = 4; + else if (colors[5] && BG_SOLID(surface[5])) + strike_pixel = 5; + else if (colors[6] && BG_SOLID(surface[6])) + strike_pixel = 6; + else if (colors[7] && BG_SOLID(surface[7])) + strike_pixel = 7; + } + + /* draw the character */ + if (attrib & OAMF_BEHIND) + { + if (colors[0]) + surface[0] = SP_PIXEL | (BG_CLEAR(surface[0]) ? col_tbl[colors[0]] : surface[0]); + if (colors[1]) + surface[1] = SP_PIXEL | (BG_CLEAR(surface[1]) ? col_tbl[colors[1]] : surface[1]); + if (colors[2]) + surface[2] = SP_PIXEL | (BG_CLEAR(surface[2]) ? col_tbl[colors[2]] : surface[2]); + if (colors[3]) + surface[3] = SP_PIXEL | (BG_CLEAR(surface[3]) ? col_tbl[colors[3]] : surface[3]); + if (colors[4]) + surface[4] = SP_PIXEL | (BG_CLEAR(surface[4]) ? col_tbl[colors[4]] : surface[4]); + if (colors[5]) + surface[5] = SP_PIXEL | (BG_CLEAR(surface[5]) ? col_tbl[colors[5]] : surface[5]); + if (colors[6]) + surface[6] = SP_PIXEL | (BG_CLEAR(surface[6]) ? col_tbl[colors[6]] : surface[6]); + if (colors[7]) + surface[7] = SP_PIXEL | (BG_CLEAR(surface[7]) ? col_tbl[colors[7]] : surface[7]); + } + else + { + if (colors[0] && SP_CLEAR(surface[0])) + surface[0] = SP_PIXEL | col_tbl[colors[0]]; + if (colors[1] && SP_CLEAR(surface[1])) + surface[1] = SP_PIXEL | col_tbl[colors[1]]; + if (colors[2] && SP_CLEAR(surface[2])) + surface[2] = SP_PIXEL | col_tbl[colors[2]]; + if (colors[3] && SP_CLEAR(surface[3])) + surface[3] = SP_PIXEL | col_tbl[colors[3]]; + if (colors[4] && SP_CLEAR(surface[4])) + surface[4] = SP_PIXEL | col_tbl[colors[4]]; + if (colors[5] && SP_CLEAR(surface[5])) + surface[5] = SP_PIXEL | col_tbl[colors[5]]; + if (colors[6] && SP_CLEAR(surface[6])) + surface[6] = SP_PIXEL | col_tbl[colors[6]]; + if (colors[7] && SP_CLEAR(surface[7])) + surface[7] = SP_PIXEL | col_tbl[colors[7]]; + } + } + + return strike_pixel; +} + +static void ppu_renderbg(uint8 *vidbuf) +{ + uint8 *bmp_ptr, *data_ptr, *tile_ptr, *attrib_ptr; + uint32 refresh_vaddr, bg_offset, attrib_base; + int tile_count; + uint8 tile_index, x_tile, y_tile; + uint8 col_high, attrib, attrib_shift; + + /* draw a line of transparent background color if bg is disabled */ + if (0 == ppu.bg_on) + { + memset(vidbuf, FULLBG, NES_SCREEN_WIDTH); + return; + } + + bmp_ptr = vidbuf - ppu.tile_xofs; /* scroll x */ + refresh_vaddr = 0x2000 + (ppu.vaddr & 0x0FE0); /* mask out x tile */ + x_tile = ppu.vaddr & 0x1F; + y_tile = (ppu.vaddr >> 5) & 0x1F; /* to simplify calculations */ + bg_offset = ((ppu.vaddr >> 12) & 7) + ppu.bg_base; /* offset in y tile */ + + /* calculate initial values */ + tile_ptr = &PPU_MEM(refresh_vaddr + x_tile); /* pointer to tile index */ + attrib_base = (refresh_vaddr & 0x2C00) + 0x3C0 + ((y_tile & 0x1C) << 1); + attrib_ptr = &PPU_MEM(attrib_base + (x_tile >> 2)); + attrib = *attrib_ptr++; + attrib_shift = (x_tile & 2) + ((y_tile & 2) << 1); + col_high = ((attrib >> attrib_shift) & 3) << 2; + + /* ppu fetches 33 tiles */ + tile_count = 33; + while (tile_count--) + { + /* Tile number from nametable */ + tile_index = *tile_ptr++; + data_ptr = &PPU_MEM(bg_offset + (tile_index << 4)); + + /* Handle $FD/$FE tile VROM switching (PunchOut) */ + if (ppu.latchfunc) + ppu.latchfunc(ppu.bg_base, tile_index); + + draw_bgtile(bmp_ptr, data_ptr[0], data_ptr[8], ppu.palette + col_high); + bmp_ptr += 8; + + x_tile++; + + if (0 == (x_tile & 1)) /* check every 2 tiles */ + { + if (0 == (x_tile & 3)) /* check every 4 tiles */ + { + if (32 == x_tile) /* check every 32 tiles */ + { + x_tile = 0; + refresh_vaddr ^= (1 << 10); /* switch nametable */ + attrib_base ^= (1 << 10); + + /* recalculate pointers */ + tile_ptr = &PPU_MEM(refresh_vaddr); + attrib_ptr = &PPU_MEM(attrib_base); + } + + /* Get the attribute byte */ + attrib = *attrib_ptr++; + } + + attrib_shift ^= 2; + col_high = ((attrib >> attrib_shift) & 3) << 2; + } + } + + /* Blank left hand column if need be */ + if (ppu.bg_mask) + { + uint32 *buf_ptr = (uint32 *) vidbuf; + uint32 bg_clear = FULLBG | FULLBG << 8 | FULLBG << 16 | FULLBG << 24; + + ((uint32 *) buf_ptr)[0] = bg_clear; + ((uint32 *) buf_ptr)[1] = bg_clear; + } +} + +/* OAM entry */ +typedef struct obj_s +{ + uint8 y_loc; + uint8 tile; + uint8 atr; + uint8 x_loc; +} obj_t; + +/* TODO: fetch valid OAM a scanline before, like the Real Thing */ +static void ppu_renderoam(uint8 *vidbuf, int scanline) +{ + uint8 *buf_ptr; + uint32 vram_offset, savecol[2]; + int sprite_num, spritecount; + obj_t *sprite_ptr; + uint8 sprite_height; + + if (0 == ppu.obj_on) + return; + + /* Get our buffer pointer */ + buf_ptr = vidbuf; + + /* Save left hand column? */ + if (ppu.obj_mask) + { + savecol[0] = ((uint32 *) buf_ptr)[0]; + savecol[1] = ((uint32 *) buf_ptr)[1]; + } + + sprite_height = ppu.obj_height; + vram_offset = ppu.obj_base; + spritecount = 0; + + sprite_ptr = (obj_t *) ppu.oam; + + for (sprite_num = 0; sprite_num < 64; sprite_num++, sprite_ptr++) + { + uint8 *data_ptr, *bmp_ptr; + uint32 vram_adr; + int y_offset; + uint8 tile_index, attrib, col_high; + uint8 sprite_y, sprite_x; + int check_strike; + int strike_pixel; + + sprite_y = sprite_ptr->y_loc + 1; + + /* Check to see if sprite is out of range */ + if ((sprite_y > scanline) || (sprite_y <= (scanline - sprite_height)) + || (0 == sprite_y) || (sprite_y >= 240)) + continue; + + sprite_x = sprite_ptr->x_loc; + tile_index = sprite_ptr->tile; + attrib = sprite_ptr->atr; + + bmp_ptr = buf_ptr + sprite_x; + + /* Handle $FD/$FE tile VROM switching (PunchOut) */ + if (ppu.latchfunc) + ppu.latchfunc(vram_offset, tile_index); + + /* Get upper two bits of color */ + col_high = ((attrib & 3) << 2); + + /* 8x16 even sprites use $0000, odd use $1000 */ + if (16 == ppu.obj_height) + vram_adr = ((tile_index & 1) << 12) | ((tile_index & 0xFE) << 4); + else + vram_adr = vram_offset + (tile_index << 4); + + /* Get the address of the tile */ + data_ptr = &PPU_MEM(vram_adr); + + /* Calculate offset (line within the sprite) */ + y_offset = scanline - sprite_y; + if (y_offset > 7) + y_offset += 8; + + /* Account for vertical flippage */ + if (attrib & OAMF_VFLIP) + { + if (16 == ppu.obj_height) + y_offset -= 23; + else + y_offset -= 7; + + data_ptr -= y_offset; + } + else + { + data_ptr += y_offset; + } + + /* if we're on sprite 0 and sprite 0 strike flag isn't set, + ** check for a strike + */ + check_strike = (0 == sprite_num) && (0 == ppu.strikeflag); + strike_pixel = draw_oamtile(bmp_ptr, attrib, data_ptr[0], data_ptr[8], ppu.palette + 16 + col_high, check_strike); + if (strike_pixel >= 0) + ppu_setstrike(strike_pixel); + + /* maximum of 8 sprites per scanline */ + if (++spritecount == PPU_MAXSPRITE) + { + ppu.stat |= PPU_STATF_MAXSPRITE; + break; + } + } + + /* Restore lefthand column */ + if (ppu.obj_mask) + { + ((uint32 *) buf_ptr)[0] = savecol[0]; + ((uint32 *) buf_ptr)[1] = savecol[1]; + } +} + +/* Fake rendering a line */ +/* This is needed for sprite 0 hits when we're skipping drawing a frame */ +static void ppu_fakeoam(int scanline) +{ + uint8 *data_ptr; + obj_t *sprite_ptr; + uint32 vram_adr, color; + int y_offset; + uint8 pat1, pat2; + uint8 tile_index, attrib; + uint8 sprite_height, sprite_y, sprite_x; + + /* we don't need to be here if strike flag is set */ + + if (0 == ppu.obj_on || ppu.strikeflag) + return; + + sprite_height = ppu.obj_height; + sprite_ptr = (obj_t *) ppu.oam; + sprite_y = sprite_ptr->y_loc + 1; + + /* Check to see if sprite is out of range */ + if ((sprite_y > scanline) || (sprite_y <= (scanline - sprite_height)) + || (0 == sprite_y) || (sprite_y > 240)) + return; + + sprite_x = sprite_ptr->x_loc; + tile_index = sprite_ptr->tile; + attrib = sprite_ptr->atr; + + /* 8x16 even sprites use $0000, odd use $1000 */ + if (16 == ppu.obj_height) + vram_adr = ((tile_index & 1) << 12) | ((tile_index & 0xFE) << 4); + else + vram_adr = ppu.obj_base + (tile_index << 4); + + data_ptr = &PPU_MEM(vram_adr); + + /* Calculate offset (line within the sprite) */ + y_offset = scanline - sprite_y; + if (y_offset > 7) + y_offset += 8; + + /* Account for vertical flippage */ + if (attrib & OAMF_VFLIP) + { + if (16 == ppu.obj_height) + y_offset -= 23; + else + y_offset -= 7; + data_ptr -= y_offset; + } + else + { + data_ptr += y_offset; + } + + /* check for a solid sprite 0 pixel */ + pat1 = data_ptr[0]; + pat2 = data_ptr[8]; + color = ((pat2 & 0xAA) << 8) | ((pat2 & 0x55) << 1) + | ((pat1 & 0xAA) << 7) | (pat1 & 0x55); + + if (color) + { + uint8 colors[8]; + + /* buckle up, it's going to get ugly... */ + if (0 == (attrib & OAMF_HFLIP)) + { + colors[0] = (color >> 14) & 3; + colors[1] = (color >> 6) & 3; + colors[2] = (color >> 12) & 3; + colors[3] = (color >> 4) & 3; + colors[4] = (color >> 10) & 3; + colors[5] = (color >> 2) & 3; + colors[6] = (color >> 8) & 3; + colors[7] = color & 3; + } + else + { + colors[7] = (color >> 14) & 3; + colors[6] = (color >> 6) & 3; + colors[5] = (color >> 12) & 3; + colors[4] = (color >> 4) & 3; + colors[3] = (color >> 10) & 3; + colors[2] = (color >> 2) & 3; + colors[1] = (color >> 8) & 3; + colors[0] = color & 3; + } + + if (colors[0]) + ppu_setstrike(sprite_x + 0); + else if (colors[1]) + ppu_setstrike(sprite_x + 1); + else if (colors[2]) + ppu_setstrike(sprite_x + 2); + else if (colors[3]) + ppu_setstrike(sprite_x + 3); + else if (colors[4]) + ppu_setstrike(sprite_x + 4); + else if (colors[5]) + ppu_setstrike(sprite_x + 5); + else if (colors[6]) + ppu_setstrike(sprite_x + 6); + else if (colors[7]) + ppu_setstrike(sprite_x + 7); + } +} + +int ppu_enabled(void) +{ + return (ppu.bg_on || ppu.obj_on); +} + +static void ppu_renderscanline(bitmap_t *bmp, int scanline, int draw_flag) +{ + uint8 *buf = bmp->line[scanline]; + + /* start scanline - transfer ppu latch into vaddr */ + if (ppu.bg_on || ppu.obj_on) + { + if (0 == scanline) + { + ppu.vaddr = ppu.vaddr_latch; + } + else + { + ppu.vaddr &= ~0x041F; + ppu.vaddr |= (ppu.vaddr_latch & 0x041F); + } + } + + if (draw_flag) + ppu_renderbg(buf); + + /* TODO: fetch obj data 1 scanline before */ + if (1 == ppu.drawsprites && 1 == draw_flag) + ppu_renderoam(buf, scanline); + else + ppu_fakeoam(scanline); +} + + +void ppu_endscanline(int scanline) +{ + /* modify vram address at end of scanline */ + if (scanline < 240 && (ppu.bg_on || ppu.obj_on)) + { + int ytile; + + /* check for max 3 bit y tile offset */ + if (7 == (ppu.vaddr >> 12)) + { + ppu.vaddr &= ~0x7000; /* clear y tile offset */ + ytile = (ppu.vaddr >> 5) & 0x1F; + + if (29 == ytile) + { + ppu.vaddr &= ~0x03E0; /* clear y tile */ + ppu.vaddr ^= 0x0800; /* toggle nametable */ + } + else if (31 == ytile) + { + ppu.vaddr &= ~0x03E0; /* clear y tile */ + } + else + { + ppu.vaddr += 0x20; /* increment y tile */ + } + } + else + { + ppu.vaddr += 0x1000; /* increment tile y offset */ + } + } +} + +void ppu_checknmi(void) +{ + if (ppu.ctrl0 & PPU_CTRL0F_NMI) + nes_nmi(); +} + +void ppu_scanline(bitmap_t *bmp, int scanline, int draw_flag) +{ + if (scanline < 240) + { + /* Lower the Max Sprite per scanline flag */ + ppu.stat &= ~PPU_STATF_MAXSPRITE; + ppu_renderscanline(bmp, scanline, draw_flag); + } + else if (241 == scanline) + { + ppu.stat |= PPU_STATF_VBLANK; + ppu.vram_accessible = 1; + } + else if (261 == scanline) + { + ppu.stat &= ~PPU_STATF_VBLANK; + ppu.strikeflag = 0; + ppu.strike_cycle = (uint32) -1; + + ppu.vram_accessible = 0; + } +} + +/* +int ppu_checkzapperhit(bitmap_t *bmp, int x, int y) +{ + uint8 pixel = bmp->line[y][x] & 0x3F; + + if (0x20 == pixel || 0x30 == pixel) + return 1; + + return 0; +} +*/ + +/*************************************************/ +/* TODO: all this stuff should go somewhere else */ +/*************************************************/ +INLINE void draw_box(bitmap_t *bmp, int x, int y, int height) +{ + int i; + uint8 *vid; + + vid = bmp->line[y] + x; + + for (i = 0; i < 10; i++) + *vid++ = GUI_GRAY; + vid += (bmp->pitch - 10); + for (i = 0; i < height; i++) + { + vid[0] = vid[9] = GUI_GRAY; + vid += bmp->pitch; + } + for (i = 0; i < 10; i++) + *vid++ = GUI_GRAY; +} + +INLINE void draw_deadsprite(bitmap_t *bmp, int x, int y, int height) +{ + int i, j, index; + uint8 *vid; + uint8 colbuf[8] = { GUI_BLACK, GUI_BLACK, GUI_BLACK, GUI_BLACK, + GUI_BLACK, GUI_BLACK, GUI_BLACK, GUI_DKGRAY }; + + vid = bmp->line[y] + x; + + for (i = 0; i < height; i++) + { + index = i; + + if (height == 16) + index >>= 1; + + for (j = 0; j < 8; j++) + { + *(vid + j) = colbuf[index++]; + index &= 7; + } + + vid += bmp->pitch; + } +} + + +/* Stuff for the OAM viewer */ +static void draw_sprite(bitmap_t *bmp, int x, int y, uint8 tile_num, uint8 attrib) +{ + int line, height; + int col_high, vram_adr; + uint8 *vid, *data_ptr; + + vid = bmp->line[y] + x; + + /* Get upper two bits of color */ + col_high = ((attrib & 3) << 2); + + /* 8x16 even sprites use $0000, odd use $1000 */ + height = ppu.obj_height; + if (16 == height) + vram_adr = ((tile_num & 1) << 12) | ((tile_num & 0xFE) << 4); + /* else just use the offset from $2000 */ + else + vram_adr = ppu.obj_base + (tile_num << 4); + + data_ptr = &PPU_MEM(vram_adr); + + for (line = 0; line < height; line++) + { + if (line == 8) + data_ptr += 8; + + draw_bgtile(vid, data_ptr[0], data_ptr[8], ppu.palette + 16 + col_high); + //draw_oamtile(vid, attrib, data_ptr[0], data_ptr[8], ppu.palette + 16 + col_high); + + data_ptr++; + vid += bmp->pitch; + } +} + +void ppu_dumpoam(bitmap_t *bmp, int x_loc, int y_loc) +{ + int sprite, x_pos, y_pos, height; + obj_t *spr_ptr; + + spr_ptr = (obj_t *) ppu.oam; + height = ppu.obj_height; + + for (sprite = 0; sprite < 64; sprite++) + { + x_pos = ((sprite & 0x0F) << 3) + (sprite & 0x0F) + x_loc; + if (height == 16) + y_pos = (sprite & 0xF0) + (sprite >> 4) + y_loc; + else + y_pos = ((sprite & 0xF0) >> 1) + (sprite >> 4) + y_loc; + + draw_box(bmp, x_pos, y_pos, height); + + if (spr_ptr->y_loc && spr_ptr->y_loc < 240) + draw_sprite(bmp, x_pos + 1, y_pos + 1, spr_ptr->tile, spr_ptr->atr); + else + draw_deadsprite(bmp, x_pos + 1, y_pos + 1, height); + + spr_ptr++; + } +} + +/* More of a debugging thing than anything else */ +void ppu_dumppattern(bitmap_t *bmp, int table_num, int x_loc, int y_loc, int col) +{ + int x_tile, y_tile; + uint8 *bmp_ptr, *data_ptr, *ptr; + int tile_num, line; + uint8 col_high; + + tile_num = 0; + col_high = col << 2; + + for (y_tile = 0; y_tile < 16; y_tile++) + { + /* Get our pointer to the bitmap */ + bmp_ptr = bmp->line[y_loc] + x_loc; + + for (x_tile = 0; x_tile < 16; x_tile++) + { + data_ptr = &PPU_MEM((table_num << 12) + (tile_num << 4)); + ptr = bmp_ptr; + + for (line = 0; line < 8; line ++) + { + draw_bgtile(ptr, data_ptr[0], data_ptr[8], ppu.palette + col_high); + data_ptr++; + ptr += bmp->pitch; + } + + bmp_ptr += 8; + tile_num++; + } + y_loc += 8; + } +} + +/* +** $Log: nes_ppu.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.14 2000/11/29 12:58:23 matt +** timing/fiq fixes +** +** Revision 1.13 2000/11/27 19:36:15 matt +** more timing fixes +** +** Revision 1.12 2000/11/26 15:51:13 matt +** frame IRQ emulation +** +** Revision 1.11 2000/11/25 20:30:39 matt +** scanline emulation simplifications/timing fixes +** +** Revision 1.10 2000/11/24 14:56:02 matt +** fixed a long-standing sprite 0 strike bug +** +** Revision 1.9 2000/11/20 13:23:17 matt +** PPU fixes +** +** Revision 1.8 2000/11/19 13:47:30 matt +** problem with frame irqs fixed +** +** Revision 1.7 2000/11/19 13:40:19 matt +** more accurate ppu behavior +** +** Revision 1.6 2000/11/14 12:09:37 matt +** only generate the palette once, please +** +** Revision 1.5 2000/11/11 14:51:43 matt +** context get/set fixed +** +** Revision 1.4 2000/11/09 12:35:50 matt +** fixed timing problem with VRAM reads/writes +** +** Revision 1.3 2000/11/05 16:35:41 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.2 2000/10/27 12:55:03 matt +** palette generating functions now take *this pointers +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.33 2000/10/23 15:53:08 matt +** better system handling +** +** Revision 1.32 2000/10/22 15:02:32 matt +** simplified mirroring +** +** Revision 1.31 2000/10/21 21:36:04 matt +** ppu cleanups / fixes +** +** Revision 1.30 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.29 2000/10/10 13:58:15 matt +** stroustrup squeezing his way in the door +** +** Revision 1.28 2000/10/08 17:54:32 matt +** reject VRAM access out of VINT period +** +** Revision 1.27 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.26 2000/09/08 11:57:29 matt +** no more nes_fiq +** +** Revision 1.25 2000/09/07 21:57:31 matt +** api change +** +** Revision 1.24 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.23 2000/07/30 06:13:12 matt +** default to no FIQs on startup +** +** Revision 1.22 2000/07/30 04:32:32 matt +** emulation of the NES frame IRQ +** +** Revision 1.21 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.20 2000/07/23 15:12:43 matt +** removed unused variables, changed INLINE +** +** Revision 1.19 2000/07/21 04:50:39 matt +** moved palette calls out of nofrendo.c and into ppu_create +** +** Revision 1.18 2000/07/17 05:12:55 matt +** nes_ppu.c is no longer a scary place to be-- cleaner & faster +** +** Revision 1.17 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.16 2000/07/11 04:42:39 matt +** updated for new screen dimension defines +** +** Revision 1.15 2000/07/10 19:10:16 matt +** should bomb out now if a game tries to write to VROM +** +** Revision 1.14 2000/07/10 05:28:30 matt +** moved joypad/oam dma from apu to ppu +** +** Revision 1.13 2000/07/10 03:03:16 matt +** added ppu_getcontext() routine +** +** Revision 1.12 2000/07/09 03:46:05 matt +** using pitch instead of width... +** +** Revision 1.11 2000/07/06 16:42:40 matt +** better palette setting interface +** +** Revision 1.10 2000/07/05 22:49:25 matt +** changed mmc2 (punchout) tile-access switching +** +** Revision 1.9 2000/07/04 23:13:26 matt +** added an irq line drawing debug feature hack +** +** Revision 1.8 2000/06/26 04:58:08 matt +** accuracy changes +** +** Revision 1.7 2000/06/22 02:13:49 matt +** more accurate emulation of $2002 +** +** Revision 1.6 2000/06/20 20:42:47 matt +** accuracy changes +** +** Revision 1.5 2000/06/20 00:05:12 matt +** tested and verified STAT quirk, added code +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mmc5_snd.h =================================================================== --- apps/plugins/nofrendo/mmc5_snd.h (revision 0) +++ apps/plugins/nofrendo/mmc5_snd.h (revision 0) @@ -0,0 +1,70 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** mmc5_snd.h +** +** Nintendo MMC5 sound emulation header +** $Id: mmc5_snd.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _MMC5_SND_H_ +#define _MMC5_SND_H_ + +#include + +extern apuext_t mmc5_ext; + +#endif /* !_MMC5_SND_H_ */ + +/* +** $Log: mmc5_snd.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/13 00:57:08 matt +** doesn't look as nasty now +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.6 2000/10/10 13:58:18 matt +** stroustrup squeezing his way in the door +** +** Revision 1.5 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.4 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.3 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.2 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.1 2000/06/20 00:06:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nesinput.h =================================================================== --- apps/plugins/nofrendo/nesinput.h (revision 0) +++ apps/plugins/nofrendo/nesinput.h (revision 0) @@ -0,0 +1,104 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nesinput.h +** +** Platform independent input definitions +** $Id: nesinput.h,v 1.1.1.1 2001/04/27 07:03:54 neil Exp $ +*/ + +#ifndef _NESINPUT_H_ +#define _NESINPUT_H_ + +/* NES control pad bitmasks */ +#define INP_PAD_A 0x01 +#define INP_PAD_B 0x02 +#define INP_PAD_SELECT 0x04 +#define INP_PAD_START 0x08 +#define INP_PAD_UP 0x10 +#define INP_PAD_DOWN 0x20 +#define INP_PAD_LEFT 0x40 +#define INP_PAD_RIGHT 0x80 + +#define INP_ZAPPER_HIT 0x00 +#define INP_ZAPPER_MISS 0x08 +#define INP_ZAPPER_TRIG 0x10 + +#define INP_JOYPAD0 0x0001 +#define INP_JOYPAD1 0x0002 +#define INP_ZAPPER 0x0004 +#define INP_POWERPAD 0x0008 +#define INP_ARKANOID 0x0010 +#define INP_VSDIPSW0 0x0020 +#define INP_VSDIPSW1 0x0040 + +/* upper byte is what's returned in D4, lower is D3 */ +#define INP_PPAD_1 0x0002 +#define INP_PPAD_2 0x0001 +#define INP_PPAD_3 0x0200 +#define INP_PPAD_4 0x0100 +#define INP_PPAD_5 0x0004 +#define INP_PPAD_6 0x0010 +#define INP_PPAD_7 0x0080 +#define INP_PPAD_8 0x0800 +#define INP_PPAD_9 0x0008 +#define INP_PPAD_10 0x0020 +#define INP_PPAD_11 0x0040 +#define INP_PPAD_12 0x0400 + + +enum +{ + INP_STATE_BREAK, + INP_STATE_MAKE +}; + +typedef struct nesinput_s +{ + int type; + int data; +} nesinput_t; + +#define MAX_CONTROLLERS 32 + +extern uint8 input_get(int type); +extern void input_register(nesinput_t *input); +extern void input_event(nesinput_t *input, int state, int value); +extern void input_strobe(void); + +#endif /* _NESINPUT_H_ */ + +/* +** $Log: nesinput.h,v $ +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.6 2000/09/10 23:25:02 matt +** minor changes +** +** Revision 1.5 2000/07/17 01:52:29 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nofrendo.c =================================================================== --- apps/plugins/nofrendo/nofrendo.c (revision 0) +++ apps/plugins/nofrendo/nofrendo.c (revision 0) @@ -0,0 +1,397 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nofrendo.c +** +** Entry point of program +** Note: all architectures should call these functions +** $Id: nofrendo.c,v 1.3 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* emulated system includes */ +#include + +/* our global machine structure */ +static struct +{ + char *filename, *nextfilename; + system_t type, nexttype; + + union + { + nes_t *nes; + } machine; + + int refresh_rate; + + int quit; +} console; + +/* our happy little timer ISR */ +volatile int nofrendo_ticks = 0; +static void timer_isr(void) +{ + nofrendo_ticks++; +} +static void timer_isr_end(void) {} /* code marker for djgpp */ + +static void shutdown_everything(void) +{ + if (console.filename) + { + free(console.filename); + console.filename = NULL; + } + if (console.nextfilename) + { + free(console.nextfilename); + console.nextfilename = NULL; + } + + config.close(); + osd_shutdown(); + gui_shutdown(); + vid_shutdown(); + log_shutdown(); +} + +/* End the current context */ +void main_eject(void) +{ + switch (console.type) + { + case system_nes: + nes_poweroff(); + nes_destroy(&(console.machine.nes)); + break; + + default: + break; + } + + if (NULL != console.filename) + { + free(console.filename); + console.filename = NULL; + } + console.type = system_unknown; +} + +/* Act on the user's quit requests */ +void main_quit(void) +{ + console.quit = 1; + + main_eject(); + + /* if there's a pending filename / system, clear */ + if (NULL != console.nextfilename) + { + free(console.nextfilename); + console.nextfilename = NULL; + } + console.nexttype = system_unknown; +} + +/* brute force system autodetection */ +static system_t detect_systemtype(const char *filename) +{ + if (NULL == filename) + return system_unknown; + + if (0 == nes_isourfile(filename)) + return system_nes; + + /* can't figure out what this thing is */ + return system_unknown; +} + +static int install_timer(int hertz) +{ + return osd_installtimer(hertz, (void *) timer_isr, + (int) timer_isr_end - (int) timer_isr, + (void *) &nofrendo_ticks, + sizeof(nofrendo_ticks)); +} + +/* This assumes there is no current context */ +static int internal_insert(const char *filename, system_t type) +{ + /* autodetect system type? */ + if (system_autodetect == type) + type = detect_systemtype(filename); + + console.filename = strdup(filename); + console.type = type; + + /* set up the event system for this system type */ + event_set_system(type); + + switch (console.type) + { + case system_nes: + gui_setrefresh(NES_REFRESH_RATE); + + console.machine.nes = nes_create(); + if (NULL == console.machine.nes) + { + log_printf("Failed to create NES instance.\n"); + return -1; + } + + if (nes_insertcart(console.filename, console.machine.nes)) + return -1; + + vid_setmode(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); + + if (install_timer(NES_REFRESH_RATE)) + return -1; + + nes_emulate(); + break; + + case system_unknown: + default: + log_printf("system type unknown, playing nofrendo NES intro.\n"); + if (NULL != console.filename) + free(console.filename); + + /* oooh, recursion */ + return internal_insert(filename, system_nes); + } + + return 0; +} + +/* This tells main_loop to load this next image */ +void main_insert(const char *filename, system_t type) +{ + console.nextfilename = strdup(filename); + console.nexttype = type; + + main_eject(); +} + +int start(char filename) +{ + /* initialize our system structure */ + console.filename = NULL; + console.nextfilename = NULL; + console.type = system_unknown; + console.nexttype = system_unknown; + console.refresh_rate = 0; + console.quit = 0; + + if (log_init()) + return -1; + + event_init(); + + return osd_main(filename); +} + +/* This is the final leg of main() */ +int main_loop(const char *filename, system_t type) +{ + vidinfo_t video; + +// if (config.open()) +// return -1; + + if (osd_init()) + return -1; + + if (gui_init()) + return -1; + + osd_getvideoinfo(&video); + if (vid_init(video.default_width, video.default_height, video.driver)) + return -1; + + console.nextfilename = strdup(filename); + console.nexttype = type; + + while (0 == console.quit) + { + if (internal_insert(console.nextfilename, console.nexttype)) + return 1; + } + + return 0; +} + +/* +** $Log: nofrendo.c,v $ +** Revision 1.3 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.2 2001/04/27 11:10:08 neil +** compile +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.48 2000/11/27 12:47:08 matt +** free them strings +** +** Revision 1.47 2000/11/25 20:26:05 matt +** removed fds "system" +** +** Revision 1.46 2000/11/25 01:51:53 matt +** bool stinks sometimes +** +** Revision 1.45 2000/11/20 13:22:12 matt +** standardized timer ISR, added nofrendo_ticks +** +** Revision 1.44 2000/11/05 22:53:13 matt +** only one video driver per system, please +** +** Revision 1.43 2000/11/01 14:15:35 matt +** multi-system event system, or whatever +** +** Revision 1.42 2000/10/28 15:16:24 matt +** removed nsf_init +** +** Revision 1.41 2000/10/27 12:58:44 matt +** gui_init can now fail +** +** Revision 1.40 2000/10/26 22:48:57 matt +** prelim NSF support +** +** Revision 1.39 2000/10/25 13:42:02 matt +** strdup - giddyap! +** +** Revision 1.38 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.37 2000/10/23 17:50:47 matt +** adding fds support +** +** Revision 1.36 2000/10/23 15:52:04 matt +** better system handling +** +** Revision 1.35 2000/10/21 19:25:59 matt +** many more cleanups +** +** Revision 1.34 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.33 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.32 2000/09/15 04:58:06 matt +** simplifying and optimizing APU core +** +** Revision 1.31 2000/09/10 23:19:14 matt +** i'm a sloppy coder +** +** Revision 1.30 2000/09/07 01:30:57 matt +** nes6502_init deprecated +** +** Revision 1.29 2000/08/16 03:17:49 matt +** bpb +** +** Revision 1.28 2000/08/16 02:58:19 matt +** changed video interface a wee bit +** +** Revision 1.27 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.26 2000/07/30 04:31:26 matt +** automagic loading of the nofrendo intro +** +** Revision 1.25 2000/07/27 01:16:36 matt +** sorted out the video problems +** +** Revision 1.24 2000/07/26 21:54:53 neil +** eject has to clear the nextfilename and nextsystem +** +** Revision 1.23 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.22 2000/07/25 02:21:36 matt +** safer xxx_destroy calls +** +** Revision 1.21 2000/07/23 16:46:47 matt +** fixed crash in win32 by reodering shutdown calls +** +** Revision 1.20 2000/07/23 15:18:23 matt +** removed unistd.h from includes +** +** Revision 1.19 2000/07/23 00:48:15 neil +** Win32 SDL +** +** Revision 1.18 2000/07/21 13:42:06 neil +** get_options removed, as it should be handled by osd_main +** +** Revision 1.17 2000/07/21 04:53:48 matt +** moved palette calls out of nofrendo.c and into ppu_create +** +** Revision 1.16 2000/07/21 02:40:43 neil +** more main fixes +** +** Revision 1.15 2000/07/21 02:09:07 neil +** new main structure? +** +** Revision 1.14 2000/07/20 17:05:12 neil +** Moved osd_init before setup_video +** +** Revision 1.13 2000/07/11 15:01:05 matt +** moved config.close() into registered atexit() routine +** +** Revision 1.12 2000/07/11 13:35:38 bsittler +** Changed the config API, implemented config file "nofrendo.cfg". The +** GGI drivers use the group [GGI]. Visual= and Mode= keys are understood. +** +** Revision 1.11 2000/07/11 04:32:21 matt +** less magic number nastiness for screen dimensions +** +** Revision 1.10 2000/07/10 03:04:15 matt +** removed scanlines, backbuffer from custom blit +** +** Revision 1.9 2000/07/07 04:39:54 matt +** removed garbage dpp shite +** +** Revision 1.8 2000/07/06 16:48:25 matt +** new video driver +** +** Revision 1.7 2000/07/05 17:26:16 neil +** Moved the externs in nofrendo.c to osd.h +** +** Revision 1.6 2000/06/26 04:55:44 matt +** cleaned up main() +** +** Revision 1.5 2000/06/20 20:41:21 matt +** moved include to top (duh) +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/noftypes.h =================================================================== --- apps/plugins/nofrendo/noftypes.h (revision 0) +++ apps/plugins/nofrendo/noftypes.h (revision 0) @@ -0,0 +1,137 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** types.h +** +** Data type definitions +** $Id: noftypes.h,v 1.1 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#include "plugin.h" +#include "codecs/lib/tlsf/src/tlsf.h" + +#define malloc(a) tlsf_malloc(a) +#define free(a) tlsf_free(a) +#define lseek(a,b,c) rb->lseek((a),(b),(c)) +#define filesize(a) rb->filesize((a)) +#define read(a,b,c) rb->read((a),(b),(c)) +#define write(a,b,c) rb->write((a),(b),(c)) +#define strtok(a,b) my_strtok((a),(b)) +#define strcat(a,b) rb->strcat((a),(b)) +#define memset(a,b,c) rb->memset((a),(b),(c)) +#define memmove(a,b,c) rb->memmove((a),(b),(c)) +#define memcmp(a,b,c) rb->memcmp((a),(b),(c)) +#define memchr(a,b,c) rb->memchr((a),(b),(c)) +#define strcpy(a,b) rb->strcpy((a),(b)) +#define strlen(a) rb->strlen((a)) +#define strcmp(a,b) rb->strcmp((a),(b)) +#define strncmp(a,b,c) rb->strncmp((a),(b),(c)) +#define strchr(a,b) rb->strchr((a),(b)) +#define strrchr(a,b) rb->strrchr((a),(b)) +#define strcasecmp(a,b) rb->strcasecmp((a),(b)) +#define strncasecmp(a,b,c) rb->strncasecmp((a),(b),(c)) +#define srand(a) rb->srand((a)) +#define rand() rb->rand() +#define atoi(a) rb->atoi((a)) +#define strcat(a,b) rb->strcat((a),(b)) +#define snprintf rb->snprintf + +/* Define this if running on little-endian (x86) systems */ +#define HOST_LITTLE_ENDIAN + +#ifdef __GNUC__ +#define INLINE static inline +#define ZERO_LENGTH 0 +#elif defined(WIN32) +#define INLINE static __inline +#define ZERO_LENGTH 0 +#else /* crapintosh? */ +#define INLINE static +#define ZERO_LENGTH 1 +#endif + +/* quell stupid compiler warnings */ +#define UNUSED(x) ((x) = (x)) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +#include +#include + +#ifdef NOFRENDO_DEBUG + +#define ASSERT(expr) log_assert((int) (expr), __LINE__, __FILE__, NULL) +#define ASSERT_MSG(msg) log_assert(false, __LINE__, __FILE__, (msg)) + +#else /* !NOFRENDO_DEBUG */ + +#define ASSERT(expr) +#define ASSERT_MSG(msg) + +#endif /* !NOFRENDO_DEBUG */ + +#endif /* _TYPES_H_ */ + +/* +** $Log: noftypes.h,v $ +** Revision 1.1 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.15 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.14 2000/10/17 03:22:16 matt +** safe UNUSED +** +** Revision 1.13 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.12 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.11 2000/08/11 01:44:05 matt +** cosmeses +** +** Revision 1.10 2000/07/31 04:28:47 matt +** one million cleanups +** +** Revision 1.9 2000/07/24 04:30:17 matt +** ASSERTs should have been calling log_shutdown +** +** Revision 1.8 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/07/04 04:46:44 matt +** moved INLINE define from osd.h +** +** Revision 1.6 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mmclist.h =================================================================== --- apps/plugins/nofrendo/mmclist.h (revision 0) +++ apps/plugins/nofrendo/mmclist.h (revision 0) @@ -0,0 +1,49 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** mmclist.h +** +** list of all mapper interfaces +** $Id: mmclist.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _MMCLIST_H_ +#define _MMCLIST_H_ + +#include + +extern mapintf_t *mappers[]; + +#endif /* !_MMCLIST_H_ */ + +/* +** $Log: mmclist.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.1 2000/07/31 04:27:40 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_ppu.h =================================================================== --- apps/plugins/nofrendo/nes_ppu.h (revision 0) +++ apps/plugins/nofrendo/nes_ppu.h (revision 0) @@ -0,0 +1,241 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_ppu.h +** +** NES Picture Processing Unit (PPU) emulation header file +** $Id: nes_ppu.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _NES_PPU_H_ +#define _NES_PPU_H_ + +#include + +/* PPU register defines */ +#define PPU_CTRL0 0x2000 +#define PPU_CTRL1 0x2001 +#define PPU_STAT 0x2002 +#define PPU_OAMADDR 0x2003 +#define PPU_OAMDATA 0x2004 +#define PPU_SCROLL 0x2005 +#define PPU_VADDR 0x2006 +#define PPU_VDATA 0x2007 + +#define PPU_OAMDMA 0x4014 +#define PPU_JOY0 0x4016 +#define PPU_JOY1 0x4017 + +/* $2000 */ +#define PPU_CTRL0F_NMI 0x80 +#define PPU_CTRL0F_OBJ16 0x20 +#define PPU_CTRL0F_BGADDR 0x10 +#define PPU_CTRL0F_OBJADDR 0x08 +#define PPU_CTRL0F_ADDRINC 0x04 +#define PPU_CTRL0F_NAMETAB 0x03 + +/* $2001 */ +#define PPU_CTRL1F_OBJON 0x10 +#define PPU_CTRL1F_BGON 0x08 +#define PPU_CTRL1F_OBJMASK 0x04 +#define PPU_CTRL1F_BGMASK 0x02 + +/* $2002 */ +#define PPU_STATF_VBLANK 0x80 +#define PPU_STATF_STRIKE 0x40 +#define PPU_STATF_MAXSPRITE 0x20 + +/* Sprite attribute byte bitmasks */ +#define OAMF_VFLIP 0x80 +#define OAMF_HFLIP 0x40 +#define OAMF_BEHIND 0x20 + +/* Maximum number of sprites per horizontal scanline */ +#define PPU_MAXSPRITE 8 + +/* some mappers do *dumb* things */ +typedef void (*ppulatchfunc_t)(uint32 address, uint8 value); +typedef void (*ppuvromswitch_t)(uint8 value); + +typedef struct ppu_s +{ + /* big nasty memory chunks */ + uint8 nametab[0x1000]; + uint8 oam[256]; + uint8 palette[32]; + uint8 *page[16]; + + /* hardware registers */ + uint8 ctrl0, ctrl1, stat, oam_addr; + uint32 vaddr, vaddr_latch; + int tile_xofs, flipflop; + int vaddr_inc; + uint32 tile_nametab; + + uint8 obj_height; + uint32 obj_base, bg_base; + + int bg_on, obj_on; + int obj_mask, bg_mask; + + uint8 latch, vdata_latch; + uint8 strobe; + + int strikeflag; + uint32 strike_cycle; + + /* callbacks for naughty mappers */ + ppulatchfunc_t latchfunc; + ppuvromswitch_t vromswitch; + + /* copy of our current palette */ + rgb_t curpal[256]; + + int vram_accessible; + + int vram_present; + int drawsprites; +} ppu_t; + + +/* TODO: should use this pointers */ +extern void ppu_setlatchfunc(ppulatchfunc_t func); +extern void ppu_setvromswitch(ppuvromswitch_t func); + +extern void ppu_getcontext(ppu_t *dest_ppu); +extern void ppu_setcontext(ppu_t *src_ppu); + +/* Mirroring */ +/* TODO: this is only used bloody once */ +extern void ppu_mirrorhipages(void); + +extern void ppu_mirror(int nt1, int nt2, int nt3, int nt4); + +extern void ppu_setpage(int size, int page_num, uint8 *location); +extern uint8 *ppu_getpage(int page); + + +/* control */ +extern void ppu_reset(int reset_type); +extern int ppu_enabled(void); +extern void ppu_scanline(bitmap_t *bmp, int scanline, int draw_flag); +extern void ppu_endscanline(int scanline); +extern void ppu_checknmi(); + +extern ppu_t *ppu_create(void); +extern void ppu_destroy(ppu_t **ppu); + +/* IO */ +extern uint8 ppu_read(uint32 address); +extern void ppu_write(uint32 address, uint8 value); +extern uint8 ppu_readhigh(uint32 address); +extern void ppu_writehigh(uint32 address, uint8 value); + +/* rendering */ +extern void ppu_setpal(ppu_t *src_ppu, rgb_t *pal); +extern void ppu_setdefaultpal(ppu_t *src_ppu); + +/* bleh */ +extern void ppu_dumppattern(bitmap_t *bmp, int table_num, int x_loc, int y_loc, int col); +extern void ppu_dumpoam(bitmap_t *bmp, int x_loc, int y_loc); +extern void ppu_displaysprites(int display); + +#endif /* _NES_PPU_H_ */ + +/* +** $Log: nes_ppu.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/11/29 12:58:23 matt +** timing/fiq fixes +** +** Revision 1.7 2000/11/27 19:36:16 matt +** more timing fixes +** +** Revision 1.6 2000/11/26 15:51:13 matt +** frame IRQ emulation +** +** Revision 1.5 2000/11/25 20:30:39 matt +** scanline emulation simplifications/timing fixes +** +** Revision 1.4 2000/11/19 13:40:19 matt +** more accurate ppu behavior +** +** Revision 1.3 2000/11/05 16:35:41 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.2 2000/10/27 12:55:03 matt +** palette generating functions now take *this pointers +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.19 2000/10/22 15:02:32 matt +** simplified mirroring +** +** Revision 1.18 2000/10/21 21:36:04 matt +** ppu cleanups / fixes +** +** Revision 1.17 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.16 2000/10/10 13:58:15 matt +** stroustrup squeezing his way in the door +** +** Revision 1.15 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.14 2000/07/30 04:32:33 matt +** emulation of the NES frame IRQ +** +** Revision 1.13 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.12 2000/07/17 05:12:56 matt +** nes_ppu.c is no longer a scary place to be-- cleaner & faster +** +** Revision 1.11 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.10 2000/07/10 05:28:30 matt +** moved joypad/oam dma from apu to ppu +** +** Revision 1.9 2000/07/10 03:03:16 matt +** added ppu_getcontext() routine +** +** Revision 1.8 2000/07/06 16:42:40 matt +** better palette setting interface +** +** Revision 1.7 2000/07/04 23:13:26 matt +** added an irq line drawing debug feature hack +** +** Revision 1.6 2000/06/26 04:58:08 matt +** accuracy changes +** +** Revision 1.5 2000/06/20 00:04:35 matt +** removed STATQUIRK macro +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nofrendo.h =================================================================== --- apps/plugins/nofrendo/nofrendo.h (revision 0) +++ apps/plugins/nofrendo/nofrendo.h (revision 0) @@ -0,0 +1,91 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nofrendo.h (c) 1998-2000 Matthew Conte (matt@conte.com) +** (c) 2000 Neil Stevens (multivac@fcmail.com) +** +** Note: all architectures should call these functions +** +** $Id: nofrendo.h,v 1.2 2001/04/27 11:10:08 neil Exp $ +*/ + +#ifndef _NOFRENDO_H_ +#define _NOFRENDO_H_ + +typedef enum +{ + system_unknown, + system_autodetect, + system_nes, + NUM_SUPPORTED_SYSTEMS +} system_t; + +extern volatile int nofrendo_ticks; /* system timer ticks */ + +/* osd_main should end with a call to main_loop(). +** Pass filename = NULL if you want to start with the demo rom +*/ +extern int main_loop(const char *filename, system_t type); + +/* These should not be called directly. Use the event interface */ +extern void main_insert(const char *filename, system_t type); +extern void main_eject(void); +extern void main_quit(void); + +extern int start(char filename); + +#endif /* !_NOFRENDO_H_ */ + +/* +** $Log: nofrendo.h,v $ +** Revision 1.2 2001/04/27 11:10:08 neil +** compile +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.9 2000/11/25 20:26:05 matt +** removed fds "system" +** +** Revision 1.8 2000/11/20 13:22:12 matt +** standardized timer ISR, added nofrendo_ticks +** +** Revision 1.7 2000/11/01 14:15:35 matt +** multi-system event system, or whatever +** +** Revision 1.6 2000/10/25 13:42:02 matt +** strdup - giddyap! +** +** Revision 1.5 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.4 2000/10/23 15:52:04 matt +** better system handling +** +** Revision 1.3 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.2 2000/07/27 01:16:36 matt +** sorted out the video problems +** +** Revision 1.1 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** +*/ Index: apps/plugins/nofrendo/fds_snd.c =================================================================== --- apps/plugins/nofrendo/fds_snd.c (revision 0) +++ apps/plugins/nofrendo/fds_snd.c (revision 0) @@ -0,0 +1,115 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** fds_snd.c +** +** Famicom Disk System sound emulation +** $Id: fds_snd.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +static int32 fds_incsize = 0; + +/* mix sound channels together */ +static int32 fds_process(void) +{ + int32 output; + output = 0; + + return output; +} + +/* write to registers */ +static void fds_write(uint32 address, uint8 value) +{ + UNUSED(address); + UNUSED(value); +} + +/* reset state of vrcvi sound channels */ +static void fds_reset(void) +{ + apu_t apu; + + apu_getcontext(&apu); +// fds_incsize = apu.cycle_rate; + fds_incsize = (int32) (APU_BASEFREQ * 65536.0 / (float) apu.sample_rate); +} + +static apu_memwrite fds_memwrite[] = +{ + { 0x4040, 0x4092, fds_write }, + { -1, -1, NULL } +}; + +apuext_t fds_ext = +{ + NULL, /* no init */ + NULL, /* no shutdown */ + fds_reset, + fds_process, + NULL, /* no reads */ + fds_memwrite +}; + +/* +** $Log: fds_snd.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.9 2000/10/11 12:13:15 matt +** quelled warnings +** +** Revision 1.8 2000/10/03 11:56:20 matt +** better support for optional sound ext routines +** +** Revision 1.7 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.6 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.5 2000/07/30 04:32:59 matt +** no more apu_getcyclerate hack +** +** Revision 1.4 2000/07/17 01:52:30 matt +** made sure last line of all source files is a newline +** +** Revision 1.3 2000/07/03 02:18:53 matt +** much better external module exporting +** +** Revision 1.2 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.1 2000/06/20 00:06:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_pal.c =================================================================== --- apps/plugins/nofrendo/nes_pal.c (revision 0) +++ apps/plugins/nofrendo/nes_pal.c (revision 0) @@ -0,0 +1,213 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_pal.c +** +** NES RGB palette +** $Id: nes_pal.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +#include "fixedpoint.h" + +#ifndef PI +#define PI 3.1415926535897932384626433832795 +#endif + +/* my NES palette, converted to RGB */ +rgb_t shady_palette[] = +{ + {0x80,0x80,0x80}, {0x00,0x00,0xBB}, {0x37,0x00,0xBF}, {0x84,0x00,0xA6}, + {0xBB,0x00,0x6A}, {0xB7,0x00,0x1E}, {0xB3,0x00,0x00}, {0x91,0x26,0x00}, + {0x7B,0x2B,0x00}, {0x00,0x3E,0x00}, {0x00,0x48,0x0D}, {0x00,0x3C,0x22}, + {0x00,0x2F,0x66}, {0x00,0x00,0x00}, {0x05,0x05,0x05}, {0x05,0x05,0x05}, + + {0xC8,0xC8,0xC8}, {0x00,0x59,0xFF}, {0x44,0x3C,0xFF}, {0xB7,0x33,0xCC}, + {0xFF,0x33,0xAA}, {0xFF,0x37,0x5E}, {0xFF,0x37,0x1A}, {0xD5,0x4B,0x00}, + {0xC4,0x62,0x00}, {0x3C,0x7B,0x00}, {0x1E,0x84,0x15}, {0x00,0x95,0x66}, + {0x00,0x84,0xC4}, {0x11,0x11,0x11}, {0x09,0x09,0x09}, {0x09,0x09,0x09}, + + {0xFF,0xFF,0xFF}, {0x00,0x95,0xFF}, {0x6F,0x84,0xFF}, {0xD5,0x6F,0xFF}, + {0xFF,0x77,0xCC}, {0xFF,0x6F,0x99}, {0xFF,0x7B,0x59}, {0xFF,0x91,0x5F}, + {0xFF,0xA2,0x33}, {0xA6,0xBF,0x00}, {0x51,0xD9,0x6A}, {0x4D,0xD5,0xAE}, + {0x00,0xD9,0xFF}, {0x66,0x66,0x66}, {0x0D,0x0D,0x0D}, {0x0D,0x0D,0x0D}, + + {0xFF,0xFF,0xFF}, {0x84,0xBF,0xFF}, {0xBB,0xBB,0xFF}, {0xD0,0xBB,0xFF}, + {0xFF,0xBF,0xEA}, {0xFF,0xBF,0xCC}, {0xFF,0xC4,0xB7}, {0xFF,0xCC,0xAE}, + {0xFF,0xD9,0xA2}, {0xCC,0xE1,0x99}, {0xAE,0xEE,0xB7}, {0xAA,0xF7,0xEE}, + {0xB3,0xEE,0xFF}, {0xDD,0xDD,0xDD}, {0x11,0x11,0x11}, {0x11,0x11,0x11} +}; + +/* dynamic palette building routines, +** care of Kevin Horton (khorton@iquest.net) +*/ + +/* our global palette */ +rgb_t nes_palette[64]; + + +static float hue = 334.0f; +static float tint = 0.4f; + +#include + +void pal_dechue(void) +{ + hue -= 0.5f; + gui_sendmsg(GUI_GREEN, "hue: %.02f", hue); + pal_generate(); +} +void pal_inchue(void) +{ + hue += 0.5f; + gui_sendmsg(GUI_GREEN, "hue: %.02f", hue); + pal_generate(); +} +void pal_dectint(void) +{ + tint -= 0.01f; + gui_sendmsg(GUI_GREEN, "tint: %.02f", tint); + pal_generate(); +} +void pal_inctint(void) +{ + tint += 0.01f; + gui_sendmsg(GUI_GREEN, "tint: %.02f", tint); + pal_generate(); +} + +static const float lightness[4][4] = +{ + { 0.50f, 0.75f, 1.00f, 1.00f }, + { 0.29f, 0.45f, 0.73f, 0.90f }, + { 0.00f, 0.24f, 0.47f, 0.77f }, + { 0.02f, 0.04f, 0.05f, 0.07f } +}; + +static const int col_angles[16] = +{ + 0, 240, 210, 180, 150, 120, 90, 60, 30, 0, 330, 300, 270, 0, 0, 0 +}; + +void pal_generate(void) +{ + int x, z; + float s, y, theta; + int r, g, b; + + for (x = 0; x < 4; x++) + { + for (z = 0; z < 16; z++) + { + switch (z) + { + case 0: + /* is color $x0? If so, get luma */ + s = 0; + y = lightness[0][x]; + break; + + case 13: + /* is color $xD? If so, get luma */ + s = 0; + y = lightness[2][x]; + break; + + case 14: + case 15: + /* is color $xE/F? If so, set to black */ + s = 0; + y = lightness[3][x]; + + break; + + default: + s = tint; /* grab tint */ + y = lightness[1][x]; /* grab default luminance */ + break; + } + + theta = (float) (PI * ((col_angles[z] + hue) / 180.0)); + + r = (int) (256.0 * (y + s * fp14_sin(theta))); + g = (int) (256.0 * (y - ((27 / 53.0) * s * fp14_sin(theta)) + ((10 / 53.0) * s * fp14_cos(theta)))); + b = (int) (256.0 * (y - (s * fp14_cos(theta)))); + + if (r > 255) + r = 255; + else if (r < 0) + r = 0; + + if (g > 255) + g = 255; + else if (g < 0) + g = 0; + + if (b > 255) + b = 255; + else if (b < 0) + b = 0; + + nes_palette[(x << 4) + z].r = r; + nes_palette[(x << 4) + z].g = g; + nes_palette[(x << 4) + z].b = b; + } + } +} + +/* +** $Log: nes_pal.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.3 2000/11/06 02:17:18 matt +** no more double->float warnings +** +** Revision 1.2 2000/11/05 16:35:41 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.9 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.8 2000/07/10 13:49:31 matt +** renamed my palette and extern'ed it +** +** Revision 1.7 2000/06/26 04:59:13 matt +** selectable tint/hue hack (just for the time being) +** +** Revision 1.6 2000/06/21 21:48:19 matt +** changed range multiplier from 255.0 to 256.0 +** +** Revision 1.5 2000/06/20 20:42:47 matt +** accuracy changes +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/sdl.c =================================================================== --- apps/plugins/nofrendo/sdl.c (revision 0) +++ apps/plugins/nofrendo/sdl.c (revision 0) @@ -0,0 +1,779 @@ +/* vim: set tabstop=3 expandtab: +** +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** sdl.c +** +** $Id: sdl.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SAMPLERATE 22050 +#define DEFAULT_BPS 8 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_WIDTH 256 +#define DEFAULT_HEIGHT NES_VISIBLE_HEIGHT + +/* +** Timer +*/ + +static void (*timer_callback)(void) = NULL; +static int tick_ideal = 0; +static int tick_interval = 0; + +Uint32 mySDLTimer(Uint32 i) +{ + static int tickDiff = 0; + Uint32 tickLast; + + tickLast = SDL_GetTicks(); + + if (timer_callback) + timer_callback(); + + tickDiff += tick_interval - tick_ideal + tickLast - SDL_GetTicks(); + + if (tickDiff >= 10) + { + tickDiff -= 10; + return tick_interval - 10; + } + else + { + return tick_interval; + } +} + +static int round(double value) +{ + int upper, lower; + upper = (int) ceil(value); + lower = (int) floor(value); + + if (upper - value > value - lower) + return lower; + else + return upper; +} + +int osd_installtimer(int frequency, void *func, int funcsize, void *counter, int countersize) +{ + double ideal = 1000 / frequency; + + /* these arguments are used only for djgpp, which needs to lock code/data */ + UNUSED(counter); + UNUSED(countersize); + UNUSED(funcsize); + + tick_ideal = round(ideal); + tick_interval = round(ideal / 10) * 10; + + SDL_SetTimer(tick_interval, mySDLTimer); + + timer_callback = func; + + return 0; +} + + +/* +** Audio +*/ +static int sound_bps = DEFAULT_BPS; +static int sound_samplerate = DEFAULT_SAMPLERATE; +static int sound_fragsize = DEFAULT_FRAGSIZE; +static unsigned char *audioBuffer = NULL; +static void (*audio_callback)(void *buffer, int length) = NULL; + +/* this is the callback that SDL calls to obtain more audio data */ +static void sdl_audio_player(void *udata, unsigned char *stream, int len) +{ + /* SDL requests buffer fills in terms of bytes, not samples */ + if (16 == sound_bps) + len /= 2; + + if (audio_callback) + audio_callback(stream, len); +} + +void osd_setsound(void (*playfunc)(void *buffer, int length)) +{ + audio_callback = playfunc; +} + +static void osd_stopsound(void) +{ + audio_callback = NULL; + + SDL_CloseAudio(); + if (NULL != audioBuffer) + free(audioBuffer); +} + +static int osd_init_sound(void) +{ + SDL_AudioSpec wanted, obtained; + unsigned int bufferSize; + + sound_bps = config.read_int("sdlaudio", "sound_bps", DEFAULT_BPS); + sound_samplerate = config.read_int("sdlaudio", "sound_samplerate", DEFAULT_SAMPLERATE); + sound_fragsize = config.read_int("sdlaudio", "sound_fragsize", DEFAULT_FRAGSIZE); + + if (sound_bps != 8 && sound_bps != 16) + sound_bps = 8; + + if (sound_samplerate < 5000) + sound_samplerate = 5000; + else if (sound_samplerate > 48000) + sound_samplerate = 48000; + + if (sound_fragsize < 128) + sound_fragsize = 128; + else if (sound_fragsize > 32768) + sound_fragsize = 32768; + + audio_callback = NULL; + + /* set the audio format */ + wanted.freq = sound_samplerate; + wanted.format = (sound_bps == 8) ? AUDIO_U8 : AUDIO_S16; + wanted.channels = 1; /* 1 = mono, 2 = stereo */ + wanted.samples = sound_fragsize; + wanted.callback = sdl_audio_player; + wanted.userdata = NULL; + + if (SDL_OpenAudio (&wanted, &obtained) < 0) + { + log_printf("Couldn't open audio: %s\n", SDL_GetError()); + return -1; + } + + /* ensure we get U8 or S16 */ + if (AUDIO_U8 != obtained.format && AUDIO_S16 != obtained.format) + { + log_printf("Could not get correct audio output format\n"); + return -1; + } + + sound_bps = (obtained.format == AUDIO_U8) ? 8 : 16; + sound_samplerate = obtained.freq; + /* twice as big, to be on the safe side */ + bufferSize = (sound_bps / 8) * obtained.samples * 2; + + audioBuffer = malloc(bufferSize); + if (NULL == audioBuffer) + { + log_printf("error allocating audio buffer\n"); + return -1; + } + + SDL_PauseAudio(0); + return 0; +} + +void osd_getsoundinfo(sndinfo_t *info) +{ + info->sample_rate = sound_samplerate; + info->bps = sound_bps; +} + +/* +** Video +*/ + +static int init(int width, int height); +static void shutdown(void); +static int set_mode(int width, int height); +static void set_palette(rgb_t *pal); +static void clear(uint8 color); +static bitmap_t *lock_write(void); +static void free_write(int num_dirties, rect_t *dirty_rects); + +viddriver_t sdlDriver = +{ + "Simple DirectMedia Layer", /* name */ + init, /* init */ + shutdown, /* shutdown */ + set_mode, /* set_mode */ + set_palette, /* set_palette */ + clear, /* clear */ + lock_write, /* lock_write */ + free_write, /* free_write */ + NULL, /* custom_blit */ + false /* invalidate flag */ +}; + +void osd_getvideoinfo(vidinfo_t *info) +{ + info->default_width = DEFAULT_WIDTH; + info->default_height = DEFAULT_HEIGHT; + info->driver = &sdlDriver; +} + +/* Now that the driver declaration is out of the way, on to the SDL stuff */ +static SDL_Surface *mySurface = NULL; +static SDL_Color myPalette[256]; +static bitmap_t *myBitmap = NULL; +static bool fullscreen = false; + +/* flip between full screen and windowed */ +void osd_togglefullscreen(int code) +{ + bool pause; + nes_t *nes = nes_getcontextptr(); + + if (INP_STATE_MAKE != code) + return; + + ASSERT(nes); + + pause = nes->pause; + nes->pause = true; + + fullscreen ^= true; + + if (set_mode(mySurface->w, mySurface->h)) + ASSERT(0); + + sdlDriver.invalidate = true; + + nes->pause = pause; +} + +/* initialise SDL video */ +static int init(int width, int height) +{ + return set_mode(width, height); +} + +/* squash memory leaks */ +static void shutdown(void) +{ + if (NULL != mySurface) + { + SDL_FreeSurface(mySurface); + mySurface = NULL; + } + + if (NULL != myBitmap) + bmp_destroy(&myBitmap); +} + +/* set a video mode */ +static int set_mode(int width, int height) +{ + int flags; + bool restorePalette; + + if (NULL != mySurface) + { + SDL_FreeSurface(mySurface); + mySurface = NULL; + restorePalette = true; + } + + if (fullscreen) + { + flags = SDL_HWSURFACE | SDL_HWPALETTE | SDL_FULLSCREEN; + mySurface = SDL_SetVideoMode(width, height, 8, flags); + if (NULL == mySurface) + log_printf("Fullscreeen failed: %s\n", SDL_GetError()); + } + + if (NULL == mySurface) + { + fullscreen = false; + flags = SDL_HWSURFACE | SDL_HWPALETTE; + mySurface = SDL_SetVideoMode(width, height, 8, flags); + } + + if (NULL == mySurface) + { + log_printf("SDL Video failed: %s\n", SDL_GetError()); + return -1; + } + + if (restorePalette) + { + SDL_SetColors(mySurface, myPalette, 0, 256); + } + + SDL_ShowCursor(0); + return 0; +} + +/* copy nes palette over to hardware */ +static void set_palette(rgb_t *pal) +{ + int i; + + for (i = 0; i < 256; i++) + { + myPalette[i].r = pal[i].r; + myPalette[i].g = pal[i].g; + myPalette[i].b = pal[i].b; + } + + SDL_SetColors(mySurface, myPalette, 0, 256); +} + +/* clear all frames to a particular color */ +static void clear(uint8 color) +{ + SDL_FillRect(mySurface, 0, color); +} + +/* acquire the directbuffer for writing */ +static bitmap_t *lock_write(void) +{ + SDL_LockSurface(mySurface); + myBitmap = bmp_createhw(mySurface->pixels, mySurface->w, + mySurface->h, mySurface->pitch); + return myBitmap; +} + +/* release the resource */ +static void free_write(int num_dirties, rect_t *dirty_rects) +{ + bmp_destroy(&myBitmap); + SDL_UnlockSurface(mySurface); + + if (-1 == num_dirties) + { + SDL_UpdateRect(mySurface, 0, 0, 0, 0); + } + else if (num_dirties > 0) + { + /* loop through and modify the rects to be in terms of the screen */ + if (NES_SCREEN_WIDTH < mySurface->w || NES_VISIBLE_HEIGHT < mySurface->h) + { + int i, x_offset, y_offset; + + x_offset = (mySurface->w - NES_SCREEN_WIDTH) >> 1; + y_offset = (mySurface->h - NES_VISIBLE_HEIGHT) >> 1; + + for (i = 0; i < num_dirties; i++) + { + dirty_rects[i].x += x_offset; + dirty_rects[i].y += y_offset; + } + } + + SDL_UpdateRects(mySurface, num_dirties, (SDL_Rect *) dirty_rects); + } +} + +/* +** Input +*/ + +typedef struct joystick_s +{ + SDL_Joystick *js; + int *button_array; + int *axis_array; +} joystick_t; + +static joystick_t **joystick_array = 0; +static int joystick_count = 0; + +static int key_array[SDLK_LAST]; +#define LOAD_KEY(key, def_key) \ +key_array[key] = config.read_int("sdlkeys", #key, def_key) + +static void osd_initinput() +{ + int i, j; + SDL_Joystick *js; + char group[255]; + char key[255]; + + /* joystick */ + + joystick_count = SDL_NumJoysticks(); + joystick_array = malloc(joystick_count * sizeof(joystick_t *)); + + if (NULL == joystick_array) + { + log_printf("error allocating space for joystick array\n"); + joystick_count = 0; + } + + log_printf("joystick_count == %i\n", joystick_count); + + for (i = 0; i < joystick_count; i++) + { + sprintf(group, "sdljoystick%i", i); + js = SDL_JoystickOpen(i); + + if (js) + { + joystick_array[i] = malloc(sizeof(joystick_t)); + joystick_array[i]->js = js; + + log_printf("joystick %i is a %s\n", i, SDL_JoystickName(i)); + + /* load buttons */ + j = SDL_JoystickNumButtons(joystick_array[i]->js); + joystick_array[i]->button_array = malloc(j * sizeof(int)); + for (j--; j >= 0; j--) + { + sprintf(key, "button%i", j); + joystick_array[i]->button_array[j] = config.read_int(group, key, event_none); + } + + /* load axes */ + j = SDL_JoystickNumAxes(joystick_array[i]->js); + joystick_array[i]->axis_array = malloc(j * sizeof(int) * 2); + for (j--; j >= 0; j--) + { + sprintf(key, "positiveaxis%i", j); + joystick_array[i]->axis_array[(j << 1) + 1] = config.read_int(group, key, event_none); + + sprintf(key, "negativeaxis%i", j); + joystick_array[i]->axis_array[j << 1] = config.read_int(group, key, event_none); + } + } + else + { + joystick_array[i] = 0; + } + } + + SDL_JoystickEventState(SDL_ENABLE); + + /* keyboard */ + + LOAD_KEY(SDLK_ESCAPE, event_quit); + + LOAD_KEY(SDLK_F1, event_soft_reset); + LOAD_KEY(SDLK_F2, event_hard_reset); + LOAD_KEY(SDLK_F3, event_gui_toggle_fps); + LOAD_KEY(SDLK_F4, event_snapshot); + LOAD_KEY(SDLK_F5, event_state_save); + LOAD_KEY(SDLK_F6, event_toggle_sprites); + LOAD_KEY(SDLK_F7, event_state_load); + LOAD_KEY(SDLK_F8, event_none); + LOAD_KEY(SDLK_F9, event_none); + LOAD_KEY(SDLK_F10, event_osd_1); + LOAD_KEY(SDLK_F11, event_none); + LOAD_KEY(SDLK_F12, event_none); + + LOAD_KEY(SDLK_BACKQUOTE, event_none); + + LOAD_KEY(SDLK_1, event_state_slot_1); + LOAD_KEY(SDLK_EXCLAIM, event_state_slot_1); + LOAD_KEY(SDLK_2, event_state_slot_2); + LOAD_KEY(SDLK_AT, event_state_slot_2); + LOAD_KEY(SDLK_3, event_state_slot_3); + LOAD_KEY(SDLK_HASH, event_state_slot_3); + LOAD_KEY(SDLK_4, event_state_slot_4); + LOAD_KEY(SDLK_DOLLAR, event_state_slot_4); + LOAD_KEY(SDLK_5, event_state_slot_5); +/* LOAD_KEY(SDLK_PERCENT, event_state_slot_5);*/ + LOAD_KEY(SDLK_6, event_state_slot_6); + LOAD_KEY(SDLK_CARET, event_state_slot_6); + LOAD_KEY(SDLK_7, event_state_slot_7); + LOAD_KEY(SDLK_AMPERSAND, event_state_slot_7); + LOAD_KEY(SDLK_8, event_state_slot_8); + LOAD_KEY(SDLK_ASTERISK, event_state_slot_8); + LOAD_KEY(SDLK_9, event_state_slot_9); + LOAD_KEY(SDLK_LEFTPAREN, event_state_slot_9); + LOAD_KEY(SDLK_0, event_state_slot_0); + LOAD_KEY(SDLK_RIGHTPAREN, event_state_slot_0); + + LOAD_KEY(SDLK_MINUS, event_gui_pattern_color_down); + LOAD_KEY(SDLK_UNDERSCORE, event_gui_pattern_color_down); + LOAD_KEY(SDLK_EQUALS, event_gui_pattern_color_up); + LOAD_KEY(SDLK_PLUS, event_gui_pattern_color_up); + + LOAD_KEY(SDLK_BACKSPACE, event_gui_display_info); + + LOAD_KEY(SDLK_TAB, event_joypad1_select); + + LOAD_KEY(SDLK_q, event_toggle_channel_0); + LOAD_KEY(SDLK_w, event_toggle_channel_1); + LOAD_KEY(SDLK_e, event_toggle_channel_2); + LOAD_KEY(SDLK_r, event_toggle_channel_3); + LOAD_KEY(SDLK_t, event_toggle_channel_4); + LOAD_KEY(SDLK_y, event_toggle_channel_5); + LOAD_KEY(SDLK_u, event_palette_hue_down); + LOAD_KEY(SDLK_i, event_palette_hue_up); + LOAD_KEY(SDLK_o, event_gui_toggle_oam); + LOAD_KEY(SDLK_p, event_gui_toggle_pattern); + +/* LOAD_KEY(SDLK_LEFTBRACE, event_none); + LOAD_KEY(SDLK_RIGHTBRACE, event_none);*/ + LOAD_KEY(SDLK_LEFTBRACKET, event_none); + LOAD_KEY(SDLK_RIGHTBRACKET, event_none); + LOAD_KEY(SDLK_BACKSLASH, event_toggle_frameskip); +/* LOAD_KEY(SDLK_Bar, event_toggle_frameskip);*/ + + LOAD_KEY(SDLK_a, event_gui_toggle_wave); + LOAD_KEY(SDLK_s, event_set_filter_0); + LOAD_KEY(SDLK_d, event_set_filter_1); + LOAD_KEY(SDLK_f, event_set_filter_2); + LOAD_KEY(SDLK_g, event_none); + LOAD_KEY(SDLK_h, event_none); + LOAD_KEY(SDLK_j, event_palette_tint_down); + LOAD_KEY(SDLK_k, event_palette_tint_up); + LOAD_KEY(SDLK_l, event_palette_set_shady); + LOAD_KEY(SDLK_COLON, event_palette_set_default); + LOAD_KEY(SDLK_SEMICOLON, event_palette_set_default); + LOAD_KEY(SDLK_QUOTEDBL, event_none); + LOAD_KEY(SDLK_RETURN, event_joypad1_start); + LOAD_KEY(SDLK_PAUSE, event_togglepause); + + LOAD_KEY(SDLK_z, event_joypad1_b); + LOAD_KEY(SDLK_x, event_joypad1_a); + LOAD_KEY(SDLK_c, event_joypad1_select); + LOAD_KEY(SDLK_v, event_joypad1_start); + LOAD_KEY(SDLK_b, event_joypad2_b); + LOAD_KEY(SDLK_n, event_joypad2_a); + LOAD_KEY(SDLK_m, event_joypad2_select); + LOAD_KEY(SDLK_COMMA, event_joypad2_start); + LOAD_KEY(SDLK_LESS, event_none); + LOAD_KEY(SDLK_PERIOD, event_none); + LOAD_KEY(SDLK_GREATER, event_none); + LOAD_KEY(SDLK_QUESTION, event_none); + LOAD_KEY(SDLK_SLASH, event_none); + + LOAD_KEY(SDLK_SPACE, event_gui_toggle); + + LOAD_KEY(SDLK_LCTRL, event_joypad1_b); + LOAD_KEY(SDLK_RCTRL, event_joypad1_b); + LOAD_KEY(SDLK_LALT, event_joypad1_a); + LOAD_KEY(SDLK_RALT, event_joypad1_a); + LOAD_KEY(SDLK_LSHIFT, event_joypad1_a); + LOAD_KEY(SDLK_RSHIFT, event_joypad1_a); + + LOAD_KEY(SDLK_KP1, event_none); + LOAD_KEY(SDLK_KP2, event_joypad1_down); + LOAD_KEY(SDLK_KP3, event_none); + LOAD_KEY(SDLK_KP4, event_joypad1_left); + LOAD_KEY(SDLK_KP5, event_startsong); + LOAD_KEY(SDLK_KP6, event_joypad1_right); + LOAD_KEY(SDLK_KP7, event_songdown); + LOAD_KEY(SDLK_KP8, event_joypad1_up); + LOAD_KEY(SDLK_KP9, event_songup); + LOAD_KEY(SDLK_UP, event_joypad1_up); + LOAD_KEY(SDLK_DOWN, event_joypad1_down); + LOAD_KEY(SDLK_LEFT, event_joypad1_left); + LOAD_KEY(SDLK_RIGHT, event_joypad1_right); + LOAD_KEY(SDLK_HOME, event_none); + LOAD_KEY(SDLK_END, event_none); + LOAD_KEY(SDLK_PAGEUP, event_none); + LOAD_KEY(SDLK_PAGEDOWN, event_none); + LOAD_KEY(SDLK_KP_PLUS, event_toggle_frameskip); + + /* events */ + + event_set(event_osd_1, osd_togglefullscreen); +} + +void osd_getinput(void) +{ + int code, highval, lowval; + SDL_Event myEvent; + event_t func_event; + + while (SDL_PollEvent(&myEvent)) + { + switch(myEvent.type) + { + case SDL_KEYDOWN: + case SDL_KEYUP: + code = (myEvent.key.state == SDL_PRESSED) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get(key_array[myEvent.key.keysym.sym]); + if (func_event) + func_event(code); + break; + + case SDL_QUIT: + event_get(event_quit)(INP_STATE_MAKE); + break; + + case SDL_JOYAXISMOTION: + highval = (myEvent.jaxis.value > 0) ? INP_STATE_MAKE : INP_STATE_BREAK; + lowval = (myEvent.jaxis.value < 0) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get(joystick_array[myEvent.jaxis.which]->axis_array[myEvent.jaxis.axis << 1]); + if (func_event) + func_event(lowval); + + func_event = event_get(joystick_array[myEvent.jaxis.which]->axis_array[(myEvent.jaxis.axis << 1) + 1]); + if (func_event) + func_event(highval); + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + code = (myEvent.jbutton.state == SDL_PRESSED) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get( joystick_array[myEvent.jbutton.which]->button_array[myEvent.jbutton.button] ); + if (func_event) + func_event(code); + break; + + default: + break; + } + } +} + +static void osd_freeinput(void) +{ + int i; + + for (i = 0; i < joystick_count; i++) + { + if (joystick_array[i]) + { + SDL_JoystickClose(joystick_array[i]->js); + free(joystick_array[i]->button_array); + free(joystick_array[i]->axis_array); + free(joystick_array[i]); + } + } + + free(joystick_array); +} + +void osd_getmouse(int *x, int *y, int *button) +{ + *button = SDL_GetMouseState(x, y); +} + +/* +** Shutdown +*/ + +/* this is at the bottom, to eliminate warnings */ +void osd_shutdown() +{ + osd_stopsound(); + osd_freeinput(); + SDL_Quit(); +} + +static int logprint(const char *string) +{ + return fprintf(stderr, "%s", string); +} + +/* +** Startup +*/ + +int osd_init() +{ + log_chain_logfunc(logprint); + + /* Initialize the SDL library */ + if (SDL_Init (SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_VIDEO + | SDL_INIT_JOYSTICK) < 0) + { + printf("Couldn't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + SDL_WM_SetCaption("Nofrendo", 0); + + if (osd_init_sound()) + return -1; + + osd_initinput(); + + return 0; +} + +/* +** $Log: sdl.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.16 2000/12/11 13:31:41 neil +** caption +** +** Revision 1.15 2000/11/25 20:29:42 matt +** tiny mod +** +** Revision 1.14 2000/11/09 14:06:31 matt +** state load fixed, state save mostly fixed +** +** Revision 1.13 2000/11/06 02:20:00 matt +** vid_drv / log api changes +** +** Revision 1.12 2000/11/05 16:36:06 matt +** thinlib round 2 +** +** Revision 1.11 2000/11/05 06:26:41 matt +** thinlib spawns changes +** +** Revision 1.10 2000/11/01 17:31:54 neil +** fixed some conflicting key assignments +** +** Revision 1.9 2000/11/01 14:17:16 matt +** multi-system event system, or whatever +** +** Revision 1.8 2000/10/23 15:54:15 matt +** suppressed warnings +** +** Revision 1.7 2000/10/22 20:37:33 neil +** restored proper timer correction, and added support for variable frequencies +** +** Revision 1.6 2000/10/22 19:17:06 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.5 2000/10/21 19:34:03 matt +** many more cleanups +** +** Revision 1.4 2000/10/17 11:59:29 matt +** let me see why i can't go window->full->window +** +** Revision 1.3 2000/10/13 14:09:57 matt +** sound is configurable from config file +** +** Revision 1.2 2000/10/13 13:19:15 matt +** fixed a few minor bugs and 16-bit sound +** +** Revision 1.1 2000/10/10 14:24:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/fds_snd.h =================================================================== --- apps/plugins/nofrendo/fds_snd.h (revision 0) +++ apps/plugins/nofrendo/fds_snd.h (revision 0) @@ -0,0 +1,59 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** fds_snd.h +** +** Famicom Disk System sound emulation +** $Id: fds_snd.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _FDS_SND_H_ +#define _FDS_SND_H_ + +#include + +extern apuext_t fds_ext; + + +#endif /* _VRCVISND_H_ */ + +/* +** $Log: fds_snd.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.3 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.2 2000/06/20 04:06:16 matt +** migrated external sound definition to apu module +** +** Revision 1.1 2000/06/20 00:06:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nesstate.c =================================================================== --- apps/plugins/nofrendo/nesstate.c (revision 0) +++ apps/plugins/nofrendo/nesstate.c (revision 0) @@ -0,0 +1,517 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nesstate.c +** +** state saving/loading +** $Id: nesstate.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nes6502.h" + +#define FIRST_STATE_SLOT 0 +#define LAST_STATE_SLOT 9 + +static int state_slot = FIRST_STATE_SLOT; + +/* Set the state-save slot to use (0 - 9) */ +void state_setslot(int slot) +{ + /* Don't send a message if we're already at that slot */ + if (state_slot != slot && slot >= FIRST_STATE_SLOT + && slot <= LAST_STATE_SLOT) + { + state_slot = slot; + gui_sendmsg(GUI_WHITE, "State slot set to %d", slot); + } +} + +static int save_baseblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + + ASSERT(state); + + nes6502_getcontext(state->cpu); + ppu_getcontext(state->ppu); + + snssFile->baseBlock.regA = state->cpu->a_reg; + snssFile->baseBlock.regX = state->cpu->x_reg; + snssFile->baseBlock.regY = state->cpu->y_reg; + snssFile->baseBlock.regFlags = state->cpu->p_reg; + snssFile->baseBlock.regStack = state->cpu->s_reg; + snssFile->baseBlock.regPc = state->cpu->pc_reg; + + snssFile->baseBlock.reg2000 = state->ppu->ctrl0; + snssFile->baseBlock.reg2001 = state->ppu->ctrl1; + + memcpy(snssFile->baseBlock.cpuRam, state->cpu->mem_page[0], 0x800); + memcpy(snssFile->baseBlock.spriteRam, state->ppu->oam, 0x100); + memcpy(snssFile->baseBlock.ppuRam, state->ppu->nametab, 0x1000); + + /* Mask off priority color bits */ + for (i = 0; i < 32; i++) + snssFile->baseBlock.palette[i] = state->ppu->palette[i] & 0x3F; + + snssFile->baseBlock.mirrorState[0] = (state->ppu->page[8] + 0x2000 - state->ppu->nametab) / 0x400; + snssFile->baseBlock.mirrorState[1] = (state->ppu->page[9] + 0x2400 - state->ppu->nametab) / 0x400; + snssFile->baseBlock.mirrorState[2] = (state->ppu->page[10] + 0x2800 - state->ppu->nametab) / 0x400; + snssFile->baseBlock.mirrorState[3] = (state->ppu->page[11] + 0x2C00 - state->ppu->nametab) / 0x400; + + snssFile->baseBlock.vramAddress = state->ppu->vaddr; + snssFile->baseBlock.spriteRamAddress = state->ppu->oam_addr; + snssFile->baseBlock.tileXOffset = state->ppu->tile_xofs; + + return 0; +} + +static int save_vramblock(nes_t *state, SNSS_FILE *snssFile) +{ + ASSERT(state); + + if (NULL == state->rominfo->vram) + return -1; + + if (state->rominfo->vram_banks > 2) + { + log_printf("too many VRAM banks: %d\n", state->rominfo->vram_banks); + return -1; + } + + snssFile->vramBlock.vramSize = VRAM_8K * state->rominfo->vram_banks; + + memcpy(snssFile->vramBlock.vram, state->rominfo->vram, snssFile->vramBlock.vramSize); + return 0; +} + +static int save_sramblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + int written = 0; + int sram_length; + + ASSERT(state); + + sram_length = state->rominfo->sram_banks * SRAM_1K; + + /* Check to see if any SRAM was written to */ + for (i = 0; i < sram_length; i++) + { + if (state->rominfo->sram[i]) + { + written = 1; + break; + } + } + + if (0 == written) + return -1; + + if (state->rominfo->sram_banks > 8) + { + log_printf("Unsupported number of SRAM banks: %d\n", state->rominfo->sram_banks); + return -1; + } + + snssFile->sramBlock.sramSize = SRAM_1K * state->rominfo->sram_banks; + + /* TODO: this should not always be true!! */ + snssFile->sramBlock.sramEnabled = 1; + + memcpy(snssFile->sramBlock.sram, state->rominfo->sram, snssFile->sramBlock.sramSize); + + return 0; +} + +static int save_soundblock(nes_t *state, SNSS_FILE *snssFile) +{ + ASSERT(state); + + apu_getcontext(state->apu); + + /* rect 0 */ + snssFile->soundBlock.soundRegisters[0x00] = state->apu->rectangle[0].regs[0]; + snssFile->soundBlock.soundRegisters[0x01] = state->apu->rectangle[0].regs[1]; + snssFile->soundBlock.soundRegisters[0x02] = state->apu->rectangle[0].regs[2]; + snssFile->soundBlock.soundRegisters[0x03] = state->apu->rectangle[0].regs[3]; + /* rect 1 */ + snssFile->soundBlock.soundRegisters[0x04] = state->apu->rectangle[1].regs[0]; + snssFile->soundBlock.soundRegisters[0x05] = state->apu->rectangle[1].regs[1]; + snssFile->soundBlock.soundRegisters[0x06] = state->apu->rectangle[1].regs[2]; + snssFile->soundBlock.soundRegisters[0x07] = state->apu->rectangle[1].regs[3]; + /* triangle */ + snssFile->soundBlock.soundRegisters[0x08] = state->apu->triangle.regs[0]; + snssFile->soundBlock.soundRegisters[0x0A] = state->apu->triangle.regs[1]; + snssFile->soundBlock.soundRegisters[0x0B] = state->apu->triangle.regs[2]; + /* noise */ + snssFile->soundBlock.soundRegisters[0X0C] = state->apu->noise.regs[0]; + snssFile->soundBlock.soundRegisters[0X0E] = state->apu->noise.regs[1]; + snssFile->soundBlock.soundRegisters[0x0F] = state->apu->noise.regs[2]; + /* dmc */ + snssFile->soundBlock.soundRegisters[0x10] = state->apu->dmc.regs[0]; + snssFile->soundBlock.soundRegisters[0x11] = state->apu->dmc.regs[1]; + snssFile->soundBlock.soundRegisters[0x12] = state->apu->dmc.regs[2]; + snssFile->soundBlock.soundRegisters[0x13] = state->apu->dmc.regs[3]; + /* control */ + snssFile->soundBlock.soundRegisters[0x15] = state->apu->enable_reg; + + return 0; +} + +static int save_mapperblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + ASSERT(state); + + mmc_getcontext(state->mmc); + + /* TODO: filthy hack in snss standard */ + /* We don't need to write mapper state for mapper 0 */ + if (0 == state->mmc->intf->number) + return -1; + + nes6502_getcontext(state->cpu); + + /* TODO: snss spec should be updated, using 4kB ROM pages.. */ + for (i = 0; i < 4; i++) + snssFile->mapperBlock.prgPages[i] = (state->cpu->mem_page[(i + 4) * 2] - state->rominfo->rom) >> 13; + + if (state->rominfo->vrom_banks) + { + for (i = 0; i < 8; i++) + snssFile->mapperBlock.chrPages[i] = (ppu_getpage(i) - state->rominfo->vrom + (i * 0x400)) >> 10; + } + else + { + /* bleh! slight hack */ + for (i = 0; i < 8; i++) + snssFile->mapperBlock.chrPages[i] = i; + } + + if (state->mmc->intf->get_state) + state->mmc->intf->get_state(&snssFile->mapperBlock); + + return 0; +} + +static void load_baseblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + + ASSERT(state); + + nes6502_getcontext(state->cpu); + ppu_getcontext(state->ppu); + + state->cpu->a_reg = snssFile->baseBlock.regA; + state->cpu->x_reg = snssFile->baseBlock.regX; + state->cpu->y_reg = snssFile->baseBlock.regY; + state->cpu->p_reg = snssFile->baseBlock.regFlags; + state->cpu->s_reg = snssFile->baseBlock.regStack; + state->cpu->pc_reg = snssFile->baseBlock.regPc; + + state->ppu->ctrl0 = snssFile->baseBlock.reg2000; + state->ppu->ctrl1 = snssFile->baseBlock.reg2001; + + memcpy(state->cpu->mem_page[0], snssFile->baseBlock.cpuRam, 0x800); + memcpy(state->ppu->oam, snssFile->baseBlock.spriteRam, 0x100); + memcpy(state->ppu->nametab, snssFile->baseBlock.ppuRam, 0x1000); + memcpy(state->ppu->palette, snssFile->baseBlock.palette, 0x20); + + /* TODO: argh, this is to handle nofrendo's filthy sprite priority method */ + for (i = 0; i < 8; i++) + state->ppu->palette[i << 2] = state->ppu->palette[0] | 0x80;//BG_TRANS_MASK; + + for (i = 0; i < 4; i++) + { + state->ppu->page[i + 8] = state->ppu->page[i + 12] = + state->ppu->nametab + (snssFile->baseBlock.mirrorState[i] * 0x400) - (0x2000 + (i * 0x400)); + } + + state->ppu->vaddr = snssFile->baseBlock.vramAddress; + state->ppu->oam_addr = snssFile->baseBlock.spriteRamAddress; + state->ppu->tile_xofs = snssFile->baseBlock.tileXOffset; + + /* do some extra handling */ + state->ppu->flipflop = 0; + state->ppu->strikeflag = 0; + + nes6502_setcontext(state->cpu); + ppu_setcontext(state->ppu); + + ppu_write(PPU_CTRL0, state->ppu->ctrl0); + ppu_write(PPU_CTRL1, state->ppu->ctrl1); + ppu_write(PPU_VADDR, (uint8) (state->ppu->vaddr >> 8)); + ppu_write(PPU_VADDR, (uint8) (state->ppu->vaddr & 0xFF)); +} + +static void load_vramblock(nes_t *state, SNSS_FILE *snssFile) +{ + ASSERT(state); + + ASSERT(snssFile->vramBlock.vramSize <= VRAM_8K); /* can't handle more than this! */ + memcpy(state->rominfo->vram, snssFile->vramBlock.vram, snssFile->vramBlock.vramSize); +} + +static void load_sramblock(nes_t *state, SNSS_FILE *snssFile) +{ + ASSERT(state); + + ASSERT(snssFile->sramBlock.sramSize <= SRAM_8K); /* can't handle more than this! */ + memcpy(state->rominfo->sram, snssFile->sramBlock.sram, snssFile->sramBlock.sramSize); +} + +static void load_controllerblock(nes_t *state, SNSS_FILE *snssFile) +{ + UNUSED(state); + UNUSED(snssFile); +} + +static void load_soundblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + + ASSERT(state); + + for (i = 0; i < 0x15; i++) + { + if (i != 0x13) /* do NOT trigger OAM DMA! */ + apu_write(0x4000 + i, snssFile->soundBlock.soundRegisters[i]); + } +} + +/* TODO: magic numbers galore */ +static void load_mapperblock(nes_t *state, SNSS_FILE *snssFile) +{ + int i; + + ASSERT(state); + + mmc_getcontext(state->mmc); + + for (i = 0; i < 4; i++) + mmc_bankrom(8, 0x8000 + (i * 0x2000), snssFile->mapperBlock.prgPages[i]); + + if (state->rominfo->vrom_banks) + { + for (i = 0; i < 8; i++) + mmc_bankvrom(1, i * 0x400, snssFile->mapperBlock.chrPages[i]); + } + else + { + ASSERT(state->rominfo->vram); + + for (i = 0; i < 8; i++) + ppu_setpage(1, i, state->rominfo->vram); + } + + if (state->mmc->intf->set_state) + state->mmc->intf->set_state(&snssFile->mapperBlock); + + mmc_setcontext(state->mmc); +} + + +int state_save(void) +{ + SNSS_FILE *snssFile; + SNSS_RETURN_CODE status; + char fn[PATH_MAX + 1], ext[5]; + nes_t *machine; + + /* get the pointer to our NES machine context */ + machine = nes_getcontextptr(); + ASSERT(machine); + + /* build our filename using the image's name and the slot number */ + strncpy(fn, machine->rominfo->filename, PATH_MAX - 4); + + ASSERT(state_slot >= FIRST_STATE_SLOT && state_slot <= LAST_STATE_SLOT); + //sprintf(ext, ".ss%d", state_slot); + osd_newextension(fn, ext); + + /* open our state file for writing */ + status = SNSS_OpenFile(&snssFile, fn, SNSS_OPEN_WRITE); + if (SNSS_OK != status) + goto _error; + + /* now get all of our blocks */ + if (0 == save_baseblock(machine, snssFile)) + { + status = SNSS_WriteBlock(snssFile, SNSS_BASR); + if (SNSS_OK != status) + goto _error; + } + + if (0 == save_vramblock(machine, snssFile)) + { + status = SNSS_WriteBlock(snssFile, SNSS_VRAM); + if (SNSS_OK != status) + goto _error; + } + + if (0 == save_sramblock(machine, snssFile)) + { + status = SNSS_WriteBlock(snssFile, SNSS_SRAM); + if (SNSS_OK != status) + goto _error; + } + + if (0 == save_soundblock(machine, snssFile)) + { + status = SNSS_WriteBlock(snssFile, SNSS_SOUN); + if (SNSS_OK != status) + goto _error; + } + + if (0 == save_mapperblock(machine, snssFile)) + { + status = SNSS_WriteBlock(snssFile, SNSS_MPRD); + if (SNSS_OK != status) + goto _error; + } + + /* close the file, we're done */ + status = SNSS_CloseFile(&snssFile); + if (SNSS_OK != status) + goto _error; + + gui_sendmsg(GUI_GREEN, "State %d saved", state_slot); + return 0; + +_error: + gui_sendmsg(GUI_RED, "error: %s", SNSS_GetErrorString(status)); + SNSS_CloseFile(&snssFile); + return -1; +} + +int state_load(void) +{ + SNSS_FILE *snssFile; + SNSS_RETURN_CODE status; + SNSS_BLOCK_TYPE block_type; + char fn[PATH_MAX + 1], ext[5]; + unsigned int i; + nes_t *machine; + + /* get our machine's context pointer */ + machine = nes_getcontextptr(); + ASSERT(machine); + + /* build the state name using the ROM's name and the slot number */ + strncpy(fn, machine->rominfo->filename, PATH_MAX - 4); + + ASSERT(state_slot >= FIRST_STATE_SLOT && state_slot <= LAST_STATE_SLOT); + //sprintf(ext, ".ss%d", state_slot); + osd_newextension(fn, ext); + + /* open our file for writing */ + status = SNSS_OpenFile(&snssFile, fn, SNSS_OPEN_READ); + if (SNSS_OK != status) + goto _error; + + /* iterate through all present blocks */ + for (i = 0; i < snssFile->headerBlock.numberOfBlocks; i++) + { + status = SNSS_GetNextBlockType(&block_type, snssFile); + if (SNSS_OK != status) + goto _error; + + status = SNSS_ReadBlock(snssFile, block_type); + if (SNSS_OK != status) + goto _error; + + switch (block_type) + { + case SNSS_BASR: + load_baseblock(machine, snssFile); + break; + + case SNSS_VRAM: + load_vramblock(machine, snssFile); + break; + + case SNSS_SRAM: + load_sramblock(machine, snssFile); + break; + + case SNSS_MPRD: + load_mapperblock(machine, snssFile); + break; + + case SNSS_CNTR: + load_controllerblock(machine, snssFile); + break; + + case SNSS_SOUN: + load_soundblock(machine, snssFile); + break; + + case SNSS_UNKNOWN_BLOCK: + default: + log_printf("unknown SNSS block type\n"); + break; + } + } + + /* close file, we're done */ + status = SNSS_CloseFile(&snssFile); + if (SNSS_OK != status) + goto _error; + + gui_sendmsg(GUI_GREEN, "State %d restored", state_slot); + + return 0; + +_error: + gui_sendmsg(GUI_RED, "error: %s", SNSS_GetErrorString(status)); + SNSS_CloseFile(&snssFile); + return -1; +} + +/* +** $Log: nesstate.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.4 2000/11/11 14:52:33 matt +** states finally bleepin' work again +** +** Revision 1.3 2000/11/09 14:07:28 matt +** state load fixed, state save mostly fixed +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_pal.h =================================================================== --- apps/plugins/nofrendo/nes_pal.h (revision 0) +++ apps/plugins/nofrendo/nes_pal.h (revision 0) @@ -0,0 +1,65 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_pal.h +** +** NES palette definition +** $Id: nes_pal.h,v 1.1.1.1 2001/04/27 07:03:54 neil Exp $ +*/ + +#ifndef _NESPAL_H_ +#define _NESPAL_H_ + +extern rgb_t nes_palette[]; +extern rgb_t shady_palette[]; + +extern void pal_generate(void); + +/* TODO: these are temporary hacks */ +extern void pal_dechue(void); +extern void pal_inchue(void); +extern void pal_dectint(void); +extern void pal_inctint(void); + +#endif /* _NESPAL_H_ */ + +/* +** $Log: nes_pal.h,v $ +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.8 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.7 2000/07/21 04:20:35 matt +** added some nasty externs +** +** Revision 1.6 2000/07/10 13:49:32 matt +** renamed my palette and extern'ed it +** +** Revision 1.5 2000/07/05 17:14:34 neil +** Linux: Act Two, Scene One +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nesstate.h =================================================================== --- apps/plugins/nofrendo/nesstate.h (revision 0) +++ apps/plugins/nofrendo/nesstate.h (revision 0) @@ -0,0 +1,63 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nesstate.h +** +** state saving header +** $Id: nesstate.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _NESSTATE_H_ +#define _NESSTATE_H_ + +#include + +extern void state_setslot(int slot); +extern int state_load(); +extern int state_save(); + +#endif /* _NESSTATE_H_ */ + +/* +** $Log: nesstate.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.4 2000/10/23 17:50:47 matt +** adding fds support +** +** Revision 1.3 2000/07/25 02:21:23 matt +** changed routine names to reduce confusion with SNSS routines +** +** Revision 1.2 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.1 2000/06/29 03:08:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_rom.c =================================================================== --- apps/plugins/nofrendo/nes_rom.c (revision 0) +++ apps/plugins/nofrendo/nes_rom.c (revision 0) @@ -0,0 +1,590 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_rom.c +** +** NES ROM loading/saving related functions +** $Id: nes_rom.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +/* TODO: make this a generic ROM loading routine */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Max length for displayed filename */ +#define ROM_DISP_MAXLEN 20 + +#define ROM_FOURSCREEN 0x08 +#define ROM_TRAINER 0x04 +#define ROM_BATTERY 0x02 +#define ROM_MIRRORTYPE 0x01 +#define ROM_INES_MAGIC "NES\x1A" + + +typedef struct inesheader_s +{ + uint8 ines_magic[4] __PACKED__; + uint8 rom_banks __PACKED__; + uint8 vrom_banks __PACKED__; + uint8 rom_type __PACKED__; + uint8 mapper_hinybble __PACKED__; + uint8 reserved[8] __PACKED__; +} inesheader_t; + + +#define TRAINER_OFFSET 0x1000 +#define TRAINER_LENGTH 0x200 +#define VRAM_LENGTH 0x2000 + +#define ROM_BANK_LENGTH 0x4000 +#define VROM_BANK_LENGTH 0x2000 + +#define SRAM_BANK_LENGTH 0x0400 +#define VRAM_BANK_LENGTH 0x2000 + +/* Save battery-backed RAM */ +static void rom_savesram(rominfo_t *rominfo) +{ + int *fp; + char fn[PATH_MAX + 1]; + + ASSERT(rominfo); + + if (rominfo->flags & ROM_FLAG_BATTERY) + { + strncpy(fn, rominfo->filename, PATH_MAX); + osd_newextension(fn, ".sav"); + + fp = rb->open(fn, O_CREAT|O_TRUNC); + if (NULL != fp) + { + write(fp, rominfo->sram, SRAM_BANK_LENGTH); + rb->close(fp); + log_printf("Wrote battery RAM to %s.\n", fn); + } + } +} + +/* Load battery-backed RAM from disk */ +static void rom_loadsram(rominfo_t *rominfo) +{ + int *fp; + char fn[PATH_MAX + 1]; + + ASSERT(rominfo); + + if (rominfo->flags & ROM_FLAG_BATTERY) + { + strncpy(fn, rominfo->filename, PATH_MAX); + osd_newextension(fn, ".sav"); + + fp = rb->open(fn, O_RDONLY); + if (NULL != fp) + { + read(fp, rominfo->sram, SRAM_BANK_LENGTH); + rb->close(fp); + log_printf("Read battery RAM from %s.\n", fn); + } + } +} + +/* Allocate space for SRAM */ +static int rom_allocsram(rominfo_t *rominfo) +{ + /* Load up SRAM */ + rominfo->sram = malloc(SRAM_BANK_LENGTH * rominfo->sram_banks); + if (NULL == rominfo->sram) + { + gui_sendmsg(GUI_RED, "Could not allocate space for battery RAM"); + return -1; + } + + /* make damn sure SRAM is clear */ + memset(rominfo->sram, 0, SRAM_BANK_LENGTH * rominfo->sram_banks); + return 0; +} + +/* If there's a trainer, load it in at $7000 */ +static void rom_loadtrainer(int *fp, rominfo_t *rominfo) +{ + ASSERT(fp); + ASSERT(rominfo); + + if (rominfo->flags & ROM_FLAG_TRAINER) + { + read(fp, rominfo->sram + TRAINER_OFFSET, TRAINER_LENGTH); + log_printf("Read in trainer at $7000\n"); + } +} + +static int rom_loadrom(int *fp, rominfo_t *rominfo) +{ + ASSERT(fp); + ASSERT(rominfo); + + /* Allocate ROM space, and load it up! */ + rominfo->rom = malloc((rominfo->rom_banks * ROM_BANK_LENGTH)); + if (NULL == rominfo->rom) + { + gui_sendmsg(GUI_RED, "Could not allocate space for ROM image"); + return -1; + } + read(fp, rominfo->rom, ROM_BANK_LENGTH); + + /* If there's VROM, allocate and stuff it in */ + if (rominfo->vrom_banks) + { + rominfo->vrom = malloc((rominfo->vrom_banks * VROM_BANK_LENGTH)); + if (NULL == rominfo->vrom) + { + gui_sendmsg(GUI_RED, "Could not allocate space for VROM"); + return -1; + } + read(fp, rominfo->vrom, VROM_BANK_LENGTH); + } + else + { + rominfo->vram = malloc(VRAM_LENGTH); + if (NULL == rominfo->vram) + { + gui_sendmsg(GUI_RED, "Could not allocate space for VRAM"); + return -1; + } + memset(rominfo->vram, 0, VRAM_LENGTH); + } + + return 0; +} + +/* If we've got a VS. system game, load in the palette, as well */ +static void rom_checkforpal(rominfo_t *rominfo) +{ + int *fp; + rgb_t vs_pal[64]; + char filename[PATH_MAX + 1]; + int i; + + ASSERT(rominfo); + + strncpy(filename, rominfo->filename, PATH_MAX); + osd_newextension(filename, ".pal"); + + fp = rb->open(filename, O_RDONLY); + if (NULL == fp) + return; /* no palette found */ + + for (i = 0; i < 64; i++) + { + //vs_pal[i].r = fgetc(fp); + //vs_pal[i].g = fgetc(fp); + //vs_pal[i].b = fgetc(fp); + } + + rb->close(fp); + /* TODO: this should really be a *SYSTEM* flag */ + rominfo->flags |= ROM_FLAG_VERSUS; + /* TODO: bad, BAD idea, calling nes_getcontextptr... */ + ppu_setpal(nes_getcontextptr()->ppu, vs_pal); + log_printf("Game specific palette found -- assuming VS. UniSystem\n"); +} + +static int *rom_findrom(const char *filename, rominfo_t *rominfo) +{ + int *fp; + + ASSERT(rominfo); + + if (NULL == filename) + return NULL; + + /* Make a copy of the name so we can extend it */ + osd_fullname(rominfo->filename, filename); + + fp = rb->open(rominfo->filename, O_RDONLY); + if (NULL == fp) + { + /* Didn't find the file? Maybe the .NES extension was omitted */ + if (NULL == strrchr(rominfo->filename, '.')) + //strncat(rominfo->filename, ".nes", PATH_MAX - strlen(rominfo->filename)); + + /* this will either return NULL or a valid file pointer */ + fp = rb->open(rominfo->filename, O_RDONLY); + } + + return fp; +} + +/* Add ROM name to a list with dirty headers */ +static int rom_adddirty(char *filename) +{ +//#ifdef NOFRENDO_DEBUG +#ifdef STUPID +#define MAX_BUFFER_LENGTH 255 + char buffer[MAX_BUFFER_LENGTH + 1]; + int found = 0; + + int *fp = rb->open("dirtyrom.txt", O_RDONLY); + if (NULL == fp) + return -1; + + while (fgets(buffer, MAX_BUFFER_LENGTH, fp)) + { + if (0 == strncmp(filename, buffer, strlen(filename))) + { + found = 1; + break; + } + } + + if (0 == found) + { + /* close up the file, open it back up for writing */ + rb->close(fp); + fp = rb->open("dirtyrom.txt", O_APPEND); + fprintf(fp, "%s -- dirty header\n", filename); + } + + rb->close(fp); +#endif /* NOFRENDO_DEBUG */ + + return 0; +} + +/* return 0 if this *is* an iNES file */ +int rom_checkmagic(const char *filename) +{ + inesheader_t head; + rominfo_t rominfo; + int *fp; + + fp = rom_findrom(filename, &rominfo); + if (NULL == fp) + return -1; + + read(fp, &head, 1); + + rb->close(fp); + + if (0 == memcmp(head.ines_magic, ROM_INES_MAGIC, 4)) + /* not an iNES file */ + return 0; + + return -1; +} + +static int rom_getheader(int *fp, rominfo_t *rominfo) +{ +#define RESERVED_LENGTH 8 + inesheader_t head; + uint8 reserved[RESERVED_LENGTH]; + int header_dirty; + + ASSERT(fp); + ASSERT(rominfo); + + /* Read in the header */ + read(fp, &head, 1); + + if (memcmp(head.ines_magic, ROM_INES_MAGIC, 4)) + { + gui_sendmsg(GUI_RED, "%s is not a valid ROM image", rominfo->filename); + return -1; + } + + rominfo->rom_banks = head.rom_banks; + rominfo->vrom_banks = head.vrom_banks; + /* iNES assumptions */ + rominfo->sram_banks = 8; /* 1kB banks, so 8KB */ + rominfo->vram_banks = 1; /* 8kB banks, so 8KB */ + rominfo->mirror = (head.rom_type & ROM_MIRRORTYPE) ? MIRROR_VERT : MIRROR_HORIZ; + rominfo->flags = 0; + if (head.rom_type & ROM_BATTERY) + rominfo->flags |= ROM_FLAG_BATTERY; + if (head.rom_type & ROM_TRAINER) + rominfo->flags |= ROM_FLAG_TRAINER; + if (head.rom_type & ROM_FOURSCREEN) + rominfo->flags |= ROM_FLAG_FOURSCREEN; + /* TODO: fourscreen a mirroring type? */ + rominfo->mapper_number = head.rom_type >> 4; + + /* Do a compare - see if we've got a clean extended header */ + memset(reserved, 0, RESERVED_LENGTH); + if (0 == memcmp(head.reserved, reserved, RESERVED_LENGTH)) + { + /* We were clean */ + header_dirty = 0; + rominfo->mapper_number |= (head.mapper_hinybble & 0xF0); + } + else + { + header_dirty = 1; + + /* @!?#@! DiskDude. */ + if (('D' == head.mapper_hinybble) && (0 == memcmp(head.reserved, "iskDude!", 8))) + log_printf("`DiskDude!' found in ROM header, ignoring high mapper nybble\n"); + else + { + log_printf("ROM header dirty, possible problem\n"); + rominfo->mapper_number |= (head.mapper_hinybble & 0xF0); + } + + rom_adddirty(rominfo->filename); + } + + /* TODO: this is an ugly hack, but necessary, I guess */ + /* Check for VS unisystem mapper */ + if (99 == rominfo->mapper_number) + rominfo->flags |= ROM_FLAG_VERSUS; + + return 0; +} + +/* Build the info string for ROM display */ +char *rom_getinfo(rominfo_t *rominfo) +{ + static char info[PATH_MAX + 1]; + char romname[PATH_MAX + 1], temp[PATH_MAX + 1]; + + /* Look to see if we were given a path along with filename */ + /* TODO: strip extensions */ + if (strrchr(rominfo->filename, PATH_SEP)) + strncpy(romname, strrchr(rominfo->filename, PATH_SEP) + 1, PATH_MAX); + else + strncpy(romname, rominfo->filename, PATH_MAX); + + /* If our filename is too long, truncate our displayed filename */ + if (strlen(romname) > ROM_DISP_MAXLEN) + { + strncpy(info, romname, ROM_DISP_MAXLEN - 3); + strcpy(info + (ROM_DISP_MAXLEN - 3), "..."); + } + else + { + strcpy(info, romname); + } + +/* sprintf(temp, " [%d] %dk/%dk %c", rominfo->mapper_number, + rominfo->rom_banks * 16, rominfo->vrom_banks * 8, + (rominfo->mirror == MIRROR_VERT) ? 'V' : 'H'); +*/ + /* Stick it on there! // + strncat(info, temp, PATH_MAX - strlen(info)); + + if (rominfo->flags & ROM_FLAG_BATTERY) + strncat(info, "B", PATH_MAX - strlen(info)); + if (rominfo->flags & ROM_FLAG_TRAINER) + strncat(info, "T", PATH_MAX - strlen(info)); + if (rominfo->flags & ROM_FLAG_FOURSCREEN) + strncat(info, "4", PATH_MAX - strlen(info)); +*/ + return info; +} + +/* Load a ROM image into memory */ +rominfo_t *rom_load(const char *filename) +{ + int *fp; + rominfo_t *rominfo; + + rominfo = malloc(sizeof(rominfo_t)); + if (NULL == rominfo) + return NULL; + + memset(rominfo, 0, sizeof(rominfo_t)); + + fp = rom_findrom(filename, rominfo); + + if (NULL == fp) + gui_sendmsg(GUI_RED, "%s not found, will use default ROM", filename); + + /* Get the header and stick it into rominfo struct */ + if (NULL == fp) + intro_get_header(rominfo); + else if (rom_getheader(fp, rominfo)) + goto _fail; + + /* Make sure we really support the mapper */ + if (0 == mmc_peek(rominfo->mapper_number)) + { + gui_sendmsg(GUI_RED, "Mapper %d not yet implemented", rominfo->mapper_number); + goto _fail; + } + + /* iNES format doesn't tell us if we need SRAM, so + ** we have to always allocate it -- bleh! + ** UNIF, TAKE ME AWAY! AAAAAAAAAA!!! + */ + if (rom_allocsram(rominfo)) + goto _fail; + + if (NULL != fp) + rom_loadtrainer(fp, rominfo); + + if (NULL == fp) + { + if (intro_get_rom(rominfo)) + goto _fail; + } + else if (rom_loadrom(fp, rominfo)) + goto _fail; + + /* Close the file */ + if (NULL != fp) + rb->close(fp); + + rom_loadsram(rominfo); + + /* See if there's a palette we can load up */ + rom_checkforpal(rominfo); + + gui_sendmsg(GUI_GREEN, "ROM loaded: %s", rom_getinfo(rominfo)); + + return rominfo; + +_fail: + if (NULL != fp) + rb->close(fp); + rom_free(&rominfo); + return NULL; +} + +/* Free a ROM */ +void rom_free(rominfo_t **rominfo) +{ + if (NULL == *rominfo) + { + gui_sendmsg(GUI_GREEN, "ROM not loaded"); + return; + } + + /* Restore palette if we loaded in a VS jobber */ + if ((*rominfo)->flags & ROM_FLAG_VERSUS) + { + /* TODO: bad idea calling nes_getcontextptr... */ + ppu_setdefaultpal(nes_getcontextptr()->ppu); + log_printf("Default NES palette restored\n"); + } + + rom_savesram(*rominfo); + + if ((*rominfo)->sram) + free((*rominfo)->sram); + if ((*rominfo)->rom) + free((*rominfo)->rom); + if ((*rominfo)->vrom) + free((*rominfo)->vrom); + if ((*rominfo)->vram) + free((*rominfo)->vram); + + free(*rominfo); + + gui_sendmsg(GUI_GREEN, "ROM freed"); +} + +/* +** $Log: nes_rom.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/11/21 13:28:40 matt +** take care to zero allocated mem +** +** Revision 1.7 2000/11/09 14:07:28 matt +** state load fixed, state save mostly fixed +** +** Revision 1.6 2000/10/28 14:24:54 matt +** where did I put that underscore? +** +** Revision 1.5 2000/10/27 12:56:35 matt +** api change for ppu palette functions +** +** Revision 1.4 2000/10/26 22:51:44 matt +** correct NULL filename handling +** +** Revision 1.3 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.19 2000/10/21 14:35:58 matt +** typo +** +** Revision 1.18 2000/10/17 03:22:37 matt +** cleaning up rom module +** +** Revision 1.17 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.16 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.15 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.14 2000/07/30 04:31:26 matt +** automagic loading of the nofrendo intro +** +** Revision 1.13 2000/07/25 02:20:58 matt +** cleanups +** +** Revision 1.12 2000/07/20 01:53:27 matt +** snprintf() ain't no standard function, eh? +** +** Revision 1.11 2000/07/19 16:06:54 neil +** little error fixed (tempinfo vs rominfo->info) +** +** Revision 1.10 2000/07/19 15:59:39 neil +** PATH_MAX, strncpy, snprintf, and strncat are our friends +** +** Revision 1.9 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.8 2000/07/06 16:47:50 matt +** new ppu palette setting calls +** +** Revision 1.7 2000/07/05 23:21:54 neil +** fclose(fp) should not be done if fp == NULL +** +** Revision 1.6 2000/07/04 04:45:14 matt +** changed include +** +** Revision 1.5 2000/06/26 04:56:10 matt +** minor cleanup +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nofrendo.make =================================================================== --- apps/plugins/nofrendo/nofrendo.make (revision 0) +++ apps/plugins/nofrendo/nofrendo.make (revision 0) @@ -0,0 +1,39 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id: nofrendo.make 19218 2008-11-25 19:54:23Z zagor $ +# + +NOFRENDOSRCDIR := $(APPSDIR)/plugins/nofrendo +NOFRENDOBUILDDIR := $(BUILDDIR)/apps/plugins/nofrendo + +ROCKS += $(NOFRENDOBUILDDIR)/nofrendo.rock + +NOFRENDO_SRC := $(call preprocess, $(NOFRENDOSRCDIR)/SOURCES) +NOFRENDO_OBJ := $(call c2obj, $(NOFRENDO_SRC)) + +OTHER_SRC += $(NOFRENDO_SRC) + +NOFRENDOCFLAGS += $(PLUGINFLAGS) -I$(NOFRENDOSRCDIR) -O3 -w + +$(NOFRENDOBUILDDIR)/nofrendo.rock: $(NOFRENDO_OBJ) $(MPEG_OBJ) $(CODECDIR)/libtlsf.a + +$(NOFRENDOBUILDDIR)/%.o: $(NOFRENDOSRCDIR)/%.c + $(SILENT)mkdir -p $(dir $@) + $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(NOFRENDOCFLAGS) -c $< -o $@ + +$(NOFRENDOBUILDDIR)/infones.rock: $(NOFRENDO_OBJ) + $(call PRINTS,LD $(@F)) + $(SILENT)$(CC) $(PLUGINFLAGS) -o $*.elf \ + $(filter %.o, $^) \ + $(filter %.a, $^) \ + -lgcc $(PLUGINLDFLAGS) -Wl,-Map,$(basename $@).map + +ifdef SIMVER + $(SILENT)cp $*.elf $@ +else + $(SILENT)$(OC) -O binary $*.elf $@ +endif Index: apps/plugins/nofrendo/nes_rom.h =================================================================== --- apps/plugins/nofrendo/nes_rom.h (revision 0) +++ apps/plugins/nofrendo/nes_rom.h (revision 0) @@ -0,0 +1,109 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_rom.h +** +** NES ROM loading/saving related defines / prototypes +** $Id: nes_rom.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _NES_ROM_H_ +#define _NES_ROM_H_ + +#include + +typedef enum +{ + MIRROR_HORIZ = 0, + MIRROR_VERT = 1 +} mirror_t; + +#define ROM_FLAG_BATTERY 0x01 +#define ROM_FLAG_TRAINER 0x02 +#define ROM_FLAG_FOURSCREEN 0x04 +#define ROM_FLAG_VERSUS 0x08 + +typedef struct rominfo_s +{ + /* pointers to ROM and VROM */ + uint8 *rom, *vrom; + + /* pointers to SRAM and VRAM */ + uint8 *sram, *vram; + + /* number of banks */ + int rom_banks, vrom_banks; + int sram_banks, vram_banks; + + int mapper_number; + mirror_t mirror; + + uint8 flags; + + char filename[PATH_MAX + 1]; +} rominfo_t; + + +extern int rom_checkmagic(const char *filename); +extern rominfo_t *rom_load(const char *filename); +extern void rom_free(rominfo_t **rominfo); +extern char *rom_getinfo(rominfo_t *rominfo); + + +#endif /* _NES_ROM_H_ */ + +/* +** $Log: nes_rom.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.11 2000/10/22 15:01:29 matt +** irrelevant mirroring modes removed +** +** Revision 1.10 2000/10/17 03:22:38 matt +** cleaning up rom module +** +** Revision 1.9 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.8 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.7 2000/07/25 02:20:58 matt +** cleanups +** +** Revision 1.6 2000/07/19 15:59:39 neil +** PATH_MAX, strncpy, snprintf, and strncat are our friends +** +** Revision 1.5 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/bitmap.c =================================================================== --- apps/plugins/nofrendo/bitmap.c (revision 0) +++ apps/plugins/nofrendo/bitmap.c (revision 0) @@ -0,0 +1,154 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** bitmap.c +** +** Bitmap object manipulation routines +** $Id: bitmap.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +void bmp_clear(const bitmap_t *bitmap, uint8 color) +{ + memset(bitmap->data, color, bitmap->pitch * bitmap->height); +} + +static bitmap_t *_make_bitmap(uint8 *data_addr, int hw, int width, + int height, int pitch, int overdraw) +{ + bitmap_t *bitmap; + int i; + + /* quick safety check */ + if (NULL == data_addr) + return NULL; + + /* Make sure to add in space for line pointers */ + bitmap = malloc(sizeof(bitmap_t) + (sizeof(uint8 *) * height)); + if (NULL == bitmap) + return NULL; + + bitmap->hardware = hw; + bitmap->height = height; + bitmap->width = width; + bitmap->data = data_addr; + bitmap->pitch = pitch + (overdraw * 2); + + /* Set up line pointers */ + /* we want to make some 32-bit aligned adjustment + ** if we haven't been given a hardware bitmap + */ + if (0 == bitmap->hardware) + { + bitmap->pitch = (bitmap->pitch + 3) & ~3; + bitmap->line[0] = (uint8 *) (((uint32) bitmap->data + overdraw + 3) & ~3); + } + else + { + bitmap->line[0] = bitmap->data + overdraw; + } + + for (i = 1; i < height; i++) + bitmap->line[i] = bitmap->line[i - 1] + bitmap->pitch; + + return bitmap; +} + +/* Allocate and initialize a bitmap structure */ +bitmap_t *bmp_create(int width, int height, int overdraw) +{ + uint8 *addr; + int pitch; + + pitch = width + (overdraw * 2); /* left and right */ + + addr = malloc((pitch * height) + 3); /* add max 32-bit aligned adjustment */ + if (NULL == addr) + return NULL; + + return _make_bitmap(addr, 0, width, height, width, overdraw); +} + +/* allocate and initialize a hardware bitmap */ +bitmap_t *bmp_createhw(uint8 *addr, int width, int height, int pitch) +{ + return _make_bitmap(addr, 1, width, height, pitch, 0); /* zero overdraw */ +} + +/* Deallocate space for a bitmap structure */ +void bmp_destroy(bitmap_t **bitmap) +{ + if (*bitmap) + { + if ((*bitmap)->data && 0 == (*bitmap)->hardware) + free((*bitmap)->data); + free(*bitmap); + *bitmap = NULL; + } +} + +/* +** $Log: bitmap.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.16 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.15 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.14 2000/09/18 02:06:48 matt +** -pedantic is your friend +** +** Revision 1.13 2000/08/13 13:16:30 matt +** bugfix for alignment adjustment +** +** Revision 1.12 2000/07/24 04:31:43 matt +** pitch/data area on non-hw bitmaps get padded to 32-bit boundaries +** +** Revision 1.11 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.10 2000/07/09 14:43:01 matt +** pitch is now configurable for bmp_createhw() +** +** Revision 1.9 2000/07/06 17:55:57 matt +** two big bugs fixed +** +** Revision 1.8 2000/07/06 17:38:11 matt +** replaced missing string.h include +** +** Revision 1.7 2000/07/06 16:46:57 matt +** added bmp_clear() routine +** +** Revision 1.6 2000/06/26 04:56:24 matt +** minor cleanup +** +** Revision 1.5 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nofconfig.h =================================================================== --- apps/plugins/nofrendo/nofconfig.h (revision 0) +++ apps/plugins/nofrendo/nofconfig.h (revision 0) @@ -0,0 +1,79 @@ +/* Nofrendo Configuration API +** +** This file is in the public domain. +** +** $Id: nofconfig.h,v 1.1 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "codecs/lib/tlsf/src/tlsf.h" + +#ifndef CONFIG_FILE +#define CONFIG_FILE "nofrendo.cfg" +#endif + +typedef struct config_s +{ + /* open loads from the disk the saved configuration. + ** + ** open must be the first config function called. + ** + ** open returns true on success, false otherwise. + */ + int (*open)(void); + + /* close saves the current configuration to disk. + ** + ** close must be the last config function called. + */ + void (*close)(void); + + /* read_int loads an integer from the configuration into "value" + ** + ** If the specified "key" does not exist, the "def"ault is returned + */ + int (*read_int)(const char *group, const char *key, int def); + + /* read_string copies a string from the configuration into "value" + ** + ** If the specified "key" does not exist, the "def"ault is returned + */ + const char *(*read_string)(const char *group, const char *key, const char *def); + + void (*write_int)(const char *group, const char *key, int value); + void (*write_string)(const char *group, const char *key, const char *value); + char *filename; +} config_t; + +extern config_t config; + +#endif /* !_CONFIG_H_ */ + +/* +** $Log: nofconfig.h,v $ +** Revision 1.1 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.5 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.4 2000/07/19 15:58:55 neil +** config file now configurable (ha) +** +** Revision 1.3 2000/07/11 14:59:27 matt +** minor cosmetics.. =) +** +** Revision 1.2 2000/07/11 13:35:38 bsittler +** Changed the config API, implemented config file "nofrendo.cfg". The +** GGI drivers use the group [GGI]. Visual= and Mode= keys are understood. +** +** Revision 1.1 2000/07/11 07:46:11 neil +** Initial commit +** +** +*/ Index: apps/plugins/nofrendo/event.c =================================================================== --- apps/plugins/nofrendo/event.c (revision 0) +++ apps/plugins/nofrendo/event.c (revision 0) @@ -0,0 +1,637 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** event.c +** +** OS-independent event handling +** $Id: event.c,v 1.3 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include + +/* TODO: put system specific stuff in their own files... */ +#include +#include +#include +#include + +/* pointer to our current system's event handler table */ +static event_t *system_events = NULL; + +/* standard keyboard input */ +static nesinput_t kb_input = { INP_JOYPAD0, 0 }; +static nesinput_t kb_alt_input = { INP_JOYPAD1, 0 }; + +static void func_event_quit(int code) +{ + UNUSED(code); + main_quit(); +} + +static void func_event_insert(int code) +{ + UNUSED(code); + /* TODO: after the GUI */ +} + +static void func_event_eject(int code) +{ + if (INP_STATE_MAKE == code) + main_eject(); +} + +static void func_event_togglepause(int code) +{ + if (INP_STATE_MAKE == code) + nes_togglepause(); +} + +static void func_event_soft_reset(int code) +{ + if (INP_STATE_MAKE == code) + nes_reset(SOFT_RESET); +} + +static void func_event_hard_reset(int code) +{ + if (INP_STATE_MAKE == code) + nes_reset(HARD_RESET); +} + +static void func_event_snapshot(int code) +{ + if (INP_STATE_MAKE == code) + gui_savesnap(); +} + +static void func_event_toggle_frameskip(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglefs(); +} + +static void func_event_state_save(int code) +{ + if (INP_STATE_MAKE == code) + state_save(); +} + +static void func_event_state_load(int code) +{ + if (INP_STATE_MAKE == code) + state_load(); +} + +static void func_event_state_slot_0(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(0); +} + +static void func_event_state_slot_1(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(1); +} + +static void func_event_state_slot_2(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(2); +} + +static void func_event_state_slot_3(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(3); +} + +static void func_event_state_slot_4(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(4); +} + +static void func_event_state_slot_5(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(5); +} + +static void func_event_state_slot_6(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(6); +} + +static void func_event_state_slot_7(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(7); +} + +static void func_event_state_slot_8(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(8); +} + +static void func_event_state_slot_9(int code) +{ + if (INP_STATE_MAKE == code) + state_setslot(9); +} + +static void func_event_gui_toggle_oam(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggleoam(); +} + +static void func_event_gui_toggle_wave(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglewave(); +} + +static void func_event_gui_toggle_pattern(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglepattern(); +} + +static void func_event_gui_pattern_color_up(int code) +{ + if (INP_STATE_MAKE == code) + gui_incpatterncol(); +} + +static void func_event_gui_pattern_color_down(int code) +{ + if (INP_STATE_MAKE == code) + gui_decpatterncol(); +} + +static void func_event_gui_toggle_fps(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglefps(); +} + +static void func_event_gui_display_info(int code) +{ + if (INP_STATE_MAKE == code) + gui_displayinfo(); +} + +static void func_event_gui_toggle(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglegui(); +} + +static void func_event_toggle_channel_0(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(0); +} + +static void func_event_toggle_channel_1(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(1); +} + +static void func_event_toggle_channel_2(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(2); +} + +static void func_event_toggle_channel_3(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(3); +} + +static void func_event_toggle_channel_4(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(4); +} + +static void func_event_toggle_channel_5(int code) +{ + if (INP_STATE_MAKE == code) + gui_toggle_chan(5); +} + +static void func_event_set_filter_0(int code) +{ + if (INP_STATE_MAKE == code) + gui_setfilter(0); +} + +static void func_event_set_filter_1(int code) +{ + if (INP_STATE_MAKE == code) + gui_setfilter(1); +} + +static void func_event_set_filter_2(int code) +{ + if (INP_STATE_MAKE == code) + gui_setfilter(2); +} + +static void func_event_toggle_sprites(int code) +{ + if (INP_STATE_MAKE == code) + gui_togglesprites(); +} + +static void func_event_palette_hue_up(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + { + pal_inchue(); + ppu_setdefaultpal(nes_getcontextptr()->ppu); + } +} + +static void func_event_palette_hue_down(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + { + pal_dechue(); + ppu_setdefaultpal(nes_getcontextptr()->ppu); + } +} + +static void func_event_palette_tint_up(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + { + pal_inctint(); + ppu_setdefaultpal(nes_getcontextptr()->ppu); + } +} + +static void func_event_palette_tint_down(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + { + pal_dectint(); + ppu_setdefaultpal(nes_getcontextptr()->ppu); + } +} + +static void func_event_palette_set_default(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + ppu_setdefaultpal(nes_getcontextptr()->ppu); +} + +static void func_event_palette_set_shady(int code) +{ + /* make sure we don't have a VS game */ + if (nes_getcontextptr()->rominfo->flags & ROM_FLAG_VERSUS) + return; + + if (INP_STATE_MAKE == code) + ppu_setpal(nes_getcontextptr()->ppu, shady_palette); +} + +static void func_event_joypad1_a(int code) +{ + input_event(&kb_input, code, INP_PAD_A); +} + +static void func_event_joypad1_b(int code) +{ + input_event(&kb_input, code, INP_PAD_B); +} + +static void func_event_joypad1_start(int code) +{ + input_event(&kb_input, code, INP_PAD_START); +} + +static void func_event_joypad1_select(int code) +{ + input_event(&kb_input, code, INP_PAD_SELECT); +} + +static void func_event_joypad1_up(int code) +{ + input_event(&kb_input, code, INP_PAD_UP); +} + +static void func_event_joypad1_down(int code) +{ + input_event(&kb_input, code, INP_PAD_DOWN); +} + +static void func_event_joypad1_left(int code) +{ + input_event(&kb_input, code, INP_PAD_LEFT); +} + +static void func_event_joypad1_right(int code) +{ + input_event(&kb_input, code, INP_PAD_RIGHT); +} + +static void func_event_joypad2_a(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_A); +} + +static void func_event_joypad2_b(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_B); +} + +static void func_event_joypad2_start(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_START); +} + +static void func_event_joypad2_select(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_SELECT); +} + +static void func_event_joypad2_up(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_UP); +} + +static void func_event_joypad2_down(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_DOWN); +} + +static void func_event_joypad2_left(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_LEFT); +} + +static void func_event_joypad2_right(int code) +{ + input_event(&kb_alt_input, code, INP_PAD_RIGHT); +} + +static void func_event_songup(int code) +{ +} + +static void func_event_songdown(int code) +{ +} + +static void func_event_startsong(int code) +{ +} + +/* NES events */ +static event_t nes_events[] = +{ + NULL, /* 0 */ + func_event_quit, + func_event_insert, + func_event_eject, + func_event_togglepause, + func_event_soft_reset, + func_event_hard_reset, + func_event_snapshot, + func_event_toggle_frameskip, + /* saves */ + func_event_state_save, + func_event_state_load, /* 10 */ + func_event_state_slot_0, + func_event_state_slot_1, + func_event_state_slot_2, + func_event_state_slot_3, + func_event_state_slot_4, + func_event_state_slot_5, + func_event_state_slot_6, + func_event_state_slot_7, + func_event_state_slot_8, + func_event_state_slot_9, /* 20 */ + /* GUI */ + func_event_gui_toggle_oam, + func_event_gui_toggle_wave, + func_event_gui_toggle_pattern, + func_event_gui_pattern_color_up, + func_event_gui_pattern_color_down, + func_event_gui_toggle_fps, + func_event_gui_display_info, + func_event_gui_toggle, + /* sound */ + func_event_toggle_channel_0, + func_event_toggle_channel_1, /* 30 */ + func_event_toggle_channel_2, + func_event_toggle_channel_3, + func_event_toggle_channel_4, + func_event_toggle_channel_5, + func_event_set_filter_0, + func_event_set_filter_1, + func_event_set_filter_2, + /* picture */ + func_event_toggle_sprites, + func_event_palette_hue_up, + func_event_palette_hue_down, + func_event_palette_tint_up, /* 40 */ + func_event_palette_tint_down, + func_event_palette_set_default, + func_event_palette_set_shady, + /* joypad 1 */ + func_event_joypad1_a, + func_event_joypad1_b, + func_event_joypad1_start, + func_event_joypad1_select, + func_event_joypad1_up, + func_event_joypad1_down, + func_event_joypad1_left, /* 50 */ + func_event_joypad1_right, + /* joypad 2 */ + func_event_joypad2_a, + func_event_joypad2_b, + func_event_joypad2_start, + func_event_joypad2_select, + func_event_joypad2_up, + func_event_joypad2_down, + func_event_joypad2_left, + func_event_joypad2_right, + /* NSF control */ + NULL, /* 60 */ + NULL, + NULL, + /* OS-specific */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 70 */ + NULL, + /* last */ + NULL +}; + + +static event_t *event_system_table[NUM_SUPPORTED_SYSTEMS] = +{ + NULL, /* unknown */ + NULL, /* autodetect */ + nes_events, /* nes */ +}; + +void event_init(void) +{ + input_register(&kb_input); + input_register(&kb_alt_input); +} + +/* set up the event system for a certain console/system type */ +void event_set_system(system_t type) +{ + ASSERT(type < NUM_SUPPORTED_SYSTEMS); + + system_events = event_system_table[type]; +} + +void event_set(int index, event_t handler) +{ + /* now, event_set is used to set osd-specific events. We should assume + ** (for now, at least) that these events should be used across all + ** emulated systems, so let's loop through all system event handler + ** tables and add this event... + */ + int i; + + for (i = 0; i < NUM_SUPPORTED_SYSTEMS; i++) + { + if(event_system_table[i]) + { + event_system_table[i][index] = handler; + } + } +} + +event_t event_get(int index) +{ + return system_events[index]; +} + + +/* +** $Log: event.c,v $ +** Revision 1.3 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.2 2001/04/27 11:10:08 neil +** compile +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.18 2000/11/25 20:26:05 matt +** removed fds "system" +** +** Revision 1.17 2000/11/09 14:05:42 matt +** state load fixed, state save mostly fixed +** +** Revision 1.16 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.15 2000/11/01 17:33:26 neil +** little crash bugs fixed +** +** Revision 1.14 2000/11/01 14:15:35 matt +** multi-system event system, or whatever +** +** Revision 1.13 2000/10/27 12:59:48 matt +** api change for ppu palette functions +** +** Revision 1.12 2000/10/26 22:48:05 matt +** no need for extern +** +** Revision 1.11 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.10 2000/10/23 17:50:46 matt +** adding fds support +** +** Revision 1.9 2000/10/23 15:52:04 matt +** better system handling +** +** Revision 1.8 2000/10/22 15:01:51 matt +** prevented palette changing in VS unisystem games +** +** Revision 1.7 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.6 2000/08/16 02:58:34 matt +** random cleanups +** +** Revision 1.5 2000/07/27 01:15:33 matt +** name changes +** +** Revision 1.4 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.3 2000/07/23 15:17:19 matt +** non-osd calls moved from osd.c to gui.c +** +** Revision 1.2 2000/07/21 12:07:40 neil +** added room in event_array for all osd events +** +** Revision 1.1 2000/07/21 04:26:38 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/bitmap.h =================================================================== --- apps/plugins/nofrendo/bitmap.h (revision 0) +++ apps/plugins/nofrendo/bitmap.h (revision 0) @@ -0,0 +1,93 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** bitmap.h +** +** Bitmap object defines / prototypes +** $Id: bitmap.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _BITMAP_H_ +#define _BITMAP_H_ + +#include + +/* a bitmap rectangle */ +typedef struct rect_s +{ + int16 x, y; + uint16 w, h; +} rect_t; + +typedef struct rgb_s +{ + int r, g, b; +} rgb_t; + +typedef struct bitmap_s +{ + int width, height, pitch; + int hardware; /* is data a hardware region? */ + uint8 *data; /* protected */ + uint8 *line[ZERO_LENGTH]; /* will hold line pointers */ +} bitmap_t; + +extern void bmp_clear(const bitmap_t *bitmap, uint8 color); +extern bitmap_t *bmp_create(int width, int height, int overdraw); +extern bitmap_t *bmp_createhw(uint8 *addr, int width, int height, int pitch); +extern void bmp_destroy(bitmap_t **bitmap); + +#endif /* _BITMAP_H_ */ + +/* +** $Log: bitmap.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.12 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.11 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.10 2000/09/18 02:06:48 matt +** -pedantic is your friend +** +** Revision 1.9 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.8 2000/07/24 04:31:43 matt +** pitch/data area on non-hw bitmaps get padded to 32-bit boundaries +** +** Revision 1.7 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.6 2000/07/09 14:43:01 matt +** pitch is now configurable for bmp_createhw() +** +** Revision 1.5 2000/07/06 16:46:57 matt +** added bmp_clear() routine +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/gui.c =================================================================== --- apps/plugins/nofrendo/gui.c (revision 0) +++ apps/plugins/nofrendo/gui.c (revision 0) @@ -0,0 +1,682 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** gui.c +** +** GUI routines +** $Id: gui.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* 8-bit GUI color table */ +rgb_t gui_pal[GUI_TOTALCOLORS] = +{ + { 0x00, 0x00, 0x00 }, /* black */ + { 0x3F, 0x3F, 0x3F }, /* dark gray */ + { 0x7F, 0x7F, 0x7F }, /* gray */ + { 0xBF, 0xBF, 0xBF }, /* light gray */ + { 0xFF, 0xFF, 0xFF }, /* white */ + { 0xFF, 0x00, 0x00 }, /* red */ + { 0x00, 0xFF, 0x00 }, /* green */ + { 0x00, 0x00, 0xFF }, /* blue */ + { 0xFF, 0xFF, 0x00 }, /* yellow */ + { 0xFF, 0xAF, 0x00 }, /* orange */ + { 0xFF, 0x00, 0xFF }, /* purple */ + { 0x3F, 0x7F, 0x7F }, /* teal */ + { 0x00, 0x2A, 0x00 }, /* dk. green */ + { 0x00, 0x00, 0x3F } /* dark blue */ +}; + +/**************************************************************/ +#include +#include +static int option_drawsprites = 1; + +/* save a PCX snapshot */ +void gui_savesnap(void) +{ + char filename[PATH_MAX]; + nes_t *nes = nes_getcontextptr(); + +/* if (osd_makesnapname(filename, PATH_MAX) < 0) + return; +*/ + if (pcx_write(filename, nes->vidbuf, nes->ppu->curpal)) + return; + + gui_sendmsg(GUI_GREEN, "Screen saved to %s", filename); +} + +/* Show/hide sprites (hiding sprites useful for making maps) */ +void gui_togglesprites(void) +{ + option_drawsprites ^= 1; + ppu_displaysprites(option_drawsprites); + gui_sendmsg(GUI_GREEN, "Sprites %s", option_drawsprites ? "displayed" : "hidden"); +} + +/* Set the frameskip policy */ +void gui_togglefs(void) +{ + nes_t *machine = nes_getcontextptr(); + + machine->autoframeskip ^= 1; + if (machine->autoframeskip) + gui_sendmsg(GUI_YELLOW, "automatic frameskip"); + else + gui_sendmsg(GUI_YELLOW, "unthrottled emulation"); +} + +/* display rom information */ +void gui_displayinfo() +{ + gui_sendmsg(GUI_ORANGE, (char *) rom_getinfo(nes_getcontextptr()->rominfo)); +} + +void gui_toggle_chan(int chan) +{ +#define FILL_CHAR 0x7C /* ASCII 124 '|' */ +#define BLANK_CHAR 0x7F /* ASCII 127 [delta] */ + static int chan_enabled[6] = { 1, 1, 1, 1, 1, 1 }; + + chan_enabled[chan] ^= 1; + apu_setchan(chan, chan_enabled[chan]); + + gui_sendmsg(GUI_ORANGE, "%ca %cb %cc %cd %ce %cext", + chan_enabled[0] ? FILL_CHAR : BLANK_CHAR, + chan_enabled[1] ? FILL_CHAR : BLANK_CHAR, + chan_enabled[2] ? FILL_CHAR : BLANK_CHAR, + chan_enabled[3] ? FILL_CHAR : BLANK_CHAR, + chan_enabled[4] ? FILL_CHAR : BLANK_CHAR, + chan_enabled[5] ? FILL_CHAR : BLANK_CHAR); +} + +void gui_setfilter(int filter_type) +{ + char *types[3] = { "no", "lowpass", "weighted" }; + static int last_filter = 2; + + if (last_filter == filter_type || filter_type < 0 || filter_type > 2) + return; + + apu_setfilter(filter_type); + gui_sendmsg(GUI_ORANGE, "%s filter", types[filter_type]); + last_filter = filter_type; +} +/**************************************************************/ + + +enum +{ + GUI_WAVENONE, + GUI_WAVELINE, + GUI_WAVESOLID, + GUI_NUMWAVESTYLES +}; +/* +enum +{ + BUTTON_UP, + BUTTON_DOWN +}; +*/ + +/* TODO: roll options into a structure */ +static message_t msg; +static int option_showfps = 0; +static int option_showgui = 0; +static int option_wavetype = GUI_WAVENONE; +static int option_showpattern = 0; +static int option_showoam = 0; +static int pattern_col = 0; + +/* timimg variables */ +static int gui_fpsupdate = 0; +static int gui_ticks = 0; +static int gui_fps = 0; +static int gui_refresh = 60; /* default to 60Hz */ + +static int mouse_x, mouse_y, mouse_button; + +static bitmap_t *gui_surface; + + +/* Put a pixel on our bitmap- just for GUI use */ +INLINE void gui_putpixel(int x_pos, int y_pos, uint8 color) +{ + gui_surface->line[y_pos][x_pos] = color; +} + +/* Line drawing */ +static void gui_hline(int x_pos, int y_pos, int length, uint8 color) +{ + while (length--) + gui_putpixel(x_pos++, y_pos, color); +} + +static void gui_vline(int x_pos, int y_pos, int height, uint8 color) +{ + while (height--) + gui_putpixel(x_pos, y_pos++, color); +} + +/* Rectangles */ +static void gui_rect(int x_pos, int y_pos, int width, int height, uint8 color) +{ + gui_hline(x_pos, y_pos, width, color); + gui_hline(x_pos, y_pos + height - 1, width, color); + gui_vline(x_pos, y_pos + 1, height - 2, color); + gui_vline(x_pos + width - 1, y_pos + 1, height - 2, color); +} + +static void gui_rectfill(int x_pos, int y_pos, int width, int height, uint8 color) +{ + while (height--) + gui_hline(x_pos, y_pos++, width, color); +} + +/* Draw the outline of a button */ +static void gui_buttonrect(int x_pos, int y_pos, int width, int height, int down) +{ + uint8 color1, color2; + + if (down) + { + color1 = GUI_GRAY; + color2 = GUI_WHITE; + } + else + { + color1 = GUI_WHITE; + color2 = GUI_GRAY; + } + + gui_hline(x_pos, y_pos, width - 1, color1); + gui_vline(x_pos, y_pos + 1, height - 2, color1); + gui_hline(x_pos, y_pos + height - 1, width, color2); + gui_vline(x_pos + width - 1, y_pos, height - 1, color2); +} + +/* Text blitting */ +INLINE void gui_charline(char ch, int x_pos, int y_pos, uint8 color) +{ + int count = 8; + while (count--) + { + if (ch & (1 << count)) + gui_putpixel(x_pos, y_pos, color); + x_pos++; + } +} + +static void gui_putchar(uint8 *dat, int height, int x_pos, int y_pos, uint8 color) +{ + while (height--) + gui_charline(*dat++, x_pos, y_pos++, color); +} + +/* Return length of text in pixels */ +static int gui_textlen(char *str, font_t *font) +{ + int pixels = 0; + int num_chars = strlen(str); + + while (num_chars--) + pixels += font->character[(*str++ - 32)].spacing; + + return pixels; +} + +/* Simple textout() type function */ +static int gui_textout(char *str, int x_pos, int y_pos, font_t *font, uint8 color) +{ + int x_new; + int num_chars = strlen(str); + int code; + + x_new = x_pos; + + while (num_chars--) + { + /* Turn ASCII code into letter */ + code = *str++; + if (code > 0x7F) + code = 0x7F; + code -= 32; /* normalize */ + gui_putchar(font->character[code].lines, font->height, x_new, y_pos, color); + x_new += font->character[code].spacing; + } + + /* Return the length in pixels */ + return (x_new - x_pos); +} + +/* Draw bar-/button-type text */ +static int gui_textbar(char *str, int x_pos, int y_pos, font_t *font, + uint8 color, uint8 bgcolor, int buttonstate) +{ + int width = gui_textlen(str, &small); + + /* Fill the 'button' */ + gui_buttonrect(x_pos, y_pos, width + 3, font->height + 3, buttonstate); + gui_rectfill(x_pos + 1, y_pos + 1, width + 1, font->height + 1, bgcolor); + + /* Print the text */ + return gui_textout(str, x_pos + 2, y_pos + 2, font, color); +} + +/* Draw the mouse pointer */ +static void gui_drawmouse(void) +{ + int ythresh, xthresh; + int i, j, color; + + ythresh = gui_surface->height - mouse_y - 1; + for (j = 0; j < CURSOR_HEIGHT; j++) + { + if (ythresh < 0) + continue; + + xthresh = gui_surface->width - mouse_x - 1; + for (i = 0; i < CURSOR_WIDTH; i++) + { + if (xthresh < 0) + continue; + + color = cursor[(j * CURSOR_WIDTH) + i]; + + if (color) + gui_putpixel(mouse_x + i, mouse_y + j, cursor_color[color]); + xthresh--; + } + ythresh--; + } +} + +void gui_tick(int ticks) +{ + + static int fps_counter = 0; + + gui_ticks += ticks; + fps_counter += ticks; + + if (fps_counter >= gui_refresh) + { + fps_counter -= gui_refresh; + gui_fpsupdate = 1; + } +} + +/* updated in sync with the timer interrupt */ +static void gui_tickdec(void) +{ +#ifdef NOFRENDO_DEBUG + static int hertz_ticks = 0; +#endif + int ticks = gui_ticks; + + if (0 == ticks) + return; + + gui_ticks = 0; + +#ifdef NOFRENDO_DEBUG + /* Check for corrupt memory block every 10 seconds */ + hertz_ticks += ticks; + if (hertz_ticks >= (10 * gui_refresh)) + { + hertz_ticks -= (10 * gui_refresh); + mem_checkblocks(); + } +#endif + + /* TODO: bleh */ + if (msg.ttl > 0) + { + msg.ttl -= ticks; + if (msg.ttl < 0) + msg.ttl = 0; + } +} + +/* Update the FPS display */ +static void gui_updatefps(void) +{ + static char fpsbuf[20]; + + /* Check to see if we need to do an sprintf or not */ + if (1 == gui_fpsupdate) + { + //sprintf(fpsbuf, "%4d FPS /%4d%%", gui_fps, (gui_fps * 100) / gui_refresh); + gui_fps = 0; + gui_fpsupdate = 0; + } + + gui_textout(fpsbuf, gui_surface->width - 1 - 90, 1, &small, GUI_GREEN); +} + +/* Turn FPS on/off */ +void gui_togglefps(void) +{ + option_showfps ^= 1; +} + +/* Turn GUI on/off */ +void gui_togglegui(void) +{ + option_showgui ^= 1; +} + +void gui_togglewave(void) +{ + option_wavetype = (option_wavetype + 1) % GUI_NUMWAVESTYLES; +} + +void gui_toggleoam(void) +{ + option_showoam ^= 1; +} + +/* TODO: hack! */ +void gui_togglepattern(void) +{ + option_showpattern ^= 1; +} + +/* TODO: hack! */ +void gui_decpatterncol(void) +{ + if (pattern_col && option_showpattern) + pattern_col--; +} + +/* TODO: hack! */ +void gui_incpatterncol(void) +{ + if ((pattern_col < 7) && option_showpattern) + pattern_col++; +} + +/* Downward-scrolling message display */ +static void gui_updatemsg(void) +{ + if (msg.ttl) + gui_textbar(msg.text, 2, gui_surface->height - 10, &small, msg.color, GUI_DKGRAY, BUTTON_UP); +} + +/* Little thing to display the waveform */ +static void gui_updatewave(int wave_type) +{ +#define WAVEDISP_WIDTH 128 + int loop, xofs, yofs; + int difference, offset; + float scale; + uint8 val, oldval; + int vis_length = 0; + void *vis_buffer = NULL; + int vis_bps; + apu_t apu; + + apu_getcontext(&apu); + vis_buffer = apu.buffer; + vis_length = apu.num_samples; + vis_bps = apu.sample_bits; + + xofs = (NES_SCREEN_WIDTH - WAVEDISP_WIDTH); + yofs = 1; + scale = (float) (vis_length / (float) WAVEDISP_WIDTH); + + if (NULL == vis_buffer) + { + /* draw centerline */ + gui_hline(xofs, yofs + 0x20, WAVEDISP_WIDTH, GUI_GRAY); + gui_textbar("no sound", xofs + 40, yofs + 0x20 - 4, &small, GUI_RED, GUI_DKGRAY, BUTTON_UP); + + } + else if (GUI_WAVELINE == wave_type) + { + /* draw centerline */ + gui_hline(xofs, yofs + 0x20, WAVEDISP_WIDTH, GUI_GRAY); + + /* initial old value */ + if (16 == vis_bps) + oldval = 0x40 - (((((uint16 *) vis_buffer)[0] >> 8) ^ 0x80) >> 2); + else + oldval = 0x40 - (((uint8 *) vis_buffer)[0] >> 2); + + for (loop = 1; loop < WAVEDISP_WIDTH; loop++) + { + //val = 0x40 - (vis_buffer[(uint32) (loop * scale)] >> 2); + if (16 == vis_bps) + val = 0x40 - (((((uint16 *) vis_buffer)[(uint32) (loop * scale)] >> 8) ^ 0x80) >> 2); + else + val = 0x40 - (((uint8 *) vis_buffer)[(uint32) (loop * scale)] >> 2); + if (oldval < val) + { + offset = oldval; + difference = (val - oldval) + 1; + } + else + { + offset = val; + difference = (oldval - val) + 1; + } + + gui_vline(xofs + loop, yofs + offset, difference, GUI_GREEN); + oldval = val; + } + } + /* solid wave */ + else if (GUI_WAVESOLID == wave_type) + { + for (loop = 0; loop < WAVEDISP_WIDTH; loop++) + { + //val = vis_buffer[(uint32) (loop * scale)] >> 2; + if (16 == vis_bps) + val = ((((uint16 *) vis_buffer)[(uint32) (loop * scale)] >> 8) ^ 0x80) >> 2; + else + val = ((uint8 *) vis_buffer)[(uint32) (loop * scale)] >> 2; + if (val == 0x20) + gui_putpixel(xofs + loop, yofs + 0x20, GUI_GREEN); + else if (val < 0x20) + gui_vline(xofs + loop, yofs + 0x20, 0x20 - val, GUI_GREEN); + else + gui_vline(xofs + loop, yofs + 0x20 - (val - 0x20), val - 0x20, + GUI_GREEN); + } + } + + gui_rect(xofs, yofs - 1, WAVEDISP_WIDTH, 66, GUI_DKGRAY); +} + + +static void gui_updatepattern(void) +{ + /* Pretty it up a bit */ + gui_textbar("Pattern Table 0", 0, 0, &small, GUI_GREEN, GUI_DKGRAY, BUTTON_UP); + gui_textbar("Pattern Table 1", 128, 0, &small, GUI_GREEN, GUI_DKGRAY, BUTTON_UP); + gui_hline(0, 9, 256, GUI_DKGRAY); + gui_hline(0, 138, 256, GUI_DKGRAY); + + /* Dump the actual tables */ + ppu_dumppattern(gui_surface, 0, 0, 10, pattern_col); + ppu_dumppattern(gui_surface, 1, 128, 10, pattern_col); +} + +static void gui_updateoam(void) +{ + int y; + + y = option_showpattern ? 140 : 0; + gui_textbar("Current OAM", 0, y, &small, GUI_GREEN, GUI_DKGRAY, BUTTON_UP); + ppu_dumpoam(gui_surface, 0, y + 9); +} + + +/* The GUI overlay */ +void gui_frame(int draw) +{ + gui_fps++; + if (0 == draw) + return; + + gui_surface = vid_getbuffer(); + + ASSERT(gui_surface); + + gui_tickdec(); + + if (option_showfps) + gui_updatefps(); + + if (option_wavetype != GUI_WAVENONE) + gui_updatewave(option_wavetype); + + if (option_showpattern) + gui_updatepattern(); + + if (option_showoam) + gui_updateoam(); + + if (msg.ttl) + gui_updatemsg(); + + if (option_showgui) + { + //osd_getmouse(&mouse_x, &mouse_y, &mouse_button); + gui_drawmouse(); + } +} + +void gui_sendmsg() +{ +} + +void gui_setrefresh(int frequency) +{ + gui_refresh = frequency; +} + +int gui_init(void) +{ + gui_refresh = 60; + memset(&msg, 0, sizeof(message_t)); + + return 0; /* can't fail */ +} + +void gui_shutdown(void) +{ +} + +/* +** $Log: gui.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.26 2000/11/25 20:26:05 matt +** removed fds "system" +** +** Revision 1.25 2000/11/09 14:05:43 matt +** state load fixed, state save mostly fixed +** +** Revision 1.24 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.23 2000/10/27 12:57:49 matt +** fixed pcx snapshots +** +** Revision 1.22 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.21 2000/10/23 17:50:47 matt +** adding fds support +** +** Revision 1.20 2000/10/23 15:52:04 matt +** better system handling +** +** Revision 1.19 2000/10/22 19:15:39 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.18 2000/10/17 03:22:37 matt +** cleaning up rom module +** +** Revision 1.17 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.16 2000/10/10 13:03:53 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.15 2000/10/08 17:59:12 matt +** gui_ticks is volatile +** +** Revision 1.14 2000/09/15 04:58:06 matt +** simplifying and optimizing APU core +** +** Revision 1.13 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.12 2000/07/30 04:29:59 matt +** no more apu_getpcmdata hack +** +** Revision 1.11 2000/07/25 02:20:47 matt +** moved gui palette filth here, for the time being +** +** Revision 1.10 2000/07/24 04:32:05 matt +** bugfix on message delay +** +** Revision 1.9 2000/07/23 15:16:25 matt +** moved non-osd code here +** +** Revision 1.8 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/07/11 04:40:23 matt +** updated for new screen dimension defines +** +** Revision 1.6 2000/07/09 03:39:33 matt +** small gui_frame cleanup +** +** Revision 1.5 2000/07/06 16:47:18 matt +** new video driver interface +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes.c =================================================================== --- apps/plugins/nofrendo/nes.c (revision 0) +++ apps/plugins/nofrendo/nes.c (revision 0) @@ -0,0 +1,770 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes.c +** +** NES hardware related routines +** $Id: nes.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include "nes6502.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define NES_CLOCK_DIVIDER 12 +//#define NES_MASTER_CLOCK 21477272.727272727272 +#define NES_MASTER_CLOCK (236250000 / 11) +#define NES_SCANLINE_CYCLES (1364.0 / NES_CLOCK_DIVIDER) +#define NES_FIQ_PERIOD (NES_MASTER_CLOCK / NES_CLOCK_DIVIDER / 60) + +#define NES_RAMSIZE 0x800 + +#define NES_SKIP_LIMIT (NES_REFRESH_RATE / 5) /* 12 or 10, depending on PAL/NTSC */ + +static nes_t nes; + +/* find out if a file is ours */ +int nes_isourfile(const char *filename) +{ + return rom_checkmagic(filename); +} + +/* TODO: just asking for problems -- please remove */ +nes_t *nes_getcontextptr(void) +{ + return &nes; +} + +void nes_getcontext(nes_t *machine) +{ + apu_getcontext(nes.apu); + ppu_getcontext(nes.ppu); + nes6502_getcontext(nes.cpu); + mmc_getcontext(nes.mmc); + + *machine = nes; +} + +void nes_setcontext(nes_t *machine) +{ + ASSERT(machine); + + apu_setcontext(machine->apu); + ppu_setcontext(machine->ppu); + nes6502_setcontext(machine->cpu); + mmc_setcontext(machine->mmc); + + nes = *machine; +} + +static uint8 ram_read(uint32 address) +{ + return nes.cpu->mem_page[0][address & (NES_RAMSIZE - 1)]; +} + +static void ram_write(uint32 address, uint8 value) +{ + nes.cpu->mem_page[0][address & (NES_RAMSIZE - 1)] = value; +} + +static void write_protect(uint32 address, uint8 value) +{ + /* don't allow write to go through */ + UNUSED(address); + UNUSED(value); +} + +static uint8 read_protect(uint32 address) +{ + /* don't allow read to go through */ + UNUSED(address); + + return 0xFF; +} + +#define LAST_MEMORY_HANDLER { -1, -1, NULL } +/* read/write handlers for standard NES */ +static nes6502_memread default_readhandler[] = +{ + { 0x0800, 0x1FFF, ram_read }, + { 0x2000, 0x3FFF, ppu_read }, + { 0x4000, 0x4015, apu_read }, + { 0x4016, 0x4017, ppu_readhigh }, + LAST_MEMORY_HANDLER +}; + +static nes6502_memwrite default_writehandler[] = +{ + { 0x0800, 0x1FFF, ram_write }, + { 0x2000, 0x3FFF, ppu_write }, + { 0x4000, 0x4013, apu_write }, + { 0x4015, 0x4015, apu_write }, + { 0x4014, 0x4017, ppu_writehigh }, + LAST_MEMORY_HANDLER +}; + +/* this big nasty boy sets up the address handlers that the CPU uses */ +static void build_address_handlers(nes_t *machine) +{ + int count, num_handlers = 0; + mapintf_t *intf; + + ASSERT(machine); + intf = machine->mmc->intf; + + memset(machine->readhandler, 0, sizeof(machine->readhandler)); + memset(machine->writehandler, 0, sizeof(machine->writehandler)); + + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == default_readhandler[count].read_func) + break; + + memcpy(&machine->readhandler[num_handlers], &default_readhandler[count], + sizeof(nes6502_memread)); + } + + if (intf->sound_ext) + { + if (NULL != intf->sound_ext->mem_read) + { + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == intf->sound_ext->mem_read[count].read_func) + break; + + memcpy(&machine->readhandler[num_handlers], &intf->sound_ext->mem_read[count], + sizeof(nes6502_memread)); + } + } + } + + if (NULL != intf->mem_read) + { + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == intf->mem_read[count].read_func) + break; + + memcpy(&machine->readhandler[num_handlers], &intf->mem_read[count], + sizeof(nes6502_memread)); + } + } + + /* TODO: poof! numbers */ + machine->readhandler[num_handlers].min_range = 0x4018; + machine->readhandler[num_handlers].max_range = 0x5FFF; + machine->readhandler[num_handlers].read_func = read_protect; + num_handlers++; + machine->readhandler[num_handlers].min_range = -1; + machine->readhandler[num_handlers].max_range = -1; + machine->readhandler[num_handlers].read_func = NULL; + num_handlers++; + ASSERT(num_handlers <= MAX_MEM_HANDLERS); + + num_handlers = 0; + + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == default_writehandler[count].write_func) + break; + + memcpy(&machine->writehandler[num_handlers], &default_writehandler[count], + sizeof(nes6502_memwrite)); + } + + if (intf->sound_ext) + { + if (NULL != intf->sound_ext->mem_write) + { + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == intf->sound_ext->mem_write[count].write_func) + break; + + memcpy(&machine->writehandler[num_handlers], &intf->sound_ext->mem_write[count], + sizeof(nes6502_memwrite)); + } + } + } + + if (NULL != intf->mem_write) + { + for (count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) + { + if (NULL == intf->mem_write[count].write_func) + break; + + memcpy(&machine->writehandler[num_handlers], &intf->mem_write[count], + sizeof(nes6502_memwrite)); + } + } + + /* catch-all for bad writes */ + /* TODO: poof! numbers */ + machine->writehandler[num_handlers].min_range = 0x4018; + machine->writehandler[num_handlers].max_range = 0x5FFF; + machine->writehandler[num_handlers].write_func = write_protect; + num_handlers++; + machine->writehandler[num_handlers].min_range = 0x8000; + machine->writehandler[num_handlers].max_range = 0xFFFF; + machine->writehandler[num_handlers].write_func = write_protect; + num_handlers++; + machine->writehandler[num_handlers].min_range = -1; + machine->writehandler[num_handlers].max_range = -1; + machine->writehandler[num_handlers].write_func = NULL; + num_handlers++; + ASSERT(num_handlers <= MAX_MEM_HANDLERS); +} + +/* raise an IRQ */ +void nes_irq(void) +{ +#ifdef NOFRENDO_DEBUG + if (nes.scanline <= NES_SCREEN_HEIGHT) + memset(nes.vidbuf->line[nes.scanline - 1], GUI_RED, NES_SCREEN_WIDTH); +#endif /* NOFRENDO_DEBUG */ + + nes6502_irq(); +} + +static uint8 nes_clearfiq(void) +{ + if (nes.fiq_occurred) + { + nes.fiq_occurred = 0; + return 0x40; + } + + return 0; +} + +void nes_setfiq(uint8 value) +{ + nes.fiq_state = value; + nes.fiq_cycles = (int) NES_FIQ_PERIOD; +} + +static void nes_checkfiq(int cycles) +{ + nes.fiq_cycles -= cycles; + if (nes.fiq_cycles <= 0) + { + nes.fiq_cycles += (int) NES_FIQ_PERIOD; + if (0 == (nes.fiq_state & 0xC0)) + { + nes.fiq_occurred = 1; + nes6502_irq(); + } + } +} + +void nes_nmi(void) +{ + nes6502_nmi(); +} + +static void nes_renderframe(int draw_flag) +{ + int elapsed_cycles; + mapintf_t *mapintf = nes.mmc->intf; + int in_vblank = 0; + + while (262 != nes.scanline) + { + ppu_scanline(nes.vidbuf, nes.scanline, draw_flag); + + if (241 == nes.scanline) + { + /* 7-9 cycle delay between when VINT flag goes up and NMI is taken */ + elapsed_cycles = nes6502_execute(7); + nes.scanline_cycles -= elapsed_cycles; + nes_checkfiq(elapsed_cycles); + + ppu_checknmi(); + + if (mapintf->vblank) + mapintf->vblank(); + in_vblank = 1; + } + + if (mapintf->hblank) + mapintf->hblank(in_vblank); + + nes.scanline_cycles += (float) NES_SCANLINE_CYCLES; + elapsed_cycles = nes6502_execute((int) nes.scanline_cycles); + nes.scanline_cycles -= (float) elapsed_cycles; + nes_checkfiq(elapsed_cycles); + + ppu_endscanline(nes.scanline); + nes.scanline++; + } + + nes.scanline = 0; +} + +static void system_video(int draw) +{ + /* TODO: hack */ + if (0 == draw) + { + gui_frame(0); + return; + } + + /* blit the NES screen to our video surface */ + vid_blit(nes.vidbuf, 0, (NES_SCREEN_HEIGHT - NES_VISIBLE_HEIGHT) / 2, + 0, 0, NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); + + /* overlay our GUI on top of it */ + gui_frame(1); + + /* blit to screen */ + vid_flush(); + + /* grab input */ + osd_getinput(); +} + +/* main emulation loop */ +void nes_emulate(void) +{ + int last_ticks, frames_to_render; + + osd_setsound(nes.apu->process); + + last_ticks = nofrendo_ticks; + frames_to_render = 0; + nes.scanline_cycles = 0; + nes.fiq_cycles = (int) NES_FIQ_PERIOD; + + while (0 == nes.poweroff) + { + if (nofrendo_ticks != last_ticks) + { + int tick_diff = nofrendo_ticks - last_ticks; + + frames_to_render += tick_diff; + gui_tick(tick_diff); + last_ticks = nofrendo_ticks; + } + + if (1 == nes.pause) + { + /* TODO: dim the screen, and pause/silence the apu */ + system_video(1); + frames_to_render = 0; + } + else if (frames_to_render > 1) + { + frames_to_render--; + nes_renderframe(0); + system_video(0); + } + else if ((1 == frames_to_render && 1 == nes.autoframeskip) + || 0 == nes.autoframeskip) + { + frames_to_render = 0; + nes_renderframe(1); + system_video(1); + } + } +} + +static void mem_trash(uint8 *buffer, int length) +{ + int i; + + for (i = 0; i < length; i++) + buffer[i] = (uint8) rand(); +} + +/* Reset NES hardware */ +void nes_reset(int reset_type) +{ + if (HARD_RESET == reset_type) + { + memset(nes.cpu->mem_page[0], 0, NES_RAMSIZE); + if (nes.rominfo->vram) + mem_trash(nes.rominfo->vram, 0x2000 * nes.rominfo->vram_banks); + } + + apu_reset(); + ppu_reset(reset_type); + mmc_reset(); + nes6502_reset(); + + nes.scanline = 241; + + gui_sendmsg(GUI_GREEN, "NES %s", + (HARD_RESET == reset_type) ? "powered on" : "reset"); +} + +void nes_destroy(nes_t **machine) +{ + if (*machine) + { + rom_free(&(*machine)->rominfo); + mmc_destroy(&(*machine)->mmc); + ppu_destroy(&(*machine)->ppu); + apu_destroy(&(*machine)->apu); + bmp_destroy(&(*machine)->vidbuf); + if ((*machine)->cpu) + { + if ((*machine)->cpu->mem_page[0]) + free((*machine)->cpu->mem_page[0]); + free((*machine)->cpu); + } + + free(*machine); + *machine = NULL; + } +} + +void nes_poweroff(void) +{ + nes.poweroff = 1; +} + +void nes_togglepause(void) +{ + nes.pause ^= 1; +} + +/* insert a cart into the NES */ +int nes_insertcart(const char *filename, nes_t *machine) +{ + nes6502_setcontext(machine->cpu); + + /* rom file */ + machine->rominfo = rom_load(filename); + if (NULL == machine->rominfo) + goto _fail; + + /* map cart's SRAM to CPU $6000-$7FFF */ + if (machine->rominfo->sram) + { + machine->cpu->mem_page[6] = machine->rominfo->sram; + machine->cpu->mem_page[7] = machine->rominfo->sram + 0x1000; + } + + /* mapper */ + machine->mmc = mmc_create(machine->rominfo); + if (NULL == machine->mmc) + goto _fail; + + /* if there's VRAM, let the PPU know */ + if (NULL != machine->rominfo->vram) + machine->ppu->vram_present = 1; + + apu_setext(machine->apu, machine->mmc->intf->sound_ext); + + build_address_handlers(machine); + + nes_setcontext(machine); + + nes_reset(HARD_RESET); + return 0; + +_fail: + nes_destroy(&machine); + return -1; +} + + +/* Initialize NES CPU, hardware, etc. */ +nes_t *nes_create(void) +{ + nes_t *machine; + sndinfo_t osd_sound; + int i; + + machine = malloc(sizeof(nes_t)); + if (NULL == machine) + return NULL; + + memset(machine, 0, sizeof(nes_t)); + + /* bitmap */ + /* 8 pixel overdraw */ + machine->vidbuf = bmp_create(NES_SCREEN_WIDTH, NES_SCREEN_HEIGHT, 8); + if (NULL == machine->vidbuf) + goto _fail; + + machine->autoframeskip = 1; + + /* cpu */ + machine->cpu = malloc(sizeof(nes6502_context)); + if (NULL == machine->cpu) + goto _fail; + + memset(machine->cpu, 0, sizeof(nes6502_context)); + + /* allocate 2kB RAM */ + machine->cpu->mem_page[0] = malloc(NES_RAMSIZE); + if (NULL == machine->cpu->mem_page[0]) + goto _fail; + + /* point all pages at NULL for now */ + for (i = 1; i < NES6502_NUMBANKS; i++) + machine->cpu->mem_page[i] = NULL; + + machine->cpu->read_handler = machine->readhandler; + machine->cpu->write_handler = machine->writehandler; + + /* apu */ + osd_getsoundinfo(&osd_sound); + machine->apu = apu_create(0, osd_sound.sample_rate, NES_REFRESH_RATE, osd_sound.bps); + + if (NULL == machine->apu) + goto _fail; + + /* set the IRQ routines */ + machine->apu->irq_callback = nes_irq; + machine->apu->irqclear_callback = nes_clearfiq; + + /* ppu */ + machine->ppu = ppu_create(); + if (NULL == machine->ppu) + goto _fail; + + machine->poweroff = 0; + machine->pause = 0; + + return machine; + +_fail: + nes_destroy(&machine); + return NULL; +} + +/* +** $Log: nes.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.18 2000/11/29 12:58:23 matt +** timing/fiq fixes +** +** Revision 1.17 2000/11/27 19:36:15 matt +** more timing fixes +** +** Revision 1.16 2000/11/26 16:13:13 matt +** slight fix (?) to nes_fiq +** +** Revision 1.15 2000/11/26 15:51:13 matt +** frame IRQ emulation +** +** Revision 1.14 2000/11/25 20:30:39 matt +** scanline emulation simplifications/timing fixes +** +** Revision 1.13 2000/11/25 01:53:42 matt +** int stinks sometimes +** +** Revision 1.12 2000/11/21 13:28:40 matt +** take care to zero allocated mem +** +** Revision 1.11 2000/11/20 13:23:32 matt +** nofrendo.c now handles timer +** +** Revision 1.10 2000/11/09 14:07:27 matt +** state load fixed, state save mostly fixed +** +** Revision 1.9 2000/11/05 22:19:37 matt +** pause buglet fixed +** +** Revision 1.8 2000/11/05 06:27:09 matt +** thinlib spawns changes +** +** Revision 1.7 2000/10/29 14:36:45 matt +** nes_clearframeirq is static +** +** Revision 1.6 2000/10/28 15:20:41 matt +** irq callbacks in nes_apu +** +** Revision 1.5 2000/10/27 12:55:58 matt +** nes6502 now uses 4kB banks across the boards +** +** Revision 1.4 2000/10/25 13:44:02 matt +** no more silly define names +** +** Revision 1.3 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.50 2000/10/23 17:51:09 matt +** adding fds support +** +** Revision 1.49 2000/10/23 15:53:08 matt +** better system handling +** +** Revision 1.48 2000/10/22 20:02:29 matt +** autoframeskip bugfix +** +** Revision 1.47 2000/10/22 19:16:15 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.46 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.45 2000/10/17 12:00:56 matt +** selectable apu base frequency +** +** Revision 1.44 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.43 2000/10/10 13:05:30 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.42 2000/10/08 17:53:37 matt +** minor accuracy changes +** +** Revision 1.41 2000/09/18 02:09:12 matt +** -pedantic is your friend +** +** Revision 1.40 2000/09/15 13:38:39 matt +** changes for optimized apu core +** +** Revision 1.39 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.38 2000/09/08 11:57:29 matt +** no more nes_fiq +** +** Revision 1.37 2000/08/31 02:39:01 matt +** moved dos stuff in here (temp) +** +** Revision 1.36 2000/08/16 02:51:55 matt +** random cleanups +** +** Revision 1.35 2000/08/11 02:43:50 matt +** moved frame irq stuff out of APU into here +** +** Revision 1.34 2000/08/11 01:42:43 matt +** change to OSD sound info interface +** +** Revision 1.33 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.32 2000/07/30 04:32:32 matt +** emulation of the NES frame IRQ +** +** Revision 1.31 2000/07/27 04:07:14 matt +** cleaned up the neighborhood lawns +** +** Revision 1.30 2000/07/27 03:59:52 neil +** pausing tweaks, during fullscreen toggles +** +** Revision 1.29 2000/07/27 03:19:22 matt +** just a little cleaner, that's all +** +** Revision 1.28 2000/07/27 02:55:23 matt +** nes_emulate went through detox +** +** Revision 1.27 2000/07/27 02:49:18 matt +** cleaner flow in nes_emulate +** +** Revision 1.26 2000/07/27 01:17:09 matt +** nes_insertrom -> nes_insertcart +** +** Revision 1.25 2000/07/26 21:36:14 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.24 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.23 2000/07/24 04:32:40 matt +** autoframeskip bugfix +** +** Revision 1.22 2000/07/23 15:13:48 matt +** apu API change, autoframeskip part of nes_t struct +** +** Revision 1.21 2000/07/21 02:44:41 matt +** merged osd_getinput and osd_gethostinput +** +** Revision 1.20 2000/07/17 05:12:55 matt +** nes_ppu.c is no longer a scary place to be-- cleaner & faster +** +** Revision 1.19 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.18 2000/07/15 23:51:23 matt +** hack for certain filthy NES titles +** +** Revision 1.17 2000/07/11 04:31:54 matt +** less magic number nastiness for screen dimensions +** +** Revision 1.16 2000/07/11 02:38:25 matt +** encapsulated memory address handlers into nes/nsf +** +** Revision 1.15 2000/07/10 13:50:49 matt +** added function nes_irq() +** +** Revision 1.14 2000/07/10 05:27:55 matt +** cleaned up mapper-specific callbacks +** +** Revision 1.13 2000/07/09 03:43:26 matt +** minor changes to gui handling +** +** Revision 1.12 2000/07/06 16:42:23 matt +** updated for new video driver +** +** Revision 1.11 2000/07/05 19:57:36 neil +** __GNUC -> __DJGPP in nes.c +** +** Revision 1.10 2000/07/05 12:23:03 matt +** removed unnecessary references +** +** Revision 1.9 2000/07/04 23:12:34 matt +** memory protection handlers +** +** Revision 1.8 2000/07/04 04:58:29 matt +** dynamic memory range handlers +** +** Revision 1.7 2000/06/26 04:58:51 matt +** minor bugfix +** +** Revision 1.6 2000/06/20 20:42:12 matt +** fixed some NULL pointer problems +** +** Revision 1.5 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/event.h =================================================================== --- apps/plugins/nofrendo/event.h (revision 0) +++ apps/plugins/nofrendo/event.h (revision 0) @@ -0,0 +1,154 @@ +/* vim: set tabstop=3 expandtab: +** +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** event.h +** +** OS-independent event handling +** $Id: event.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#include + +enum +{ + event_none = 0, + event_quit, + event_insert, + event_eject, + event_togglepause, + event_soft_reset, + event_hard_reset, + event_snapshot, + event_toggle_frameskip, + /* saves */ + event_state_save, + event_state_load, + event_state_slot_0, + event_state_slot_1, + event_state_slot_2, + event_state_slot_3, + event_state_slot_4, + event_state_slot_5, + event_state_slot_6, + event_state_slot_7, + event_state_slot_8, + event_state_slot_9, + /* GUI */ + event_gui_toggle_oam, + event_gui_toggle_wave, + event_gui_toggle_pattern, + event_gui_pattern_color_up, + event_gui_pattern_color_down, + event_gui_toggle_fps, + event_gui_display_info, + event_gui_toggle, + /* sound */ + event_toggle_channel_0, + event_toggle_channel_1, + event_toggle_channel_2, + event_toggle_channel_3, + event_toggle_channel_4, + event_toggle_channel_5, + event_set_filter_0, + event_set_filter_1, + event_set_filter_2, + /* picture */ + event_toggle_sprites, + event_palette_hue_up, + event_palette_hue_down, + event_palette_tint_up, + event_palette_tint_down, + event_palette_set_default, + event_palette_set_shady, + /* joypad 1 */ + event_joypad1_a, + event_joypad1_b, + event_joypad1_start, + event_joypad1_select, + event_joypad1_up, + event_joypad1_down, + event_joypad1_left, + event_joypad1_right, + /* joypad 2 */ + event_joypad2_a, + event_joypad2_b, + event_joypad2_start, + event_joypad2_select, + event_joypad2_up, + event_joypad2_down, + event_joypad2_left, + event_joypad2_right, + /* NSF control */ + event_songup, + event_songdown, + event_startsong, + /* OS specific */ + event_osd_1, + event_osd_2, + event_osd_3, + event_osd_4, + event_osd_5, + event_osd_6, + event_osd_7, + event_osd_8, + event_osd_9, + /* last */ + event_last +}; + +typedef void (*event_t)(int code); + +extern void event_init(void); +extern void event_set(int index, event_t handler); +extern event_t event_get(int index); +extern void event_set_system(system_t type); + +#endif /* !_EVENT_H_ */ + +/* +** $Log: event.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.6 2000/11/01 14:15:35 matt +** multi-system event system, or whatever +** +** Revision 1.5 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.4 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.3 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.2 2000/07/21 04:27:40 matt +** don't mind me... +** +** Revision 1.1 2000/07/21 04:26:38 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/gui.h =================================================================== --- apps/plugins/nofrendo/gui.h (revision 0) +++ apps/plugins/nofrendo/gui.h (revision 0) @@ -0,0 +1,146 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** gui.h +** +** GUI defines / prototypes +** $Id: gui.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _GUI_H_ +#define _GUI_H_ + +/* GUI colors - the last 64 of a 256-color palette */ + +#define GUI_FIRSTENTRY 192 + +enum +{ + GUI_BLACK = GUI_FIRSTENTRY, + GUI_DKGRAY, + GUI_GRAY, + GUI_LTGRAY, + GUI_WHITE, + GUI_RED, + GUI_GREEN, + GUI_BLUE, + GUI_YELLOW, + GUI_ORANGE, + GUI_PURPLE, + GUI_TEAL, + GUI_DKGREEN, + GUI_DKBLUE, + GUI_LASTENTRY +}; + +#define GUI_TOTALCOLORS (GUI_LASTENTRY - GUI_FIRSTENTRY) + +/* TODO: bleh */ +#include +extern rgb_t gui_pal[GUI_TOTALCOLORS]; + +#define MAX_MSG_LENGTH 256 + +typedef struct message_s +{ + int ttl; + char text[MAX_MSG_LENGTH]; + uint8 color; +} message_t; + +extern void gui_tick(int ticks); +extern void gui_setrefresh(int frequency); + +extern void gui_sendmsg(); + +extern int gui_init(void); +extern void gui_shutdown(void); + +extern void gui_frame(int draw); + +extern void gui_togglefps(void); +extern void gui_togglegui(void); +extern void gui_togglewave(void); +extern void gui_togglepattern(void); +extern void gui_toggleoam(void); + +extern void gui_decpatterncol(void); +extern void gui_incpatterncol(void); + +extern void gui_savesnap(void); +extern void gui_togglesprites(void); +extern void gui_togglefs(void); +extern void gui_displayinfo(); +extern void gui_toggle_chan(int chan); +extern void gui_setfilter(int filter_type); + + +#endif /* _GUI_H_ */ + +/* +** $Log: gui.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.17 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.16 2000/10/27 12:57:49 matt +** fixed pcx snapshots +** +** Revision 1.15 2000/10/23 17:50:47 matt +** adding fds support +** +** Revision 1.14 2000/10/23 15:52:04 matt +** better system handling +** +** Revision 1.13 2000/10/22 19:15:39 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.12 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.11 2000/10/10 13:03:53 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.10 2000/10/08 17:59:12 matt +** gui_ticks is volatile +** +** Revision 1.9 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.8 2000/07/25 02:20:47 matt +** moved gui palette filth here, for the time being +** +** Revision 1.7 2000/07/23 15:16:25 matt +** moved non-osd code here +** +** Revision 1.6 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.5 2000/07/09 03:39:33 matt +** small gui_frame cleanup +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/osd.h =================================================================== --- apps/plugins/nofrendo/osd.h (revision 0) +++ apps/plugins/nofrendo/osd.h (revision 0) @@ -0,0 +1,188 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** osd.h +** +** O/S dependent routine defintions (must be customized) +** $Id: osd.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _OSD_H_ +#define _OSD_H_ + +#include +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif /* PATH_MAX */ + +#ifdef __GNUC__ +#define __PACKED__ __attribute__ ((packed)) + +#ifdef __DJGPP__ +#define PATH_SEP '\\' +#else /* !__DJGPP__ */ +#define PATH_SEP '/' +#endif /* !__DJGPP__ */ + +#elif defined(WIN32) +#define __PACKED__ +#define PATH_SEP '\\' +#else /* !defined(WIN32) && !__GNUC__ */ +#define __PACKED__ +#define PATH_SEP ':' +#endif /* !defined(WIN32) && !__GNUC__ */ + +#if !defined(WIN32) && !defined(__DJGPP__) +#define stricmp strcasecmp +#endif /* !WIN32 && !__DJGPP__ */ + + +extern void osd_setsound(void (*playfunc)(void *buffer, int size)); + + +#ifndef NSF_PLAYER +#include +#include + +typedef struct vidinfo_s +{ + int default_width, default_height; + viddriver_t *driver; +} vidinfo_t; + +typedef struct sndinfo_s +{ + int sample_rate; + int bps; +} sndinfo_t; + +/* get info */ +extern void osd_getvideoinfo(vidinfo_t *info); +extern void osd_getsoundinfo(sndinfo_t *info); + +/* init / shutdown */ +extern int osd_init(void); +extern void osd_shutdown(void); +extern int osd_main(int filename); + +extern int osd_installtimer(int frequency, void *func, int funcsize, + void *counter, int countersize); + +/* filename manipulation */ +extern void osd_fullname(char *fullname, const char *shortname); +extern char *osd_newextension(char *string, char *ext); + +/* input */ +extern void osd_getinput(void); +extern void osd_getmouse(int *x, int *y, int *button); + +/* build a filename for a snapshot, return -ve for error */ +extern int osd_makesnapname(char *filename, int len); + +#endif /* !NSF_PLAYER */ + +#endif /* _OSD_H_ */ + +/* +** $Log: osd.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.30 2000/11/05 22:53:13 matt +** only one video driver per system, please +** +** Revision 1.29 2000/11/05 06:23:41 matt +** thinlib spawns changes +** +** Revision 1.28 2000/10/22 19:15:39 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.27 2000/10/21 19:25:59 matt +** many more cleanups +** +** Revision 1.26 2000/10/10 13:03:53 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.25 2000/10/02 15:01:12 matt +** frag size has been removed +** +** Revision 1.24 2000/08/31 02:40:18 matt +** fixed some crap +** +** Revision 1.23 2000/08/16 02:57:14 matt +** changed video interface a wee bit +** +** Revision 1.22 2000/08/11 01:46:30 matt +** new OSD sound information interface +** +** Revision 1.21 2000/08/04 15:01:32 neil +** BeOS cleanups +** +** Revision 1.20 2000/08/04 14:36:14 neil +** BeOS is working.. kinda +** +** Revision 1.19 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.18 2000/07/23 16:21:35 neil +** neither stricmp nor strcasecmp works everywhere +** +** Revision 1.17 2000/07/23 15:17:40 matt +** osd_getfragsize +** +** Revision 1.16 2000/07/21 13:37:20 neil +** snap filenames are OS-dependent +** +** Revision 1.15 2000/07/21 04:58:37 matt +** new osd_main structure +** +** Revision 1.14 2000/07/21 04:26:15 matt +** added some nasty externs +** +** Revision 1.13 2000/07/21 02:42:45 matt +** merged osd_getinput and osd_gethostinput +** +** Revision 1.12 2000/07/19 13:10:35 neil +** PATH_MAX +** +** Revision 1.11 2000/07/10 03:04:15 matt +** removed scanlines, backbuffer from custom blit +** +** Revision 1.10 2000/07/06 16:48:25 matt +** new video driver +** +** Revision 1.9 2000/07/05 17:26:16 neil +** Moved the externs in nofrendo.c to osd.h +** +** Revision 1.8 2000/07/04 23:07:06 matt +** djgpp path separator bugfix +** +** Revision 1.7 2000/07/04 04:45:33 matt +** moved INLINE define into types.h +** +** Revision 1.6 2000/06/29 16:06:18 neil +** Wrapped DOS-specific headers in an ifdef +** +** Revision 1.5 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/pcx.c =================================================================== --- apps/plugins/nofrendo/pcx.c (revision 0) +++ apps/plugins/nofrendo/pcx.c (revision 0) @@ -0,0 +1,139 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** pcx.c +** +** PCX format screen-saving routines +** $Id: pcx.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + +/* Save a PCX snapshot from a given NES bitmap */ +int pcx_write(char *filename, bitmap_t *bmp, rgb_t *pal) +{ + int *fp; + pcxheader_t header; + int i, line; + int width, height, x_min, y_min; + + ASSERT(bmp); + + width = bmp->width; + height = bmp->height; + x_min = 0; + y_min = 0; + + fp = rb->open(filename, O_WRONLY); + if (NULL == fp) + return -1; + + /* Fill in the header nonsense */ + memset(&header, 0, sizeof(header)); + + header.Manufacturer = 10; + header.Version = 5; + header.Encoding = 1; + header.BitsPerPixel = 8; + header.Xmin = x_min; + header.Ymin = y_min; + header.Xmax = width - 1; + header.Ymax = height - 1; + header.NPlanes = 1; + header.BytesPerLine = width; + header.PaletteInfo = 1; + header.HscreenSize = width - 1; + header.VscreenSize = height - 1; + + write(fp, &header, sizeof(header)); + + /* RLE encoding */ + for (line = 0; line < height; line++) + { + uint8 last, *mem; + int xpos = 0; + + mem = bmp->line[line + y_min] + x_min; + + while (xpos < width) + { + int rle_count = 0; + + do + { + last = *mem++; + xpos++; + rle_count++; + } + while (*mem == last && xpos < width && rle_count < 0x3F); + + if (rle_count > 1 || 0xC0 == (last & 0xC0)) + { + //fputc(0xC0 | rle_count, fp); + //fputc(last, fp); + } + else + { + //fputc(last, fp); + } + } + } + + /* Write palette */ + //fputc(0x0C, fp); /* $0C signifies 256 color palette */ + for (i = 0; i < 256; i++) + { + //fputc(pal[i].r, fp); + //fputc(pal[i].g, fp); + //fputc(pal[i].b, fp); + } + + /* We're done! */ + rb->close(fp); + return 0; +} + +/* +** $Log: pcx.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/11/06 05:17:48 matt +** better! +** +** Revision 1.7 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.6 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.5 2000/06/26 04:55:13 matt +** changed routine name, big whoop +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/version.h =================================================================== --- apps/plugins/nofrendo/version.h (revision 0) +++ apps/plugins/nofrendo/version.h (revision 0) @@ -0,0 +1,65 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** version.h +** +** Program name / version definitions +** $Id: version.h,v 1.2 2001/05/05 16:50:49 neil Exp $ +*/ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + +#ifdef NSF_PLAYER +#define APP_STRING "Nosefart" +#else +#define APP_STRING "Nofrendo" +#endif /* NSF_PLAYER */ + +#define APP_VERSION "2.0" + +#endif /* _VERSION_H_ */ + +/* +** $Log: version.h,v $ +** Revision 1.2 2001/05/05 16:50:49 neil +** preparing for distribution +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.9 2000/07/31 04:28:47 matt +** one million cleanups +** +** Revision 1.8 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/07/04 04:46:55 matt +** updated version number +** +** Revision 1.6 2000/06/20 00:03:39 matt +** updated for 1.91 +** +** Revision 1.5 2000/06/09 17:01:56 matt +** changed version to 1.90 +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes.h =================================================================== --- apps/plugins/nofrendo/nes.h (revision 0) +++ apps/plugins/nofrendo/nes.h (revision 0) @@ -0,0 +1,218 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes.h +** +** NES hardware related definitions / prototypes +** $Id: nes.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _NES_H_ +#define _NES_H_ + +#include +#include +#include +#include +#include +#include "nes6502.h" +#include + +/* Visible (NTSC) screen height */ +#ifndef NES_VISIBLE_HEIGHT +#define NES_VISIBLE_HEIGHT 224 +#endif /* !NES_VISIBLE_HEIGHT */ +#define NES_SCREEN_WIDTH 256 +#define NES_SCREEN_HEIGHT 240 + +/* NTSC = 60Hz, PAL = 50Hz */ +#ifdef PAL +#define NES_REFRESH_RATE 50 +#else /* !PAL */ +#define NES_REFRESH_RATE 60 +#endif /* !PAL */ + +#define MAX_MEM_HANDLERS 32 + +enum +{ + SOFT_RESET, + HARD_RESET +}; + + +typedef struct nes_s +{ + /* hardware things */ + nes6502_context *cpu; + nes6502_memread readhandler[MAX_MEM_HANDLERS]; + nes6502_memwrite writehandler[MAX_MEM_HANDLERS]; + + ppu_t *ppu; + apu_t *apu; + mmc_t *mmc; + rominfo_t *rominfo; + + /* video buffer */ + bitmap_t *vidbuf; + + int fiq_occurred; + uint8 fiq_state; + int fiq_cycles; + + int scanline; + + /* Timing stuff */ + float scanline_cycles; + int autoframeskip; + + /* control */ + int poweroff; + int pause; + +} nes_t; + + +extern int nes_isourfile(const char *filename); + +/* temp hack */ +extern nes_t *nes_getcontextptr(void); + +/* Function prototypes */ +extern void nes_getcontext(nes_t *machine); +extern void nes_setcontext(nes_t *machine); + +extern nes_t *nes_create(void); +extern void nes_destroy(nes_t **machine); +extern int nes_insertcart(const char *filename, nes_t *machine); + +extern void nes_setfiq(uint8 state); +extern void nes_nmi(void); +extern void nes_irq(void); +extern void nes_emulate(void); + +extern void nes_reset(int reset_type); + +extern void nes_poweroff(void); +extern void nes_togglepause(void); + +#endif /* _NES_H_ */ + +/* +** $Log: nes.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/11/26 15:51:13 matt +** frame IRQ emulation +** +** Revision 1.7 2000/11/25 20:30:39 matt +** scanline emulation simplifications/timing fixes +** +** Revision 1.6 2000/11/25 01:52:17 matt +** int stinks sometimes +** +** Revision 1.5 2000/11/09 14:07:28 matt +** state load fixed, state save mostly fixed +** +** Revision 1.4 2000/10/29 14:36:45 matt +** nes_clearframeirq is static +** +** Revision 1.3 2000/10/25 01:23:08 matt +** basic system autodetection +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.26 2000/10/23 17:51:10 matt +** adding fds support +** +** Revision 1.25 2000/10/23 15:53:08 matt +** better system handling +** +** Revision 1.24 2000/10/22 19:16:15 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.23 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.22 2000/10/10 13:58:15 matt +** stroustrup squeezing his way in the door +** +** Revision 1.21 2000/10/08 17:53:36 matt +** minor accuracy changes +** +** Revision 1.20 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.19 2000/09/08 11:57:29 matt +** no more nes_fiq +** +** Revision 1.18 2000/08/11 02:43:50 matt +** moved frame irq stuff out of APU into here +** +** Revision 1.17 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.16 2000/07/30 04:32:32 matt +** emulation of the NES frame IRQ +** +** Revision 1.15 2000/07/27 01:17:09 matt +** nes_insertrom -> nes_insertcart +** +** Revision 1.14 2000/07/26 21:36:16 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.13 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.12 2000/07/23 15:13:13 matt +** autoframeskip is now a member variable of nes_t +** +** Revision 1.11 2000/07/17 05:12:55 matt +** nes_ppu.c is no longer a scary place to be-- cleaner & faster +** +** Revision 1.10 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.9 2000/07/16 09:48:58 neil +** Make visible height compile-time configurable in the Makefile +** +** Revision 1.8 2000/07/11 04:31:55 matt +** less magic number nastiness for screen dimensions +** +** Revision 1.7 2000/07/11 02:40:36 matt +** forgot to remove framecounter +** +** Revision 1.6 2000/07/11 02:38:25 matt +** encapsulated memory address handlers into nes/nsf +** +** Revision 1.5 2000/07/10 13:50:50 matt +** added function nes_irq() +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/dis6502.c =================================================================== --- apps/plugins/nofrendo/dis6502.c (revision 0) +++ apps/plugins/nofrendo/dis6502.c (revision 0) @@ -0,0 +1,532 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** dis6502.c +** +** 6502 disassembler based on code from John Saeger +** $Id: dis6502.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include "nes6502.h" +#include "dis6502.h" + +#ifdef NES6502_DEBUG + +/* addressing modes */ +enum +{ + _imp, + _acc, + _rel, + _imm, + _abs, + _abs_x, + _abs_y, + _zero, + _zero_x, + _zero_y, + _ind, + _ind_x, + _ind_y +}; + +/* keep a filthy local copy of PC to +** reduce the amount of parameter passing +*/ +static uint32 pc_reg; + +/* if we ever overrun this buffer, something will +** have gone very wrong anyway... +*/ +static char disasm_buf[256]; + + +static uint8 dis_op8(void) +{ + return (nes6502_getbyte(pc_reg + 1)); +} + +static uint16 dis_op16(void) +{ + return (nes6502_getbyte(pc_reg + 1) + (nes6502_getbyte(pc_reg + 2) << 8)); +} + +static int dis_show_ind(char *buf) +{ + return sprintf(buf, "(%04X) ", dis_op16()); +} + +static int dis_show_ind_x(char *buf) +{ + return sprintf(buf, "(%02X,x) ", dis_op8()); +} + +static int dis_show_ind_y(char *buf) +{ + return sprintf(buf, "(%02X),y ", dis_op8()); +} + +static int dis_show_zero_x(char *buf) +{ + return sprintf(buf, " %02X,x ", dis_op8()); +} + +static int dis_show_zero_y(char *buf) +{ + return sprintf(buf, " %02X,y ", dis_op8()); +} + +static int dis_show_abs_y(char *buf) +{ + return sprintf(buf, " %04X,y ", dis_op16()); +} + +static int dis_show_abs_x(char *buf) +{ + return sprintf(buf, " %04X,x ", dis_op16()); +} + +static int dis_show_zero(char *buf) +{ + return sprintf(buf, " %02X ", dis_op8()); +} + +static int dis_show_abs(char *buf) +{ + return sprintf(buf, " %04X ", dis_op16()); +} + +static int dis_show_immediate(char *buf) +{ + return sprintf(buf, "#%02X ", dis_op8()); +} + +static int dis_show_acc(char *buf) +{ + return sprintf(buf, " a "); +} + +static int dis_show_relative(char *buf) +{ + int target; + + target = (int8) dis_op8(); + target += (pc_reg + 2); + return sprintf(buf, " %04X ", target); +} + +static int dis_show_code(char *buf, int optype) +{ + char *dest = buf + sprintf(buf, "%02X ", nes6502_getbyte(pc_reg)); + + switch (optype) + { + case _imp: + case _acc: + dest += sprintf(dest, " "); + break; + + case _rel: + case _imm: + case _zero: + case _zero_x: + case _zero_y: + case _ind_y: + case _ind_x: + dest += sprintf(dest, "%02X ", nes6502_getbyte(pc_reg + 1)); + break; + + case _abs: + case _abs_x: + case _abs_y: + case _ind: + dest += sprintf(dest, "%02X %02X ", nes6502_getbyte(pc_reg + 1), nes6502_getbyte(pc_reg + 2)); + break; + } + + return (int) (dest - buf); +} + +static int dis_show_op(char *buf, char *opstr, int optype) +{ + char *dest = buf; + + dest += dis_show_code(dest, optype); + dest += sprintf(dest, "%s ", opstr); + + switch(optype) + { + case _imp: dest += sprintf(dest, " "); break; + case _acc: dest += dis_show_acc(dest); break; + case _rel: dest += dis_show_relative(dest); break; + case _imm: dest += dis_show_immediate(dest); break; + case _abs: dest += dis_show_abs(dest); break; + case _abs_x: dest += dis_show_abs_x(dest); break; + case _abs_y: dest += dis_show_abs_y(dest); break; + case _zero: dest += dis_show_zero(dest); break; + case _zero_x: dest += dis_show_zero_x(dest); break; + case _zero_y: dest += dis_show_zero_y(dest); break; + case _ind: dest += dis_show_ind(dest); break; + case _ind_x: dest += dis_show_ind_x(dest); break; + case _ind_y: dest += dis_show_ind_y(dest); break; + } + + return (int) (dest - buf); +} + +char *nes6502_disasm(uint32 PC, uint8 P, uint8 A, uint8 X, uint8 Y, uint8 S) +{ + char *buf = disasm_buf; + char *op; + int type; + + pc_reg = PC; + + buf += sprintf(buf, "%04X: ", pc_reg); + + switch (nes6502_getbyte(pc_reg)) + { + case 0x00: op = "brk"; type = _imp; break; + case 0x01: op = "ora"; type = _ind_x; break; + case 0x02: op = "jam"; type = _imp; break; + case 0x03: op = "slo"; type = _ind_x; break; + case 0x04: op = "nop"; type = _zero; break; + case 0x05: op = "ora"; type = _zero; break; + case 0x06: op = "asl"; type = _zero; break; + case 0x07: op = "slo"; type = _zero; break; + case 0x08: op = "php"; type = _imp; break; + case 0x09: op = "ora"; type = _imm; break; + case 0x0a: op = "asl"; type = _acc; break; + case 0x0b: op = "anc"; type = _imm; break; + case 0x0c: op = "nop"; type = _abs; break; + case 0x0d: op = "ora"; type = _abs; break; + case 0x0e: op = "asl"; type = _abs; break; + case 0x0f: op = "slo"; type = _abs; break; + + case 0x10: op = "bpl"; type = _rel; break; + case 0x11: op = "ora"; type = _ind_y; break; + case 0x12: op = "jam"; type = _imp; break; + case 0x13: op = "slo"; type = _ind_y; break; + case 0x14: op = "nop"; type = _zero_x; break; + case 0x15: op = "ora"; type = _zero_x; break; + case 0x16: op = "asl"; type = _zero_x; break; + case 0x17: op = "slo"; type = _zero_x; break; + case 0x18: op = "clc"; type = _imp; break; + case 0x19: op = "ora"; type = _abs_y; break; + case 0x1a: op = "nop"; type = _imp; break; + case 0x1b: op = "slo"; type = _abs_y; break; + case 0x1c: op = "nop"; type = _abs_x; break; + case 0x1d: op = "ora"; type = _abs_x; break; + case 0x1e: op = "asl"; type = _abs_x; break; + case 0x1f: op = "slo"; type = _abs_x; break; + + case 0x20: op = "jsr"; type = _abs; break; + case 0x21: op = "and"; type = _ind_x; break; + case 0x22: op = "jam"; type = _imp; break; + case 0x23: op = "rla"; type = _ind_x; break; + case 0x24: op = "bit"; type = _zero; break; + case 0x25: op = "and"; type = _zero; break; + case 0x26: op = "rol"; type = _zero; break; + case 0x27: op = "rla"; type = _zero; break; + case 0x28: op = "plp"; type = _imp; break; + case 0x29: op = "and"; type = _imm; break; + case 0x2a: op = "rol"; type = _acc; break; + case 0x2b: op = "anc"; type = _imm; break; + case 0x2c: op = "bit"; type = _abs; break; + case 0x2d: op = "and"; type = _abs; break; + case 0x2e: op = "rol"; type = _abs; break; + case 0x2f: op = "rla"; type = _abs; break; + + case 0x30: op = "bmi"; type = _rel; break; + case 0x31: op = "and"; type = _ind_y; break; + case 0x32: op = "jam"; type = _imp; break; + case 0x33: op = "rla"; type = _ind_y; break; + case 0x34: op = "nop"; type = _imp; break; + case 0x35: op = "and"; type = _zero_x; break; + case 0x36: op = "rol"; type = _zero_x; break; + case 0x37: op = "rla"; type = _zero_x; break; + case 0x38: op = "sec"; type = _imp; break; + case 0x39: op = "and"; type = _abs_y; break; + case 0x3a: op = "nop"; type = _imp; break; + case 0x3b: op = "rla"; type = _abs_y; break; + case 0x3c: op = "nop"; type = _abs_x; break; + case 0x3d: op = "and"; type = _abs_x; break; + case 0x3e: op = "rol"; type = _abs_x; break; + case 0x3f: op = "rla"; type = _abs_x; break; + + case 0x40: op = "rti"; type = _imp; break; + case 0x41: op = "eor"; type = _ind_x; break; + case 0x42: op = "jam"; type = _imp; break; + case 0x43: op = "sre"; type = _ind_x; break; + case 0x44: op = "nop"; type = _zero; break; + case 0x45: op = "eor"; type = _zero; break; + case 0x46: op = "lsr"; type = _zero; break; + case 0x47: op = "sre"; type = _zero; break; + case 0x48: op = "pha"; type = _imp; break; + case 0x49: op = "eor"; type = _imm; break; + case 0x4a: op = "lsr"; type = _acc; break; + case 0x4b: op = "asr"; type = _imm; break; + case 0x4c: op = "jmp"; type = _abs; break; + case 0x4d: op = "eor"; type = _abs; break; + case 0x4e: op = "lsr"; type = _abs; break; + case 0x4f: op = "sre"; type = _abs; break; + + case 0x50: op = "bvc"; type = _rel; break; + case 0x51: op = "eor"; type = _ind_y; break; + case 0x52: op = "jam"; type = _imp; break; + case 0x53: op = "sre"; type = _ind_y; break; + case 0x54: op = "nop"; type = _zero_x; break; + case 0x55: op = "eor"; type = _zero_x; break; + case 0x56: op = "lsr"; type = _zero_x; break; + case 0x57: op = "sre"; type = _zero_x; break; + case 0x58: op = "cli"; type = _imp; break; + case 0x59: op = "eor"; type = _abs_y; break; + case 0x5a: op = "nop"; type = _imp; break; + case 0x5b: op = "sre"; type = _abs_y; break; + case 0x5c: op = "nop"; type = _abs_x; break; + case 0x5d: op = "eor"; type = _abs_x; break; + case 0x5e: op = "lsr"; type = _abs_x; break; + case 0x5f: op = "sre"; type = _abs_x; break; + + case 0x60: op = "rts"; type = _imp; break; + case 0x61: op = "adc"; type = _ind_x; break; + case 0x62: op = "jam"; type = _imp; break; + case 0x63: op = "rra"; type = _ind_x; break; + case 0x64: op = "nop"; type = _zero; break; + case 0x65: op = "adc"; type = _zero; break; + case 0x66: op = "ror"; type = _zero; break; + case 0x67: op = "rra"; type = _zero; break; + case 0x68: op = "pla"; type = _imp; break; + case 0x69: op = "adc"; type = _imm; break; + case 0x6a: op = "ror"; type = _acc; break; + case 0x6b: op = "arr"; type = _imm; break; + case 0x6c: op = "jmp"; type = _ind; break; + case 0x6d: op = "adc"; type = _abs; break; + case 0x6e: op = "ror"; type = _abs; break; + case 0x6f: op = "rra"; type = _abs; break; + + case 0x70: op = "bvs"; type = _rel; break; + case 0x71: op = "adc"; type = _ind_y; break; + case 0x72: op = "jam"; type = _imp; break; + case 0x73: op = "rra"; type = _ind_y; break; + case 0x74: op = "nop"; type = _zero_x; break; + case 0x75: op = "adc"; type = _zero_x; break; + case 0x76: op = "ror"; type = _zero_x; break; + case 0x77: op = "rra"; type = _zero_x; break; + case 0x78: op = "sei"; type = _imp; break; + case 0x79: op = "adc"; type = _abs_y; break; + case 0x7a: op = "nop"; type = _imp; break; + case 0x7b: op = "rra"; type = _abs_y; break; + case 0x7c: op = "nop"; type = _abs_x; break; + case 0x7d: op = "adc"; type = _abs_x; break; + case 0x7e: op = "ror"; type = _abs_x; break; + case 0x7f: op = "rra"; type = _abs_x; break; + + case 0x80: op = "nop"; type = _imm; break; + case 0x81: op = "sta"; type = _ind_x; break; + case 0x82: op = "nop"; type = _imm; break; + case 0x83: op = "sax"; type = _ind_x; break; + case 0x84: op = "sty"; type = _zero; break; + case 0x85: op = "sta"; type = _zero; break; + case 0x86: op = "stx"; type = _zero; break; + case 0x87: op = "sax"; type = _zero; break; + case 0x88: op = "dey"; type = _imp; break; + case 0x89: op = "nop"; type = _imm; break; + case 0x8a: op = "txa"; type = _imp; break; + case 0x8b: op = "ane"; type = _imm; break; + case 0x8c: op = "sty"; type = _abs; break; + case 0x8d: op = "sta"; type = _abs; break; + case 0x8e: op = "stx"; type = _abs; break; + case 0x8f: op = "sax"; type = _abs; break; + + case 0x90: op = "bcc"; type = _rel; break; + case 0x91: op = "sta"; type = _ind_y; break; + case 0x92: op = "jam"; type = _imp; break; + case 0x93: op = "sha"; type = _ind_y; break; + case 0x94: op = "sty"; type = _zero_x; break; + case 0x95: op = "sta"; type = _zero_x; break; + case 0x96: op = "stx"; type = _zero_y; break; + case 0x97: op = "sax"; type = _zero_y; break; + case 0x98: op = "tya"; type = _imp; break; + case 0x99: op = "sta"; type = _abs_y; break; + case 0x9a: op = "txs"; type = _imp; break; + case 0x9b: op = "shs"; type = _abs_y; break; + case 0x9c: op = "shy"; type = _abs_x; break; + case 0x9d: op = "sta"; type = _abs_x; break; + case 0x9e: op = "shx"; type = _abs_y; break; + case 0x9f: op = "sha"; type = _abs_y; break; + + case 0xa0: op = "ldy"; type = _imm; break; + case 0xa1: op = "lda"; type = _ind_x; break; + case 0xa2: op = "ldx"; type = _imm; break; + case 0xa3: op = "lax"; type = _ind_x; break; + case 0xa4: op = "ldy"; type = _zero; break; + case 0xa5: op = "lda"; type = _zero; break; + case 0xa6: op = "ldx"; type = _zero; break; + case 0xa7: op = "lax"; type = _zero; break; + case 0xa8: op = "tay"; type = _imp; break; + case 0xa9: op = "lda"; type = _imm; break; + case 0xaa: op = "tax"; type = _imp; break; + case 0xab: op = "lxa"; type = _imm; break; + case 0xac: op = "ldy"; type = _abs; break; + case 0xad: op = "lda"; type = _abs; break; + case 0xae: op = "ldx"; type = _abs; break; + case 0xaf: op = "lax"; type = _abs; break; + + case 0xb0: op = "bcs"; type = _rel; break; + case 0xb1: op = "lda"; type = _ind_y; break; + case 0xb2: op = "jam"; type = _imp; break; + case 0xb3: op = "lax"; type = _ind_y; break; + case 0xb4: op = "ldy"; type = _zero_x; break; + case 0xb5: op = "lda"; type = _zero_x; break; + case 0xb6: op = "ldx"; type = _zero_y; break; + case 0xb7: op = "lax"; type = _zero_y; break; + case 0xb8: op = "clv"; type = _imp; break; + case 0xb9: op = "lda"; type = _abs_y; break; + case 0xba: op = "tsx"; type = _imp; break; + case 0xbb: op = "las"; type = _abs_y; break; + case 0xbc: op = "ldy"; type = _abs_x; break; + case 0xbd: op = "lda"; type = _abs_x; break; + case 0xbe: op = "ldx"; type = _abs_y; break; + case 0xbf: op = "lax"; type = _abs_y; break; + + case 0xc0: op = "cpy"; type = _imm; break; + case 0xc1: op = "cmp"; type = _ind_x; break; + case 0xc2: op = "nop"; type = _imm; break; + case 0xc3: op = "dcp"; type = _ind_x; break; + case 0xc4: op = "cpy"; type = _zero; break; + case 0xc5: op = "cmp"; type = _zero; break; + case 0xc6: op = "dec"; type = _zero; break; + case 0xc7: op = "dcp"; type = _zero; break; + case 0xc8: op = "iny"; type = _imp; break; + case 0xc9: op = "cmp"; type = _imm; break; + case 0xca: op = "dex"; type = _imp; break; + case 0xcb: op = "sbx"; type = _imm; break; + case 0xcc: op = "cpy"; type = _abs; break; + case 0xcd: op = "cmp"; type = _abs; break; + case 0xce: op = "dec"; type = _abs; break; + case 0xcf: op = "dcp"; type = _abs; break; + + case 0xd0: op = "bne"; type = _rel; break; + case 0xd1: op = "cmp"; type = _ind_y; break; + case 0xd2: op = "jam"; type = _imp; break; + case 0xd3: op = "dcp"; type = _ind_y; break; + case 0xd4: op = "nop"; type = _zero_x; break; + case 0xd5: op = "cmp"; type = _zero_x; break; + case 0xd6: op = "dec"; type = _zero_x; break; + case 0xd7: op = "dcp"; type = _zero_x; break; + case 0xd8: op = "cld"; type = _imp; break; + case 0xd9: op = "cmp"; type = _abs_y; break; + case 0xda: op = "nop"; type = _imp; break; + case 0xdb: op = "dcp"; type = _abs_y; break; + case 0xdc: op = "nop"; type = _abs_x; break; + case 0xdd: op = "cmp"; type = _abs_x; break; + case 0xde: op = "dec"; type = _abs_x; break; + case 0xdf: op = "dcp"; type = _abs_x; break; + + case 0xe0: op = "cpx"; type = _imm; break; + case 0xe1: op = "sbc"; type = _ind_x; break; + case 0xe2: op = "nop"; type = _imm; break; + case 0xe3: op = "isb"; type = _ind_x; break; + case 0xe4: op = "cpx"; type = _zero; break; + case 0xe5: op = "sbc"; type = _zero; break; + case 0xe6: op = "inc"; type = _zero; break; + case 0xe7: op = "isb"; type = _zero; break; + case 0xe8: op = "inx"; type = _imp; break; + case 0xe9: op = "sbc"; type = _imm; break; + case 0xea: op = "nop"; type = _imp; break; + case 0xeb: op = "sbc"; type = _imm; break; + case 0xec: op = "cpx"; type = _abs; break; + case 0xed: op = "sbc"; type = _abs; break; + case 0xee: op = "inc"; type = _abs; break; + case 0xef: op = "isb"; type = _abs; break; + + case 0xf0: op = "beq"; type = _rel; break; + case 0xf1: op = "sbc"; type = _ind_y; break; + case 0xf2: op = "jam"; type = _imp; break; + case 0xf3: op = "isb"; type = _ind_y; break; + case 0xf4: op = "nop"; type = _zero_x; break; + case 0xf5: op = "sbc"; type = _zero_x; break; + case 0xf6: op = "inc"; type = _zero_x; break; + case 0xf7: op = "isb"; type = _zero_x; break; + case 0xf8: op = "sed"; type = _imp; break; + case 0xf9: op = "sbc"; type = _abs_y; break; + case 0xfa: op = "nop"; type = _imp; break; + case 0xfb: op = "isb"; type = _abs_y; break; + case 0xfc: op = "nop"; type = _abs_x; break; + case 0xfd: op = "sbc"; type = _abs_x; break; + case 0xfe: op = "inc"; type = _abs_x; break; + case 0xff: op = "isb"; type = _abs_x; break; + } + + buf += dis_show_op(buf, op, type); + + buf += sprintf(buf, "%c%c1%c%c%c%c%c %02X %02X %02X %02X\n", + (P & N_FLAG) ? 'N' : '.', + (P & V_FLAG) ? 'V' : '.', + (P & B_FLAG) ? 'B' : '.', + (P & D_FLAG) ? 'D' : '.', + (P & I_FLAG) ? 'I' : '.', + (P & Z_FLAG) ? 'Z' : '.', + (P & C_FLAG) ? 'C' : '.', + A, X, Y, S); + + return disasm_buf; +} + +#endif /* NES6502_DEBUG */ + +/* +** $Log: dis6502.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:39 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.11 2000/08/30 14:49:25 matt +** changed output of flags to be more readable +** +** Revision 1.10 2000/08/28 12:53:44 matt +** fixes for disassembler +** +** Revision 1.9 2000/07/25 10:49:38 matt +** fixed zero page Y output +** +** Revision 1.8 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/07/11 04:26:23 matt +** rewrote to fill up a static buffer, rather than use log_printf +** +** Revision 1.6 2000/07/10 05:15:58 matt +** fixed a bug in indirect x/y disassembly +** +** Revision 1.5 2000/07/05 12:06:23 matt +** cosmetic changes +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/vid_drv.c =================================================================== --- apps/plugins/nofrendo/vid_drv.c (revision 0) +++ apps/plugins/nofrendo/vid_drv.c (revision 0) @@ -0,0 +1,574 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** vid_drv.c +** +** Video driver +** $Id: vid_drv.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* hardware surface */ +static bitmap_t *screen = NULL; + +/* primary / backbuffer surfaces */ +static bitmap_t *primary_buffer = NULL, *back_buffer = NULL; + +static viddriver_t *driver = NULL; + +/* fast automagic loop unrolling */ +#define DUFFS_DEVICE(transfer, count) \ +{ \ + register int n = (count + 7) / 8; \ + switch (count % 8) \ + { \ + case 0: do { { transfer; } \ + case 7: { transfer; } \ + case 6: { transfer; } \ + case 5: { transfer; } \ + case 4: { transfer; } \ + case 3: { transfer; } \ + case 2: { transfer; } \ + case 1: { transfer; } \ + } while (--n > 0); \ + } \ +} + +/* some system dependent replacement routines (for speed) */ +INLINE int vid_memcmp(const void *p1, const void *p2, int len) +{ + /* check for 32-bit aligned data */ + if (0 == (((uint32) p1 & 3) | ((uint32) p2 & 3))) + { + uint32 *dw1 = (uint32 *) p1; + uint32 *dw2 = (uint32 *) p2; + + len >>= 2; + + DUFFS_DEVICE(if (*dw1++ != *dw2++) return -1, len); + } + else + /* fall back to 8-bit compares */ + { + uint8 *b1 = (uint8 *) p1; + uint8 *b2 = (uint8 *) p2; + + DUFFS_DEVICE(if (*b1++ != *b2++) return -1, len); + } + + return 0; +} + +/* super-dooper assembly memcpy (thanks, SDL!) */ +#if defined(__GNUC__) && defined(i386) +#define vid_memcpy(dest, src, len) \ +{ \ + int u0, u1, u2; \ + __asm__ __volatile__ ( \ + " cld \n" \ + " rep \n" \ + " movsl \n" \ + " testb $2,%b4 \n" \ + " je 1f \n" \ + " movsw \n" \ + "1: \n" \ + " testb $1,%b4 \n" \ + " je 2f \n" \ + " movsb \n" \ + "2: \n" \ + : "=&c" (u0), "=&D" (u1), "=&S" (u2) \ + : "0" ((len)/4), "q" (len), "1" (dest), "2" (src) \ + : "memory"); \ +} +#else /* !(defined(__GNUC__) && defined(i386)) */ +INLINE void vid_memcpy(void *dest, const void *src, int len) +{ + uint32 *s = (uint32 *) src; + uint32 *d = (uint32 *) dest; + + ASSERT(0 == ((len & 3) | ((uint32) src & 3) | ((uint32) dest & 3))); + len >>= 2; + + DUFFS_DEVICE(*d++ = *s++, len); +} +#endif /* !(defined(__GNUC__) && defined(i386)) */ + + +/* TODO: any way to remove this filth (GUI needs it)? */ +bitmap_t *vid_getbuffer(void) +{ + return primary_buffer; +} + +void vid_setpalette(rgb_t *p) +{ + ASSERT(driver); + ASSERT(p); + + driver->set_palette(p); +} + +/* blits a bitmap onto primary buffer */ +void vid_blit(bitmap_t *bitmap, int src_x, int src_y, int dest_x, int dest_y, + int width, int height) +{ + int bitmap_pitch, primary_pitch; + uint8 *dest_ptr, *src_ptr; + + ASSERT(bitmap); + + /* clip to source */ + if (src_y >= bitmap->height) + return; + if (src_y + height > bitmap->height) + height = bitmap->height - src_y; + + if (src_x >= bitmap->width) + return; + if (src_x + width > bitmap->width) + width = bitmap->width - src_x; + + /* clip to dest */ + if (dest_y + height <= 0) + { + return; + } + else if (dest_y < 0) + { + height += dest_y; + src_y -= dest_y; + dest_y = 0; + } + + if (dest_y >= primary_buffer->height) + return; + if (dest_y + height > primary_buffer->height) + height = primary_buffer->height - dest_y; + + if (dest_x + width <= 0) + { + return; + } + else if (dest_x < 0) + { + width += dest_x; + src_x -= dest_x; + dest_x = 0; + } + + if (dest_x >= primary_buffer->width) + return; + if (dest_x + width > primary_buffer->width) + width = primary_buffer->width - dest_x; + + src_ptr = bitmap->line[src_y] + src_x; + dest_ptr = primary_buffer->line[dest_y] + dest_x; + + /* Avoid doing unnecessary indexed lookups */ + bitmap_pitch = bitmap->pitch; + primary_pitch = primary_buffer->pitch; + + /* do the copy */ + while (height--) + { + vid_memcpy(dest_ptr, src_ptr, width); + src_ptr += bitmap_pitch; + dest_ptr += primary_pitch; + } +} + +static void vid_blitscreen(int num_dirties, rect_t *dirty_rects) +{ + int src_x, src_y, dest_x, dest_y; + int blit_width, blit_height; + + screen = driver->lock_write(); + + /* center in y direction */ + if (primary_buffer->height <= screen->height) + { + src_y = 0; + blit_height = primary_buffer->height; + dest_y = (screen->height - blit_height) >> 1; + } + else + { + src_y = (primary_buffer->height - screen->height) >> 1; + blit_height = screen->height; + dest_y = 0; + } + + /* and in x */ + if (primary_buffer->width <= screen->width) + { + src_x = 0; + blit_width = primary_buffer->width; + dest_x = (screen->width - blit_width) >> 1; + } + else + { + src_x = (primary_buffer->width - screen->width) >> 1; + blit_width = screen->width; + dest_x = 0; + } + + /* should we just copy the entire screen? */ + if (-1 == num_dirties) + { + uint8 *dest, *src; + + src = primary_buffer->line[src_y] + src_x; + dest = screen->line[dest_y] + dest_x; + + while (blit_height--) + { + vid_memcpy(dest, src, primary_buffer->width); + src += primary_buffer->pitch; + dest += screen->pitch; + } + } + else + { + /* we need to blit just a bunch of dirties */ + int i, j, height; + rect_t *rects = dirty_rects; + + for (i = 0; i < num_dirties && blit_height; i++) + { + height = rects->h; + if (blit_height < height) + height = blit_height; + + j = 0; + DUFFS_DEVICE( + { + vid_memcpy(screen->line[dest_y + rects->y + j] + rects->x + dest_x, + primary_buffer->line[src_y + rects->y + j] + rects->x + src_x, + rects->w); + j++; + blit_height--; + }, height); + + rects++; + } + } + + if (driver->free_write) + driver->free_write(num_dirties, dirty_rects); +} + +/* TODO: this code is sickly */ + +#define CHUNK_WIDTH 256 +#define CHUNK_HEIGHT 16 +#define MAX_DIRTIES ((256 / CHUNK_WIDTH) * (240 / CHUNK_HEIGHT)) +#define DIRTY_CUTOFF ((3 * MAX_DIRTIES) / 4) + +#if 0 +INLINE int calc_dirties(rect_t *list) +{ + bool dirty; + int num_dirties = 0; + int i = 0, j, line_offset = 0; + int iterations = primary_buffer->height / CHUNK_HEIGHT; + + for (i = 0; i < iterations; i++) + { + dirty = false; + + j = line_offset; + DUFFS_DEVICE( + { + if (vid_memcmp(back_buffer->line[j], primary_buffer->line[j], + CHUNK_WIDTH)) + { + dirty = true; + break; + } + + j++; + }, CHUNK_HEIGHT); + + if (true == dirty) + { + list->h = CHUNK_HEIGHT; + list->w = CHUNK_WIDTH; + list->x = 0; + list->y = line_offset; + list++; + + /* totally arbitrary at this point */ + if (++num_dirties > DIRTY_CUTOFF) + return -1; + } + + line_offset += CHUNK_HEIGHT; + } + + return num_dirties; +} +#endif + +void vid_flush(void) +{ + bitmap_t *temp; + int num_dirties; + rect_t dirty_rects[MAX_DIRTIES]; + + ASSERT(driver); + + if (1 == driver->invalidate) + { + driver->invalidate = 0; + num_dirties = -1; + } + else + { + //num_dirties = calc_dirties(dirty_rects); + num_dirties = -1; + } + + if (driver->custom_blit) + driver->custom_blit(primary_buffer, num_dirties, dirty_rects); + else + vid_blitscreen(num_dirties, dirty_rects); + + /* Swap pointers to the main/back buffers */ + temp = back_buffer; + back_buffer = primary_buffer; + primary_buffer = temp; +} + +/* emulated machine tells us which resolution it wants */ +int vid_setmode(int width, int height) +{ + if (NULL != primary_buffer) + bmp_destroy(&primary_buffer); + if (NULL != back_buffer) + bmp_destroy(&back_buffer); + + primary_buffer = bmp_create(width, height, 0); /* no overdraw */ + if (NULL == primary_buffer) + return -1; + + /* Create our backbuffer */ + back_buffer = bmp_create(width, height, 0); /* no overdraw */ + if (NULL == back_buffer) + { + bmp_destroy(&primary_buffer); + return -1; + } + + bmp_clear(primary_buffer, GUI_BLACK); + bmp_clear(back_buffer, GUI_BLACK); + + return 0; +} + +static int vid_findmode(int width, int height, viddriver_t *osd_driver) +{ + if (osd_driver->init(width, height)) + { + driver = NULL; + return -1; /* mode not available! */ + } + + /* we got our driver */ + driver = osd_driver; + + /* re-assert dimensions, clear the surface */ + screen = driver->lock_write(); + + /* use custom pageclear, if necessary */ + if (driver->clear) + driver->clear(GUI_BLACK); + else + bmp_clear(screen, GUI_BLACK); + + /* release surface */ + if (driver->free_write) + driver->free_write(-1, NULL); + + log_printf("video driver: %s at %dx%d\n", driver->name, + screen->width, screen->height); + + return 0; +} + +/* This is the interface to the drivers, used in nofrendo.c */ +int vid_init(int width, int height, viddriver_t *osd_driver) +{ + if (vid_findmode(width, height, osd_driver)) + { + log_printf("video initialization failed for %s at %dx%d\n", + osd_driver->name, width, height); + return -1; + } + + return 0; +} + +void vid_shutdown(void) +{ + if (NULL == driver) + return; + + if (NULL != primary_buffer) + bmp_destroy(&primary_buffer); + if (NULL != back_buffer) + bmp_destroy(&back_buffer); + + if (driver && driver->shutdown) + driver->shutdown(); +} + + +/* +** $Log: vid_drv.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.40 2000/11/25 20:26:42 matt +** not much +** +** Revision 1.39 2000/11/16 14:27:27 matt +** even more crash-proofness +** +** Revision 1.38 2000/11/16 14:11:18 neil +** Better *not* to crash in case of catastrophic failure in the driver +** +** Revision 1.37 2000/11/13 00:55:16 matt +** no dirties seems to be faster (!?!?) +** +** Revision 1.36 2000/11/06 05:16:18 matt +** minor clipping bug +** +** Revision 1.35 2000/11/06 02:16:26 matt +** cleanups +** +** Revision 1.34 2000/11/05 22:53:13 matt +** only one video driver per system, please +** +** Revision 1.33 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.32 2000/11/05 06:23:41 matt +** thinlib spawns changes +** +** Revision 1.31 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.30 2000/10/10 13:03:53 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.29 2000/10/08 17:58:23 matt +** lock_read() should not allow us to clear the bitmap +** +** Revision 1.28 2000/09/18 02:06:48 matt +** -pedantic is your friend +** +** Revision 1.27 2000/08/16 02:53:05 matt +** changed init() interface a wee bit +** +** Revision 1.26 2000/08/14 02:45:59 matt +** fixed nasty bug in vid_blitscreen +** +** Revision 1.24 2000/08/11 01:44:37 matt +** clipping bugfix +** +** Revision 1.23 2000/07/31 04:28:47 matt +** one million cleanups +** +** Revision 1.22 2000/07/28 07:25:49 neil +** Video driver has an invalidate flag, telling vid_drv not to calculate dirties for the next frame +** +** Revision 1.21 2000/07/28 03:51:45 matt +** lock_read used instead of lock_write in some places +** +** Revision 1.20 2000/07/28 01:24:05 matt +** dirty rectangle support +** +** Revision 1.19 2000/07/27 23:49:52 matt +** no more getmode +** +** Revision 1.18 2000/07/27 04:30:37 matt +** change to get_mode api +** +** Revision 1.17 2000/07/27 04:05:58 matt +** changed place where name goes +** +** Revision 1.16 2000/07/27 01:16:22 matt +** api changes for new main and dirty rects +** +** Revision 1.15 2000/07/26 21:36:13 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.14 2000/07/24 04:33:57 matt +** skeleton of dirty rectangle code in place +** +** Revision 1.13 2000/07/23 14:35:39 matt +** cleanups +** +** Revision 1.12 2000/07/18 19:41:26 neil +** use screen->pitch in blitscreen, not screen_width +** +** Revision 1.11 2000/07/11 04:30:16 matt +** overdraw unnecessary! +** +** Revision 1.10 2000/07/10 19:07:57 matt +** added custom clear() member call to video driver +** +** Revision 1.9 2000/07/10 03:06:49 matt +** my dependency file is broken... *snif* +** +** Revision 1.8 2000/07/10 03:04:15 matt +** removed scanlines, backbuffer from custom blit +** +** Revision 1.7 2000/07/10 01:03:20 neil +** New video scheme allows for custom blitters to be determined by the driver at runtime +** +** Revision 1.6 2000/07/09 03:34:46 matt +** temporary cleanup +** +** Revision 1.5 2000/07/08 23:48:29 neil +** Another assumption GGI kills: pitch == width for hardware bitmaps +** +** Revision 1.4 2000/07/07 20:18:03 matt +** added overdraw, fixed some bugs in blitters +** +** Revision 1.3 2000/07/07 18:33:55 neil +** no need to lock for reading just to get the dimensions +** +** Revision 1.2 2000/07/07 18:11:37 neil +** Generalizing the video driver +** +** Revision 1.1 2000/07/06 16:48:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/pcx.h =================================================================== --- apps/plugins/nofrendo/pcx.h (revision 0) +++ apps/plugins/nofrendo/pcx.h (revision 0) @@ -0,0 +1,82 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** pcx.h +** +** PCX format screen-saving routines +** $Id: pcx.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _PCX_H_ +#define _PCX_H_ + +#include +#include + +/* Got these out of ZSoft's document */ +typedef struct pcxheader_s +{ + uint8 Manufacturer __PACKED__; + uint8 Version __PACKED__; + uint8 Encoding __PACKED__; + uint8 BitsPerPixel __PACKED__; + uint16 Xmin __PACKED__; + uint16 Ymin __PACKED__; + uint16 Xmax __PACKED__; + uint16 Ymax __PACKED__; + uint16 HDpi __PACKED__; + uint16 VDpi __PACKED__; + uint8 Colormap[48] __PACKED__; + uint8 Reserved __PACKED__; + uint8 NPlanes __PACKED__; + uint16 BytesPerLine __PACKED__; + uint16 PaletteInfo __PACKED__; + uint16 HscreenSize __PACKED__; + uint16 VscreenSize __PACKED__; + uint8 Filler[54] __PACKED__; +} pcxheader_t; + +extern int pcx_write(char *filename, bitmap_t *bmp, rgb_t *pal); + +#endif /* _PCX_H_ */ + +/* +** $Log: pcx.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.7 2000/07/25 02:21:56 matt +** had forgotten some includes +** +** Revision 1.6 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.5 2000/06/26 04:55:13 matt +** changed routine name, big whoop +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/memguard.c =================================================================== --- apps/plugins/nofrendo/memguard.c (revision 0) +++ apps/plugins/nofrendo/memguard.c (revision 0) @@ -0,0 +1,492 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** memguard.c +** +** memory allocation wrapper routines +** +** NOTE: based on code (c) 1998 the Retrocade group +** $Id: memguard.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +#include +#include + +/* Maximum number of allocated blocks at any one time */ +#define MAX_BLOCKS 4096 + +/* Memory block structure */ +typedef struct memblock_s +{ + void *block_addr; + int block_size; + char *file_name; + int line_num; +} memblock_t; + +/* debugging flag */ +int mem_debug = 1; + + +#ifdef NOFRENDO_DEBUG + +static int mem_blockcount = 0; /* allocated block count */ +static memblock_t *mem_record = NULL; + +#define GUARD_STRING "GgUuAaRrDdSsTtRrIiNnGgBbLlOoCcKk" +#define GUARD_LENGTH 256 /* before and after allocated block */ + + +/* +** Check the memory guard to make sure out of bounds writes have not +** occurred. +*/ +static int mem_checkguardblock(void *data, int guard_size) +{ + char *check, *block; + int i, alloc_size; + + /* get the original pointer */ + block = ((char *) data) - guard_size; + + /* get the size */ + alloc_size = *((uint32 *) block)++; + + /* check leading guard string */ + check = GUARD_STRING; + for (i = sizeof(uint32); i < guard_size; i++) + { + /* wrap */ + if ('\0' == *check) + check = GUARD_STRING; + + if (*block++ != *check++) + return -1; + } + + /* check end of block */ + check = GUARD_STRING; + block = ((char *) data) + alloc_size; + for (i = 0; i < guard_size; i++) + { + /* wrap */ + if ('\0' == *check) + check = GUARD_STRING; + if (*block++ != *check++) + return -1; + } + + /* we're okay! */ + return 0; +} + +/* free a guard block */ +static void mem_freeguardblock(void *data, int guard_size) +{ + char *orig = ((char *) data) - guard_size; + + free(orig); +} + +/* allocate memory, guarding with a guard block in front and behind */ +static void *mem_guardalloc(int alloc_size, int guard_size) +{ + void *orig; + char *block, *check; + uint32 *ptr; + int i; + + /* pad it up to a 32-bit multiple */ + alloc_size = (alloc_size + 3) & ~3; + + /* allocate memory */ + orig = malloc(alloc_size + (guard_size * 2)); + if (NULL == orig) + return NULL; + + block = (char *) orig; + + /* get it to the pointer we will actually return */ + orig = (void *) ((char *) orig + guard_size); + + /* trash it all */ + ptr = (uint32 *) orig; + for (i = alloc_size / 4; i; i--) + *ptr++ = 0xDEADBEEF; + + /* store the size of the newly allocated block*/ + *((uint32 *) block)++ = alloc_size; + + /* put guard string at beginning of block */ + check = GUARD_STRING; + for (i = sizeof(uint32); i < guard_size; i++) + { + /* wrap */ + if ('\0' == *check) + check = GUARD_STRING; + + *block++ = *check++; + } + + /* put at end of block */ + check = GUARD_STRING; + block = (char *) orig + alloc_size; + for (i = 0; i < guard_size; i++) + { + /* wrap */ + if ('\0' == *check) + check = GUARD_STRING; + + *block++ = *check++; + } + + return orig; +} + + +/* Free up the space used by the memory block manager */ +void mem_cleanup(void) +{ + if (mem_record) + { + free(mem_record); + mem_record = NULL; + } +} + + +/* Allocate a bunch of memory to keep track of all memory blocks */ +static void mem_init(void) +{ + mem_cleanup(); + + mem_blockcount = 0; + + mem_record = malloc(MAX_BLOCKS * sizeof(memblock_t)); + ASSERT(mem_record); + memset(mem_record, 0, MAX_BLOCKS * sizeof(memblock_t)); +} + + +/* add a block of memory to the master record */ +static void mem_addblock(void *data, int block_size, char *file, int line) +{ + int i; + + for (i = 0; i < MAX_BLOCKS; i++) + { + if (NULL == mem_record[i].block_addr) + { + mem_record[i].block_addr = data; + mem_record[i].block_size = block_size; + mem_record[i].file_name = file; + mem_record[i].line_num = line; + return; + } + } + + ASSERT_MSG("out of memory blocks."); +} + +/* find an entry in the block record and delete it */ +static void mem_deleteblock(void *data, char *file, int line) +{ + int i; + char fail[256]; + + for (i = 0; i < MAX_BLOCKS; i++) + { + if (data == mem_record[i].block_addr) + { + if (mem_checkguardblock(mem_record[i].block_addr, GUARD_LENGTH)) + { +// sprintf(fail, "mem_deleteblock 0x%08X at line %d of %s -- block corrupt", +// (uint32) data, line, file); + ASSERT_MSG(fail); + } + + memset(&mem_record[i], 0, sizeof(memblock_t)); + return; + } + } + +// sprintf(fail, "mem_deleteblock 0x%08X at line %d of %s -- block not found", +// (uint32) data, line, file); + ASSERT_MSG(fail); +} +#endif /* NOFRENDO_DEBUG */ + +/* debugger-friendly versions of calls */ +#ifdef NOFRENDO_DEBUG + +/* allocates memory and clears it */ +void *_my_malloc(int size, char *file, int line) +{ + void *temp; + char fail[256]; + + if (NULL == mem_record && false != mem_debug) + mem_init(); + + if (false != mem_debug) + temp = mem_guardalloc(size, GUARD_LENGTH); + else + temp = malloc(size); + + if (NULL == temp) + { +// sprintf(fail, "malloc: out of memory at line %d of %s. block size: %d\n", +// line, file, size); + ASSERT_MSG(fail); + } + + if (false != mem_debug) + mem_addblock(temp, size, file, line); + + mem_blockcount++; + + return temp; +} + +/* free a pointer allocated with my_malloc */ +void _my_free(void **data, char *file, int line) +{ + char fail[256]; + + if (NULL == data || NULL == *data) + { +// sprintf(fail, "free: attempted to free NULL pointer at line %d of %s\n", +// line, file); + ASSERT_MSG(fail); + } + + /* if this is true, we are in REAL trouble */ + if (0 == mem_blockcount) + { + ASSERT_MSG("free: attempted to free memory when no blocks available"); + } + + mem_blockcount--; /* dec our block count */ + + if (false != mem_debug) + { + mem_deleteblock(*data, file, line); + mem_freeguardblock(*data, GUARD_LENGTH); + } + else + { + free(*data); + } + + *data = NULL; /* NULL our source */ +} + +char *_my_strdup(const char *string, char *file, int line) +{ + char *temp; + + if (NULL == string) + return NULL; + + temp = (char *) _my_malloc(strlen(string) + 1, file, line); + if (NULL == temp) + return NULL; + + strcpy(temp, string); + + return temp; +} + +#else /* !NOFRENDO_DEBUG */ + +/* allocates memory and clears it */ +void *_my_malloc(int size) +{ + void *temp; + char fail[256]; + + temp = malloc(size); + + if (NULL == temp) + { +// sprintf(fail, "malloc: out of memory. block size: %d\n", size); + ASSERT_MSG(fail); + } + + return temp; +} + +/* free a pointer allocated with my_malloc */ +void _my_free(void **data) +{ + char fail[256]; + + if (NULL == data || NULL == *data) + { +// sprintf(fail, "free: attempted to free NULL pointer.\n"); + ASSERT_MSG(fail); + } + + free(*data); + *data = NULL; /* NULL our source */ +} + +char *_my_strdup(const char *string) +{ + char *temp; + + if (NULL == string) + return NULL; + + /* will ASSERT for us */ + temp = (char *) _my_malloc(strlen(string) + 1); + if (NULL == temp) + return NULL; + + strcpy(temp, string); + + return temp; +} + +#endif /* !NOFRENDO_DEBUG */ + +/* check for orphaned memory handles */ +void mem_checkleaks(void) +{ +#ifdef NOFRENDO_DEBUG + int i; + + if (false == mem_debug || NULL == mem_record) + return; + + if (mem_blockcount) + { + log_printf("memory leak - %d unfreed block%s\n\n", mem_blockcount, + mem_blockcount == 1 ? "" : "s"); + + for (i = 0; i < MAX_BLOCKS; i++) + { + if (mem_record[i].block_addr) + { + log_printf("addr: 0x%08X, size: %d, line %d of %s%s\n", + (uint32) mem_record[i].block_addr, + mem_record[i].block_size, + mem_record[i].line_num, + mem_record[i].file_name, + (mem_checkguardblock(mem_record[i].block_addr, GUARD_LENGTH)) + ? " -- block corrupt" : ""); + } + } + } + else + log_printf("no memory leaks\n"); +#endif /* NOFRENDO_DEBUG */ +} + +void mem_checkblocks(void) +{ +#ifdef NOFRENDO_DEBUG + int i; + + if (false == mem_debug || NULL == mem_record) + return; + + for (i = 0; i < MAX_BLOCKS; i++) + { + if (mem_record[i].block_addr) + { + if (mem_checkguardblock(mem_record[i].block_addr, GUARD_LENGTH)) + { + log_printf("addr: 0x%08X, size: %d, line %d of %s -- block corrupt\n", + (uint32) mem_record[i].block_addr, + mem_record[i].block_size, + mem_record[i].line_num, + mem_record[i].file_name); + } + } + } +#endif /* NOFRENDO_DEBUG */ +} + +/* +** $Log: memguard.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.23 2000/11/24 21:42:48 matt +** vc complaints +** +** Revision 1.22 2000/11/21 13:27:30 matt +** trash all newly allocated memory +** +** Revision 1.21 2000/11/21 13:22:30 matt +** memory guard shouldn't zero memory for us +** +** Revision 1.20 2000/10/28 14:01:53 matt +** memguard.h was being included in the wrong place +** +** Revision 1.19 2000/10/26 22:48:33 matt +** strdup'ing a NULL ptr returns NULL +** +** Revision 1.18 2000/10/25 13:41:29 matt +** added strdup +** +** Revision 1.17 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.16 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.15 2000/09/18 02:06:48 matt +** -pedantic is your friend +** +** Revision 1.14 2000/08/11 01:45:48 matt +** hearing about no corrupt blocks every 10 seconds really was annoying +** +** Revision 1.13 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.12 2000/07/24 04:31:07 matt +** mem_checkblocks now gives feedback +** +** Revision 1.11 2000/07/06 17:20:52 matt +** block manager space itself wasn't being freed - d'oh! +** +** Revision 1.10 2000/07/06 17:15:43 matt +** false isn't NULL, Neil... =) +** +** Revision 1.9 2000/07/05 23:10:01 neil +** It's a shame if the memguard segfaults +** +** Revision 1.8 2000/06/26 04:54:48 matt +** simplified and made more robust +** +** Revision 1.7 2000/06/12 01:11:41 matt +** cleaned up some error output for win32 +** +** Revision 1.6 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/dis6502.h =================================================================== --- apps/plugins/nofrendo/dis6502.h (revision 0) +++ apps/plugins/nofrendo/dis6502.h (revision 0) @@ -0,0 +1,58 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** dis6502.h +** +** 6502 disassembler header +** $Id: dis6502.h,v 1.1 2001/04/27 12:54:39 neil Exp $ +*/ + +#ifndef _DIS6502_H_ +#define _DIS6502_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern char *nes6502_disasm(uint32 PC, uint8 P, uint8 A, uint8 X, uint8 Y, uint8 S); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_DIS6502_H_ */ + +/* +** $Log: dis6502.h,v $ +** Revision 1.1 2001/04/27 12:54:39 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.6 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.5 2000/07/11 04:26:23 matt +** rewrote to fill up a static buffer, rather than use log_printf +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes6502.c =================================================================== --- apps/plugins/nofrendo/nes6502.c (revision 0) +++ apps/plugins/nofrendo/nes6502.c (revision 0) @@ -0,0 +1,2573 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes6502.c +** +** NES custom 6502 (2A03) CPU implementation +** $Id: nes6502.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + + +#include +#include "nes6502.h" +#include "dis6502.h" + +//#define NES6502_DISASM + +#ifdef __GNUC__ +#define NES6502_JUMPTABLE +#endif /* __GNUC__ */ + + +#define ADD_CYCLES(x) \ +{ \ + remaining_cycles -= (x); \ + cpu.total_cycles += (x); \ +} + +/* +** Check to see if an index reg addition overflowed to next page +*/ +#define PAGE_CROSS_CHECK(addr, reg) \ +{ \ + if ((reg) > (uint8) (addr)) \ + ADD_CYCLES(1); \ +} + +#define EMPTY_READ(value) /* empty */ + +/* +** Addressing mode macros +*/ + +/* Immediate */ +#define IMMEDIATE_BYTE(value) \ +{ \ + value = bank_readbyte(PC++); \ +} + +/* Absolute */ +#define ABSOLUTE_ADDR(address) \ +{ \ + address = bank_readword(PC); \ + PC += 2; \ +} + +#define ABSOLUTE(address, value) \ +{ \ + ABSOLUTE_ADDR(address); \ + value = mem_readbyte(address); \ +} + +#define ABSOLUTE_BYTE(value) \ +{ \ + ABSOLUTE(temp, value); \ +} + +/* Absolute indexed X */ +#define ABS_IND_X_ADDR(address) \ +{ \ + ABSOLUTE_ADDR(address); \ + address = (address + X) & 0xFFFF; \ +} + +#define ABS_IND_X(address, value) \ +{ \ + ABS_IND_X_ADDR(address); \ + value = mem_readbyte(address); \ +} + +#define ABS_IND_X_BYTE(value) \ +{ \ + ABS_IND_X(temp, value); \ +} + +/* special page-cross check version for read instructions */ +#define ABS_IND_X_BYTE_READ(value) \ +{ \ + ABS_IND_X_ADDR(temp); \ + PAGE_CROSS_CHECK(temp, X); \ + value = mem_readbyte(temp); \ +} + +/* Absolute indexed Y */ +#define ABS_IND_Y_ADDR(address) \ +{ \ + ABSOLUTE_ADDR(address); \ + address = (address + Y) & 0xFFFF; \ +} + +#define ABS_IND_Y(address, value) \ +{ \ + ABS_IND_Y_ADDR(address); \ + value = mem_readbyte(address); \ +} + +#define ABS_IND_Y_BYTE(value) \ +{ \ + ABS_IND_Y(temp, value); \ +} + +/* special page-cross check version for read instructions */ +#define ABS_IND_Y_BYTE_READ(value) \ +{ \ + ABS_IND_Y_ADDR(temp); \ + PAGE_CROSS_CHECK(temp, Y); \ + value = mem_readbyte(temp); \ +} + +/* Zero-page */ +#define ZERO_PAGE_ADDR(address) \ +{ \ + IMMEDIATE_BYTE(address); \ +} + +#define ZERO_PAGE(address, value) \ +{ \ + ZERO_PAGE_ADDR(address); \ + value = ZP_READBYTE(address); \ +} + +#define ZERO_PAGE_BYTE(value) \ +{ \ + ZERO_PAGE(btemp, value); \ +} + +/* Zero-page indexed X */ +#define ZP_IND_X_ADDR(address) \ +{ \ + ZERO_PAGE_ADDR(address); \ + address += X; \ +} + +#define ZP_IND_X(address, value) \ +{ \ + ZP_IND_X_ADDR(address); \ + value = ZP_READBYTE(address); \ +} + +#define ZP_IND_X_BYTE(value) \ +{ \ + ZP_IND_X(btemp, value); \ +} + +/* Zero-page indexed Y */ +/* Not really an adressing mode, just for LDx/STx */ +#define ZP_IND_Y_ADDR(address) \ +{ \ + ZERO_PAGE_ADDR(address); \ + address += Y; \ +} + +#define ZP_IND_Y_BYTE(value) \ +{ \ + ZP_IND_Y_ADDR(btemp); \ + value = ZP_READBYTE(btemp); \ +} + +/* Indexed indirect */ +#define INDIR_X_ADDR(address) \ +{ \ + ZERO_PAGE_ADDR(btemp); \ + btemp += X; \ + address = zp_readword(btemp); \ +} + +#define INDIR_X(address, value) \ +{ \ + INDIR_X_ADDR(address); \ + value = mem_readbyte(address); \ +} + +#define INDIR_X_BYTE(value) \ +{ \ + INDIR_X(temp, value); \ +} + +/* Indirect indexed */ +#define INDIR_Y_ADDR(address) \ +{ \ + ZERO_PAGE_ADDR(btemp); \ + address = (zp_readword(btemp) + Y) & 0xFFFF; \ +} + +#define INDIR_Y(address, value) \ +{ \ + INDIR_Y_ADDR(address); \ + value = mem_readbyte(address); \ +} + +#define INDIR_Y_BYTE(value) \ +{ \ + INDIR_Y(temp, value); \ +} + +/* special page-cross check version for read instructions */ +#define INDIR_Y_BYTE_READ(value) \ +{ \ + INDIR_Y_ADDR(temp); \ + PAGE_CROSS_CHECK(temp, Y); \ + value = mem_readbyte(temp); \ +} + + + +/* Stack push/pull */ +#define PUSH(value) stack[S--] = (uint8) (value) +#define PULL() stack[++S] + + +/* +** flag register helper macros +*/ + +/* Theory: Z and N flags are set in just about every +** instruction, so we will just store the value in those +** flag variables, and mask out the irrelevant data when +** we need to check them (branches, etc). This makes the +** zero flag only really be 'set' when z_flag == 0. +** The rest of the flags are stored as true booleans. +*/ + +/* Scatter flags to separate variables */ +#define SCATTER_FLAGS(value) \ +{ \ + n_flag = (value) & N_FLAG; \ + v_flag = (value) & V_FLAG; \ + b_flag = (value) & B_FLAG; \ + d_flag = (value) & D_FLAG; \ + i_flag = (value) & I_FLAG; \ + z_flag = (0 == ((value) & Z_FLAG)); \ + c_flag = (value) & C_FLAG; \ +} + +/* Combine flags into flag register */ +#define COMBINE_FLAGS() \ +( \ + (n_flag & N_FLAG) \ + | (v_flag ? V_FLAG : 0) \ + | R_FLAG \ + | (b_flag ? B_FLAG : 0) \ + | (d_flag ? D_FLAG : 0) \ + | (i_flag ? I_FLAG : 0) \ + | (z_flag ? 0 : Z_FLAG) \ + | c_flag \ +) + +/* Set N and Z flags based on given value */ +#define SET_NZ_FLAGS(value) n_flag = z_flag = (value); + +/* For BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS */ +#define RELATIVE_BRANCH(condition) \ +{ \ + if (condition) \ + { \ + IMMEDIATE_BYTE(btemp); \ + if (((int8) btemp + (PC & 0x00FF)) & 0x100) \ + ADD_CYCLES(1); \ + ADD_CYCLES(3); \ + PC += (int8) btemp; \ + } \ + else \ + { \ + PC++; \ + ADD_CYCLES(2); \ + } \ +} + +#define JUMP(address) \ +{ \ + PC = bank_readword((address)); \ +} + +/* +** Interrupt macros +*/ +#define NMI_PROC() \ +{ \ + PUSH(PC >> 8); \ + PUSH(PC & 0xFF); \ + b_flag = 0; \ + PUSH(COMBINE_FLAGS()); \ + i_flag = 1; \ + JUMP(NMI_VECTOR); \ +} + +#define IRQ_PROC() \ +{ \ + PUSH(PC >> 8); \ + PUSH(PC & 0xFF); \ + b_flag = 0; \ + PUSH(COMBINE_FLAGS()); \ + i_flag = 1; \ + JUMP(IRQ_VECTOR); \ +} + +/* +** Instruction macros +*/ + +/* Warning! NES CPU has no decimal mode, so by default this does no BCD! */ +#ifdef NES6502_DECIMAL +#define ADC(cycles, read_func) \ +{ \ + read_func(data); \ + if (d_flag) \ + { \ + temp = (A & 0x0F) + (data & 0x0F) + c_flag; \ + if (temp >= 10) \ + temp = (temp - 10) | 0x10; \ + temp += (A & 0xF0) + (data & 0xF0); \ + z_flag = (A + data + c_flag) & 0xFF; \ + n_flag = temp; \ + v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \ + if (temp > 0x90) \ + { \ + temp += 0x60; \ + c_flag = 1; \ + } \ + else \ + { \ + c_flag = 0; \ + } \ + A = (uint8) temp; \ + } \ + else \ + { \ + temp = A + data + c_flag; \ + c_flag = (temp >> 8) & 1; \ + v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \ + A = (uint8) temp; \ + SET_NZ_FLAGS(A); \ + }\ + ADD_CYCLES(cycles); \ +} +#else +#define ADC(cycles, read_func) \ +{ \ + read_func(data); \ + temp = A + data + c_flag; \ + c_flag = (temp >> 8) & 1; \ + v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \ + A = (uint8) temp; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} +#endif /* NES6502_DECIMAL */ + +/* undocumented */ +#define ANC(cycles, read_func) \ +{ \ + read_func(data); \ + A &= data; \ + c_flag = (n_flag & N_FLAG) >> 7; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define AND(cycles, read_func) \ +{ \ + read_func(data); \ + A &= data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define ANE(cycles, read_func) \ +{ \ + read_func(data); \ + A = (A | 0xEE) & X & data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#ifdef NES6502_DECIMAL +#define ARR(cycles, read_func) \ +{ \ + read_func(data); \ + data &= A; \ + if (d_flag) \ + { \ + temp = (data >> 1) | (c_flag << 7); \ + SET_NZ_FLAGS(temp); \ + v_flag = (temp ^ data) & 0x40; \ + if (((data & 0x0F) + (data & 0x01)) > 5) \ + temp = (temp & 0xF0) | ((temp + 0x6) & 0x0F); \ + if (((data & 0xF0) + (data & 0x10)) > 0x50) \ + { \ + temp = (temp & 0x0F) | ((temp + 0x60) & 0xF0); \ + c_flag = 1; \ + } \ + else \ + { \ + c_flag = 0; \ + } \ + A = (uint8) temp; \ + } \ + else \ + { \ + A = (data >> 1) | (c_flag << 7); \ + SET_NZ_FLAGS(A); \ + c_flag = (A & 0x40) >> 6; \ + v_flag = ((A >> 6) ^ (A >> 5)) & 1; \ + }\ + ADD_CYCLES(cycles); \ +} +#else +#define ARR(cycles, read_func) \ +{ \ + read_func(data); \ + data &= A; \ + A = (data >> 1) | (c_flag << 7); \ + SET_NZ_FLAGS(A); \ + c_flag = (A & 0x40) >> 6; \ + v_flag = ((A >> 6) ^ (A >> 5)) & 1; \ + ADD_CYCLES(cycles); \ +} +#endif /* NES6502_DECIMAL */ + +#define ASL(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + c_flag = data >> 7; \ + data <<= 1; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define ASL_A() \ +{ \ + c_flag = A >> 7; \ + A <<= 1; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(2); \ +} + +/* undocumented */ +#define ASR(cycles, read_func) \ +{ \ + read_func(data); \ + data &= A; \ + c_flag = data & 1; \ + A = data >> 1; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define BCC() \ +{ \ + RELATIVE_BRANCH(0 == c_flag); \ +} + +#define BCS() \ +{ \ + RELATIVE_BRANCH(0 != c_flag); \ +} + +#define BEQ() \ +{ \ + RELATIVE_BRANCH(0 == z_flag); \ +} + +/* bit 7/6 of data move into N/V flags */ +#define BIT(cycles, read_func) \ +{ \ + read_func(data); \ + n_flag = data; \ + v_flag = data & V_FLAG; \ + z_flag = data & A; \ + ADD_CYCLES(cycles); \ +} + +#define BMI() \ +{ \ + RELATIVE_BRANCH(n_flag & N_FLAG); \ +} + +#define BNE() \ +{ \ + RELATIVE_BRANCH(0 != z_flag); \ +} + +#define BPL() \ +{ \ + RELATIVE_BRANCH(0 == (n_flag & N_FLAG)); \ +} + +/* Software interrupt type thang */ +#define BRK() \ +{ \ + PC++; \ + PUSH(PC >> 8); \ + PUSH(PC & 0xFF); \ + b_flag = 1; \ + PUSH(COMBINE_FLAGS()); \ + i_flag = 1; \ + JUMP(IRQ_VECTOR); \ + ADD_CYCLES(7); \ +} + +#define BVC() \ +{ \ + RELATIVE_BRANCH(0 == v_flag); \ +} + +#define BVS() \ +{ \ + RELATIVE_BRANCH(0 != v_flag); \ +} + +#define CLC() \ +{ \ + c_flag = 0; \ + ADD_CYCLES(2); \ +} + +#define CLD() \ +{ \ + d_flag = 0; \ + ADD_CYCLES(2); \ +} + +#define CLI() \ +{ \ + i_flag = 0; \ + ADD_CYCLES(2); \ + if (cpu.int_pending && remaining_cycles > 0) \ + { \ + cpu.int_pending = 0; \ + IRQ_PROC(); \ + ADD_CYCLES(INT_CYCLES); \ + } \ +} + +#define CLV() \ +{ \ + v_flag = 0; \ + ADD_CYCLES(2); \ +} + +/* C is clear when data > A */ +#define _COMPARE(reg, value) \ +{ \ + temp = (reg) - (value); \ + c_flag = ((temp & 0x100) >> 8) ^ 1; \ + SET_NZ_FLAGS((uint8) temp); \ +} + +#define CMP(cycles, read_func) \ +{ \ + read_func(data); \ + _COMPARE(A, data); \ + ADD_CYCLES(cycles); \ +} + +#define CPX(cycles, read_func) \ +{ \ + read_func(data); \ + _COMPARE(X, data); \ + ADD_CYCLES(cycles); \ +} + +#define CPY(cycles, read_func) \ +{ \ + read_func(data); \ + _COMPARE(Y, data); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define DCP(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + data--; \ + write_func(addr, data); \ + CMP(cycles, EMPTY_READ); \ +} + +#define DEC(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + data--; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define DEX() \ +{ \ + X--; \ + SET_NZ_FLAGS(X); \ + ADD_CYCLES(2); \ +} + +#define DEY() \ +{ \ + Y--; \ + SET_NZ_FLAGS(Y); \ + ADD_CYCLES(2); \ +} + +/* undocumented (double-NOP) */ +#define DOP(cycles) \ +{ \ + PC++; \ + ADD_CYCLES(cycles); \ +} + +#define EOR(cycles, read_func) \ +{ \ + read_func(data); \ + A ^= data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define INC(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + data++; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define INX() \ +{ \ + X++; \ + SET_NZ_FLAGS(X); \ + ADD_CYCLES(2); \ +} + +#define INY() \ +{ \ + Y++; \ + SET_NZ_FLAGS(Y); \ + ADD_CYCLES(2); \ +} + +/* undocumented */ +#define ISB(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + data++; \ + write_func(addr, data); \ + SBC(cycles, EMPTY_READ); \ +} + +/* TODO: make this a function callback */ +#ifdef NES6502_TESTOPS +#define JAM() \ +{ \ + cpu_Jam(); \ +} +#else /* !NES6502_TESTOPS */ +#define JAM() \ +{ \ + PC--; \ + cpu.jammed = 1; \ + cpu.int_pending = 0; \ + ADD_CYCLES(2); \ +} +#endif /* !NES6502_TESTOPS */ + +#define JMP_INDIRECT() \ +{ \ + temp = bank_readword(PC); \ + /* bug in crossing page boundaries */ \ + if (0xFF == (temp & 0xFF)) \ + PC = (bank_readbyte(temp & 0xFF00) << 8) | bank_readbyte(temp); \ + else \ + JUMP(temp); \ + ADD_CYCLES(5); \ +} + +#define JMP_ABSOLUTE() \ +{ \ + JUMP(PC); \ + ADD_CYCLES(3); \ +} + +#define JSR() \ +{ \ + PC++; \ + PUSH(PC >> 8); \ + PUSH(PC & 0xFF); \ + JUMP(PC - 1); \ + ADD_CYCLES(6); \ +} + +/* undocumented */ +#define LAS(cycles, read_func) \ +{ \ + read_func(data); \ + A = X = S = (S & data); \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define LAX(cycles, read_func) \ +{ \ + read_func(A); \ + X = A; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define LDA(cycles, read_func) \ +{ \ + read_func(A); \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define LDX(cycles, read_func) \ +{ \ + read_func(X); \ + SET_NZ_FLAGS(X);\ + ADD_CYCLES(cycles); \ +} + +#define LDY(cycles, read_func) \ +{ \ + read_func(Y); \ + SET_NZ_FLAGS(Y);\ + ADD_CYCLES(cycles); \ +} + +#define LSR(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + c_flag = data & 1; \ + data >>= 1; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define LSR_A() \ +{ \ + c_flag = A & 1; \ + A >>= 1; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(2); \ +} + +/* undocumented */ +#define LXA(cycles, read_func) \ +{ \ + read_func(data); \ + A = X = ((A | 0xEE) & data); \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define NOP() \ +{ \ + ADD_CYCLES(2); \ +} + +#define ORA(cycles, read_func) \ +{ \ + read_func(data); \ + A |= data; \ + SET_NZ_FLAGS(A);\ + ADD_CYCLES(cycles); \ +} + +#define PHA() \ +{ \ + PUSH(A); \ + ADD_CYCLES(3); \ +} + +#define PHP() \ +{ \ + /* B flag is pushed on stack as well */ \ + PUSH(COMBINE_FLAGS() | B_FLAG); \ + ADD_CYCLES(3); \ +} + +#define PLA() \ +{ \ + A = PULL(); \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(4); \ +} + +#define PLP() \ +{ \ + btemp = PULL(); \ + SCATTER_FLAGS(btemp); \ + ADD_CYCLES(4); \ +} + +/* undocumented */ +#define RLA(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + btemp = c_flag; \ + c_flag = data >> 7; \ + data = (data << 1) | btemp; \ + write_func(addr, data); \ + A &= data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +/* 9-bit rotation (carry flag used for rollover) */ +#define ROL(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + btemp = c_flag; \ + c_flag = data >> 7; \ + data = (data << 1) | btemp; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define ROL_A() \ +{ \ + btemp = c_flag; \ + c_flag = A >> 7; \ + A = (A << 1) | btemp; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(2); \ +} + +#define ROR(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + btemp = c_flag << 7; \ + c_flag = data & 1; \ + data = (data >> 1) | btemp; \ + write_func(addr, data); \ + SET_NZ_FLAGS(data); \ + ADD_CYCLES(cycles); \ +} + +#define ROR_A() \ +{ \ + btemp = c_flag << 7; \ + c_flag = A & 1; \ + A = (A >> 1) | btemp; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(2); \ +} + +/* undocumented */ +#define RRA(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + btemp = c_flag << 7; \ + c_flag = data & 1; \ + data = (data >> 1) | btemp; \ + write_func(addr, data); \ + ADC(cycles, EMPTY_READ); \ +} + +#define RTI() \ +{ \ + btemp = PULL(); \ + SCATTER_FLAGS(btemp); \ + PC = PULL(); \ + PC |= PULL() << 8; \ + ADD_CYCLES(6); \ + if (0 == i_flag && cpu.int_pending && remaining_cycles > 0) \ + { \ + cpu.int_pending = 0; \ + IRQ_PROC(); \ + ADD_CYCLES(INT_CYCLES); \ + } \ +} + +#define RTS() \ +{ \ + PC = PULL(); \ + PC = (PC | (PULL() << 8)) + 1; \ + ADD_CYCLES(6); \ +} + +/* undocumented */ +#define SAX(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + data = A & X; \ + write_func(addr, data); \ + ADD_CYCLES(cycles); \ +} + +/* Warning! NES CPU has no decimal mode, so by default this does no BCD! */ +#ifdef NES6502_DECIMAL +#define SBC(cycles, read_func) \ +{ \ + read_func(data); \ + temp = A - data - (c_flag ^ 1); \ + if (d_flag) \ + { \ + uint8 al, ah; \ + al = (A & 0x0F) - (data & 0x0F) - (c_flag ^ 1); \ + ah = (A >> 4) - (data >> 4); \ + if (al & 0x10) \ + { \ + al -= 6; \ + ah--; \ + } \ + if (ah & 0x10) \ + { \ + ah -= 6; \ + c_flag = 0; \ + } \ + else \ + { \ + c_flag = 1; \ + } \ + v_flag = (A ^ temp) & (A ^ data) & 0x80; \ + SET_NZ_FLAGS(temp & 0xFF); \ + A = (ah << 4) | (al & 0x0F); \ + } \ + else \ + { \ + v_flag = (A ^ temp) & (A ^ data) & 0x80; \ + c_flag = ((temp & 0x100) >> 8) ^ 1; \ + A = (uint8) temp; \ + SET_NZ_FLAGS(A & 0xFF); \ + } \ + ADD_CYCLES(cycles); \ +} +#else +#define SBC(cycles, read_func) \ +{ \ + read_func(data); \ + temp = A - data - (c_flag ^ 1); \ + v_flag = (A ^ data) & (A ^ temp) & 0x80; \ + c_flag = ((temp >> 8) & 1) ^ 1; \ + A = (uint8) temp; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} +#endif /* NES6502_DECIMAL */ + +/* undocumented */ +#define SBX(cycles, read_func) \ +{ \ + read_func(data); \ + temp = (A & X) - data; \ + c_flag = ((temp >> 8) & 1) ^ 1; \ + X = temp & 0xFF; \ + SET_NZ_FLAGS(X); \ + ADD_CYCLES(cycles); \ +} + +#define SEC() \ +{ \ + c_flag = 1; \ + ADD_CYCLES(2); \ +} + +#define SED() \ +{ \ + d_flag = 1; \ + ADD_CYCLES(2); \ +} + +#define SEI() \ +{ \ + i_flag = 1; \ + ADD_CYCLES(2); \ +} + +/* undocumented */ +#define SHA(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + data = A & X & ((uint8) ((addr >> 8) + 1)); \ + write_func(addr, data); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define SHS(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + S = A & X; \ + data = S & ((uint8) ((addr >> 8) + 1)); \ + write_func(addr, data); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define SHX(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + data = X & ((uint8) ((addr >> 8) + 1)); \ + write_func(addr, data); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define SHY(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + data = Y & ((uint8) ((addr >> 8 ) + 1)); \ + write_func(addr, data); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define SLO(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + c_flag = data >> 7; \ + data <<= 1; \ + write_func(addr, data); \ + A |= data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +/* undocumented */ +#define SRE(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr, data); \ + c_flag = data & 1; \ + data >>= 1; \ + write_func(addr, data); \ + A ^= data; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(cycles); \ +} + +#define STA(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + write_func(addr, A); \ + ADD_CYCLES(cycles); \ +} + +#define STX(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + write_func(addr, X); \ + ADD_CYCLES(cycles); \ +} + +#define STY(cycles, read_func, write_func, addr) \ +{ \ + read_func(addr); \ + write_func(addr, Y); \ + ADD_CYCLES(cycles); \ +} + +#define TAX() \ +{ \ + X = A; \ + SET_NZ_FLAGS(X);\ + ADD_CYCLES(2); \ +} + +#define TAY() \ +{ \ + Y = A; \ + SET_NZ_FLAGS(Y);\ + ADD_CYCLES(2); \ +} + +/* undocumented (triple-NOP) */ +#define TOP() \ +{ \ + PC += 2; \ + ADD_CYCLES(4); \ +} + +#define TSX() \ +{ \ + X = S; \ + SET_NZ_FLAGS(X);\ + ADD_CYCLES(2); \ +} + +#define TXA() \ +{ \ + A = X; \ + SET_NZ_FLAGS(A);\ + ADD_CYCLES(2); \ +} + +#define TXS() \ +{ \ + S = X; \ + ADD_CYCLES(2); \ +} + +#define TYA() \ +{ \ + A = Y; \ + SET_NZ_FLAGS(A); \ + ADD_CYCLES(2); \ +} + + + +/* internal CPU context */ +static nes6502_context cpu; +static int remaining_cycles = 0; /* so we can release timeslice */ +/* memory region pointers */ +static uint8 *ram = NULL, *stack = NULL; +static uint8 null_page[NES6502_BANKSIZE]; + + +/* +** Zero-page helper macros +*/ + +#define ZP_READBYTE(addr) ram[(addr)] +#define ZP_WRITEBYTE(addr, value) ram[(addr)] = (uint8) (value) + +#ifdef HOST_LITTLE_ENDIAN + +/* NOTE: following two functions will fail on architectures +** which do not support byte alignment +*/ +INLINE uint32 zp_readword(register uint8 address) +{ + return (uint32) (*(uint16 *)(ram + address)); +} + +INLINE uint32 bank_readword(register uint32 address) +{ + /* technically, this should fail if the address is $xFFF, but + ** any code that does this would be suspect anyway, as it would + ** be fetching a word across page boundaries, which only would + ** make sense if the banks were physically consecutive. + */ + return (uint32) (*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); +} + +#else /* !HOST_LITTLE_ENDIAN */ + +INLINE uint32 zp_readword(register uint8 address) +{ +#ifdef TARGET_CPU_PPC + return __lhbrx(ram, address); +#else /* !TARGET_CPU_PPC */ + uint32 x = (uint32) *(uint16 *)(ram + address); + return (x << 8) | (x >> 8); +#endif /* !TARGET_CPU_PPC */ +} + +INLINE uint32 bank_readword(register uint32 address) +{ +#ifdef TARGET_CPU_PPC + return __lhbrx(cpu.mem_page[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK); +#else /* !TARGET_CPU_PPC */ + uint32 x = (uint32) *(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)); + return (x << 8) | (x >> 8); +#endif /* !TARGET_CPU_PPC */ +} + +#endif /* !HOST_LITTLE_ENDIAN */ + +INLINE uint8 bank_readbyte(register uint32 address) +{ + return cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK]; +} + +INLINE void bank_writebyte(register uint32 address, register uint8 value) +{ + cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value; +} + +/* read a byte of 6502 memory */ +static uint8 mem_readbyte(uint32 address) +{ + nes6502_memread *mr; + + /* TODO: following 2 cases are N2A03-specific */ + if (address < 0x800) + { + /* RAM */ + return ram[address]; + } + else if (address >= 0x8000) + { + /* always paged memory */ + return bank_readbyte(address); + } + /* check memory range handlers */ + else + { + for (mr = cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++) + { + if (address >= mr->min_range && address <= mr->max_range) + return mr->read_func(address); + } + } + + /* return paged memory */ + return bank_readbyte(address); +} + +/* write a byte of data to 6502 memory */ +static void mem_writebyte(uint32 address, uint8 value) +{ + nes6502_memwrite *mw; + + /* RAM */ + if (address < 0x800) + { + ram[address] = value; + return; + } + /* check memory range handlers */ + else + { + for (mw = cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++) + { + if (address >= mw->min_range && address <= mw->max_range) + { + mw->write_func(address, value); + return; + } + } + } + + /* write to paged memory */ + bank_writebyte(address, value); +} + +/* set the current context */ +void nes6502_setcontext(nes6502_context *context) +{ + int loop; + + ASSERT(context); + + cpu = *context; + + /* set dead page for all pages not pointed at anything */ + for (loop = 0; loop < NES6502_NUMBANKS; loop++) + { + if (NULL == cpu.mem_page[loop]) + cpu.mem_page[loop] = null_page; + } + + ram = cpu.mem_page[0]; /* quick zero-page/RAM references */ + stack = ram + STACK_OFFSET; +} + +/* get the current context */ +void nes6502_getcontext(nes6502_context *context) +{ + int loop; + + ASSERT(context); + + *context = cpu; + + /* reset dead pages to null */ + for (loop = 0; loop < NES6502_NUMBANKS; loop++) + { + if (null_page == context->mem_page[loop]) + context->mem_page[loop] = NULL; + } +} + +/* DMA a byte of data from ROM */ +uint8 nes6502_getbyte(uint32 address) +{ + return bank_readbyte(address); +} + +/* get number of elapsed cycles */ +uint32 nes6502_getcycles(int reset_flag) +{ + uint32 cycles = cpu.total_cycles; + + if (reset_flag) + cpu.total_cycles = 0; + + return cycles; +} + +#define GET_GLOBAL_REGS() \ +{ \ + PC = cpu.pc_reg; \ + A = cpu.a_reg; \ + X = cpu.x_reg; \ + Y = cpu.y_reg; \ + SCATTER_FLAGS(cpu.p_reg); \ + S = cpu.s_reg; \ +} + +#define STORE_LOCAL_REGS() \ +{ \ + cpu.pc_reg = PC; \ + cpu.a_reg = A; \ + cpu.x_reg = X; \ + cpu.y_reg = Y; \ + cpu.p_reg = COMBINE_FLAGS(); \ + cpu.s_reg = S; \ +} + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#ifdef NES6502_JUMPTABLE + +#define OPCODE_BEGIN(xx) op##xx: +#ifdef NES6502_DISASM + +#define OPCODE_END \ + if (remaining_cycles <= 0) \ + goto end_execute; \ + log_printf(nes6502_disasm(PC, COMBINE_FLAGS(), A, X, Y, S)); \ + goto *opcode_table[bank_readbyte(PC++)]; + +#else /* !NES6520_DISASM */ + +#define OPCODE_END \ + if (remaining_cycles <= 0) \ + goto end_execute; \ + goto *opcode_table[bank_readbyte(PC++)]; + +#endif /* !NES6502_DISASM */ + +#else /* !NES6502_JUMPTABLE */ +#define OPCODE_BEGIN(xx) case 0x##xx: +#define OPCODE_END break; +#endif /* !NES6502_JUMPTABLE */ + + +/* Execute instructions until count expires +** +** Returns the number of cycles *actually* executed, which will be +** anywhere from zero to timeslice_cycles + 6 +*/ +int nes6502_execute(int timeslice_cycles) +{ + int old_cycles = cpu.total_cycles; + + uint32 temp, addr; /* for macros */ + uint8 btemp, baddr; /* for macros */ + uint8 data; + + /* flags */ + uint8 n_flag, v_flag, b_flag; + uint8 d_flag, i_flag, z_flag, c_flag; + + /* local copies of regs */ + uint32 PC; + uint8 A, X, Y, S; + +#ifdef NES6502_JUMPTABLE + + static void *opcode_table[256] = + { + &&op00, &&op01, &&op02, &&op03, &&op04, &&op05, &&op06, &&op07, + &&op08, &&op09, &&op0A, &&op0B, &&op0C, &&op0D, &&op0E, &&op0F, + &&op10, &&op11, &&op12, &&op13, &&op14, &&op15, &&op16, &&op17, + &&op18, &&op19, &&op1A, &&op1B, &&op1C, &&op1D, &&op1E, &&op1F, + &&op20, &&op21, &&op22, &&op23, &&op24, &&op25, &&op26, &&op27, + &&op28, &&op29, &&op2A, &&op2B, &&op2C, &&op2D, &&op2E, &&op2F, + &&op30, &&op31, &&op32, &&op33, &&op34, &&op35, &&op36, &&op37, + &&op38, &&op39, &&op3A, &&op3B, &&op3C, &&op3D, &&op3E, &&op3F, + &&op40, &&op41, &&op42, &&op43, &&op44, &&op45, &&op46, &&op47, + &&op48, &&op49, &&op4A, &&op4B, &&op4C, &&op4D, &&op4E, &&op4F, + &&op50, &&op51, &&op52, &&op53, &&op54, &&op55, &&op56, &&op57, + &&op58, &&op59, &&op5A, &&op5B, &&op5C, &&op5D, &&op5E, &&op5F, + &&op60, &&op61, &&op62, &&op63, &&op64, &&op65, &&op66, &&op67, + &&op68, &&op69, &&op6A, &&op6B, &&op6C, &&op6D, &&op6E, &&op6F, + &&op70, &&op71, &&op72, &&op73, &&op74, &&op75, &&op76, &&op77, + &&op78, &&op79, &&op7A, &&op7B, &&op7C, &&op7D, &&op7E, &&op7F, + &&op80, &&op81, &&op82, &&op83, &&op84, &&op85, &&op86, &&op87, + &&op88, &&op89, &&op8A, &&op8B, &&op8C, &&op8D, &&op8E, &&op8F, + &&op90, &&op91, &&op92, &&op93, &&op94, &&op95, &&op96, &&op97, + &&op98, &&op99, &&op9A, &&op9B, &&op9C, &&op9D, &&op9E, &&op9F, + &&opA0, &&opA1, &&opA2, &&opA3, &&opA4, &&opA5, &&opA6, &&opA7, + &&opA8, &&opA9, &&opAA, &&opAB, &&opAC, &&opAD, &&opAE, &&opAF, + &&opB0, &&opB1, &&opB2, &&opB3, &&opB4, &&opB5, &&opB6, &&opB7, + &&opB8, &&opB9, &&opBA, &&opBB, &&opBC, &&opBD, &&opBE, &&opBF, + &&opC0, &&opC1, &&opC2, &&opC3, &&opC4, &&opC5, &&opC6, &&opC7, + &&opC8, &&opC9, &&opCA, &&opCB, &&opCC, &&opCD, &&opCE, &&opCF, + &&opD0, &&opD1, &&opD2, &&opD3, &&opD4, &&opD5, &&opD6, &&opD7, + &&opD8, &&opD9, &&opDA, &&opDB, &&opDC, &&opDD, &&opDE, &&opDF, + &&opE0, &&opE1, &&opE2, &&opE3, &&opE4, &&opE5, &&opE6, &&opE7, + &&opE8, &&opE9, &&opEA, &&opEB, &&opEC, &&opED, &&opEE, &&opEF, + &&opF0, &&opF1, &&opF2, &&opF3, &&opF4, &&opF5, &&opF6, &&opF7, + &&opF8, &&opF9, &&opFA, &&opFB, &&opFC, &&opFD, &&opFE, &&opFF + }; + +#endif /* NES6502_JUMPTABLE */ + + remaining_cycles = timeslice_cycles; + + GET_GLOBAL_REGS(); + + /* check for DMA cycle burning */ + if (cpu.burn_cycles && remaining_cycles > 0) + { + int burn_for; + + burn_for = MIN(remaining_cycles, cpu.burn_cycles); + ADD_CYCLES(burn_for); + cpu.burn_cycles -= burn_for; + } + + if (0 == i_flag && cpu.int_pending && remaining_cycles > 0) + { + cpu.int_pending = 0; + IRQ_PROC(); + ADD_CYCLES(INT_CYCLES); + } + +#ifdef NES6502_JUMPTABLE + /* fetch first instruction */ + OPCODE_END + +#else /* !NES6502_JUMPTABLE */ + + /* Continue until we run out of cycles */ + while (remaining_cycles > 0) + { +#ifdef NES6502_DISASM + log_printf(nes6502_disasm(PC, COMBINE_FLAGS(), A, X, Y, S)); +#endif /* NES6502_DISASM */ + + /* Fetch and execute instruction */ + switch (bank_readbyte(PC++)) + { +#endif /* !NES6502_JUMPTABLE */ + + OPCODE_BEGIN(00) /* BRK */ + BRK(); + OPCODE_END + + OPCODE_BEGIN(01) /* ORA ($nn,X) */ + ORA(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(02) /* JAM */ + OPCODE_BEGIN(12) /* JAM */ + OPCODE_BEGIN(22) /* JAM */ + OPCODE_BEGIN(32) /* JAM */ + OPCODE_BEGIN(42) /* JAM */ + OPCODE_BEGIN(52) /* JAM */ + OPCODE_BEGIN(62) /* JAM */ + OPCODE_BEGIN(72) /* JAM */ + OPCODE_BEGIN(92) /* JAM */ + OPCODE_BEGIN(B2) /* JAM */ + OPCODE_BEGIN(D2) /* JAM */ + OPCODE_BEGIN(F2) /* JAM */ + JAM(); + /* kill the CPU */ + remaining_cycles = 0; + OPCODE_END + + OPCODE_BEGIN(03) /* SLO ($nn,X) */ + SLO(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(04) /* NOP $nn */ + OPCODE_BEGIN(44) /* NOP $nn */ + OPCODE_BEGIN(64) /* NOP $nn */ + DOP(3); + OPCODE_END + + OPCODE_BEGIN(05) /* ORA $nn */ + ORA(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(06) /* ASL $nn */ + ASL(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(07) /* SLO $nn */ + SLO(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(08) /* PHP */ + PHP(); + OPCODE_END + + OPCODE_BEGIN(09) /* ORA #$nn */ + ORA(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(0A) /* ASL A */ + ASL_A(); + OPCODE_END + + OPCODE_BEGIN(0B) /* ANC #$nn */ + ANC(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(0C) /* NOP $nnnn */ + TOP(); + OPCODE_END + + OPCODE_BEGIN(0D) /* ORA $nnnn */ + ORA(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(0E) /* ASL $nnnn */ + ASL(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(0F) /* SLO $nnnn */ + SLO(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(10) /* BPL $nnnn */ + BPL(); + OPCODE_END + + OPCODE_BEGIN(11) /* ORA ($nn),Y */ + ORA(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(13) /* SLO ($nn),Y */ + SLO(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(14) /* NOP $nn,X */ + OPCODE_BEGIN(34) /* NOP */ + OPCODE_BEGIN(54) /* NOP $nn,X */ + OPCODE_BEGIN(74) /* NOP $nn,X */ + OPCODE_BEGIN(D4) /* NOP $nn,X */ + OPCODE_BEGIN(F4) /* NOP ($nn,X) */ + DOP(4); + OPCODE_END + + OPCODE_BEGIN(15) /* ORA $nn,X */ + ORA(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(16) /* ASL $nn,X */ + ASL(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(17) /* SLO $nn,X */ + SLO(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(18) /* CLC */ + CLC(); + OPCODE_END + + OPCODE_BEGIN(19) /* ORA $nnnn,Y */ + ORA(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(1A) /* NOP */ + OPCODE_BEGIN(3A) /* NOP */ + OPCODE_BEGIN(5A) /* NOP */ + OPCODE_BEGIN(7A) /* NOP */ + OPCODE_BEGIN(DA) /* NOP */ + OPCODE_BEGIN(FA) /* NOP */ + NOP(); + OPCODE_END + + OPCODE_BEGIN(1B) /* SLO $nnnn,Y */ + SLO(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(1C) /* NOP $nnnn,X */ + OPCODE_BEGIN(3C) /* NOP $nnnn,X */ + OPCODE_BEGIN(5C) /* NOP $nnnn,X */ + OPCODE_BEGIN(7C) /* NOP $nnnn,X */ + OPCODE_BEGIN(DC) /* NOP $nnnn,X */ + OPCODE_BEGIN(FC) /* NOP $nnnn,X */ + TOP(); + OPCODE_END + + OPCODE_BEGIN(1D) /* ORA $nnnn,X */ + ORA(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(1E) /* ASL $nnnn,X */ + ASL(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(1F) /* SLO $nnnn,X */ + SLO(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(20) /* JSR $nnnn */ + JSR(); + OPCODE_END + + OPCODE_BEGIN(21) /* AND ($nn,X) */ + AND(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(23) /* RLA ($nn,X) */ + RLA(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(24) /* BIT $nn */ + BIT(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(25) /* AND $nn */ + AND(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(26) /* ROL $nn */ + ROL(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(27) /* RLA $nn */ + RLA(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(28) /* PLP */ + PLP(); + OPCODE_END + + OPCODE_BEGIN(29) /* AND #$nn */ + AND(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(2A) /* ROL A */ + ROL_A(); + OPCODE_END + + OPCODE_BEGIN(2B) /* ANC #$nn */ + ANC(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(2C) /* BIT $nnnn */ + BIT(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(2D) /* AND $nnnn */ + AND(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(2E) /* ROL $nnnn */ + ROL(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(2F) /* RLA $nnnn */ + RLA(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(30) /* BMI $nnnn */ + BMI(); + OPCODE_END + + OPCODE_BEGIN(31) /* AND ($nn),Y */ + AND(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(33) /* RLA ($nn),Y */ + RLA(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(35) /* AND $nn,X */ + AND(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(36) /* ROL $nn,X */ + ROL(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(37) /* RLA $nn,X */ + RLA(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(38) /* SEC */ + SEC(); + OPCODE_END + + OPCODE_BEGIN(39) /* AND $nnnn,Y */ + AND(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(3B) /* RLA $nnnn,Y */ + RLA(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(3D) /* AND $nnnn,X */ + AND(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(3E) /* ROL $nnnn,X */ + ROL(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(3F) /* RLA $nnnn,X */ + RLA(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(40) /* RTI */ + RTI(); + OPCODE_END + + OPCODE_BEGIN(41) /* EOR ($nn,X) */ + EOR(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(43) /* SRE ($nn,X) */ + SRE(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(45) /* EOR $nn */ + EOR(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(46) /* LSR $nn */ + LSR(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(47) /* SRE $nn */ + SRE(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(48) /* PHA */ + PHA(); + OPCODE_END + + OPCODE_BEGIN(49) /* EOR #$nn */ + EOR(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(4A) /* LSR A */ + LSR_A(); + OPCODE_END + + OPCODE_BEGIN(4B) /* ASR #$nn */ + ASR(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(4C) /* JMP $nnnn */ + JMP_ABSOLUTE(); + OPCODE_END + + OPCODE_BEGIN(4D) /* EOR $nnnn */ + EOR(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(4E) /* LSR $nnnn */ + LSR(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(4F) /* SRE $nnnn */ + SRE(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(50) /* BVC $nnnn */ + BVC(); + OPCODE_END + + OPCODE_BEGIN(51) /* EOR ($nn),Y */ + EOR(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(53) /* SRE ($nn),Y */ + SRE(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(55) /* EOR $nn,X */ + EOR(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(56) /* LSR $nn,X */ + LSR(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(57) /* SRE $nn,X */ + SRE(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(58) /* CLI */ + CLI(); + OPCODE_END + + OPCODE_BEGIN(59) /* EOR $nnnn,Y */ + EOR(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(5B) /* SRE $nnnn,Y */ + SRE(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(5D) /* EOR $nnnn,X */ + EOR(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(5E) /* LSR $nnnn,X */ + LSR(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(5F) /* SRE $nnnn,X */ + SRE(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(60) /* RTS */ + RTS(); + OPCODE_END + + OPCODE_BEGIN(61) /* ADC ($nn,X) */ + ADC(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(63) /* RRA ($nn,X) */ + RRA(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(65) /* ADC $nn */ + ADC(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(66) /* ROR $nn */ + ROR(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(67) /* RRA $nn */ + RRA(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(68) /* PLA */ + PLA(); + OPCODE_END + + OPCODE_BEGIN(69) /* ADC #$nn */ + ADC(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(6A) /* ROR A */ + ROR_A(); + OPCODE_END + + OPCODE_BEGIN(6B) /* ARR #$nn */ + ARR(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(6C) /* JMP ($nnnn) */ + JMP_INDIRECT(); + OPCODE_END + + OPCODE_BEGIN(6D) /* ADC $nnnn */ + ADC(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(6E) /* ROR $nnnn */ + ROR(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(6F) /* RRA $nnnn */ + RRA(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(70) /* BVS $nnnn */ + BVS(); + OPCODE_END + + OPCODE_BEGIN(71) /* ADC ($nn),Y */ + ADC(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(73) /* RRA ($nn),Y */ + RRA(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(75) /* ADC $nn,X */ + ADC(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(76) /* ROR $nn,X */ + ROR(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(77) /* RRA $nn,X */ + RRA(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(78) /* SEI */ + SEI(); + OPCODE_END + + OPCODE_BEGIN(79) /* ADC $nnnn,Y */ + ADC(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(7B) /* RRA $nnnn,Y */ + RRA(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(7D) /* ADC $nnnn,X */ + ADC(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(7E) /* ROR $nnnn,X */ + ROR(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(7F) /* RRA $nnnn,X */ + RRA(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(80) /* NOP #$nn */ + OPCODE_BEGIN(82) /* NOP #$nn */ + OPCODE_BEGIN(89) /* NOP #$nn */ + OPCODE_BEGIN(C2) /* NOP #$nn */ + OPCODE_BEGIN(E2) /* NOP #$nn */ + DOP(2); + OPCODE_END + + OPCODE_BEGIN(81) /* STA ($nn,X) */ + STA(6, INDIR_X_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(83) /* SAX ($nn,X) */ + SAX(6, INDIR_X_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(84) /* STY $nn */ + STY(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(85) /* STA $nn */ + STA(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(86) /* STX $nn */ + STX(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(87) /* SAX $nn */ + SAX(3, ZERO_PAGE_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(88) /* DEY */ + DEY(); + OPCODE_END + + OPCODE_BEGIN(8A) /* TXA */ + TXA(); + OPCODE_END + + OPCODE_BEGIN(8B) /* ANE #$nn */ + ANE(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(8C) /* STY $nnnn */ + STY(4, ABSOLUTE_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(8D) /* STA $nnnn */ + STA(4, ABSOLUTE_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(8E) /* STX $nnnn */ + STX(4, ABSOLUTE_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(8F) /* SAX $nnnn */ + SAX(4, ABSOLUTE_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(90) /* BCC $nnnn */ + BCC(); + OPCODE_END + + OPCODE_BEGIN(91) /* STA ($nn),Y */ + STA(6, INDIR_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(93) /* SHA ($nn),Y */ + SHA(6, INDIR_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(94) /* STY $nn,X */ + STY(4, ZP_IND_X_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(95) /* STA $nn,X */ + STA(4, ZP_IND_X_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(96) /* STX $nn,Y */ + STX(4, ZP_IND_Y_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(97) /* SAX $nn,Y */ + SAX(4, ZP_IND_Y_ADDR, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(98) /* TYA */ + TYA(); + OPCODE_END + + OPCODE_BEGIN(99) /* STA $nnnn,Y */ + STA(5, ABS_IND_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(9A) /* TXS */ + TXS(); + OPCODE_END + + OPCODE_BEGIN(9B) /* SHS $nnnn,Y */ + SHS(5, ABS_IND_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(9C) /* SHY $nnnn,X */ + SHY(5, ABS_IND_X_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(9D) /* STA $nnnn,X */ + STA(5, ABS_IND_X_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(9E) /* SHX $nnnn,Y */ + SHX(5, ABS_IND_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(9F) /* SHA $nnnn,Y */ + SHA(5, ABS_IND_Y_ADDR, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(A0) /* LDY #$nn */ + LDY(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A1) /* LDA ($nn,X) */ + LDA(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(A2) /* LDX #$nn */ + LDX(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A3) /* LAX ($nn,X) */ + LAX(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(A4) /* LDY $nn */ + LDY(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A5) /* LDA $nn */ + LDA(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A6) /* LDX $nn */ + LDX(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A7) /* LAX $nn */ + LAX(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(A8) /* TAY */ + TAY(); + OPCODE_END + + OPCODE_BEGIN(A9) /* LDA #$nn */ + LDA(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(AA) /* TAX */ + TAX(); + OPCODE_END + + OPCODE_BEGIN(AB) /* LXA #$nn */ + LXA(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(AC) /* LDY $nnnn */ + LDY(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(AD) /* LDA $nnnn */ + LDA(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(AE) /* LDX $nnnn */ + LDX(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(AF) /* LAX $nnnn */ + LAX(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(B0) /* BCS $nnnn */ + BCS(); + OPCODE_END + + OPCODE_BEGIN(B1) /* LDA ($nn),Y */ + LDA(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(B3) /* LAX ($nn),Y */ + LAX(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(B4) /* LDY $nn,X */ + LDY(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(B5) /* LDA $nn,X */ + LDA(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(B6) /* LDX $nn,Y */ + LDX(4, ZP_IND_Y_BYTE); + OPCODE_END + + OPCODE_BEGIN(B7) /* LAX $nn,Y */ + LAX(4, ZP_IND_Y_BYTE); + OPCODE_END + + OPCODE_BEGIN(B8) /* CLV */ + CLV(); + OPCODE_END + + OPCODE_BEGIN(B9) /* LDA $nnnn,Y */ + LDA(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(BA) /* TSX */ + TSX(); + OPCODE_END + + OPCODE_BEGIN(BB) /* LAS $nnnn,Y */ + LAS(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(BC) /* LDY $nnnn,X */ + LDY(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(BD) /* LDA $nnnn,X */ + LDA(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(BE) /* LDX $nnnn,Y */ + LDX(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(BF) /* LAX $nnnn,Y */ + LAX(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(C0) /* CPY #$nn */ + CPY(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(C1) /* CMP ($nn,X) */ + CMP(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(C3) /* DCP ($nn,X) */ + DCP(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(C4) /* CPY $nn */ + CPY(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(C5) /* CMP $nn */ + CMP(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(C6) /* DEC $nn */ + DEC(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(C7) /* DCP $nn */ + DCP(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(C8) /* INY */ + INY(); + OPCODE_END + + OPCODE_BEGIN(C9) /* CMP #$nn */ + CMP(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(CA) /* DEX */ + DEX(); + OPCODE_END + + OPCODE_BEGIN(CB) /* SBX #$nn */ + SBX(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(CC) /* CPY $nnnn */ + CPY(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(CD) /* CMP $nnnn */ + CMP(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(CE) /* DEC $nnnn */ + DEC(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(CF) /* DCP $nnnn */ + DCP(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(D0) /* BNE $nnnn */ + BNE(); + OPCODE_END + + OPCODE_BEGIN(D1) /* CMP ($nn),Y */ + CMP(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(D3) /* DCP ($nn),Y */ + DCP(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(D5) /* CMP $nn,X */ + CMP(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(D6) /* DEC $nn,X */ + DEC(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(D7) /* DCP $nn,X */ + DCP(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(D8) /* CLD */ + CLD(); + OPCODE_END + + OPCODE_BEGIN(D9) /* CMP $nnnn,Y */ + CMP(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(DB) /* DCP $nnnn,Y */ + DCP(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(DD) /* CMP $nnnn,X */ + CMP(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(DE) /* DEC $nnnn,X */ + DEC(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(DF) /* DCP $nnnn,X */ + DCP(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(E0) /* CPX #$nn */ + CPX(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(E1) /* SBC ($nn,X) */ + SBC(6, INDIR_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(E3) /* ISB ($nn,X) */ + ISB(8, INDIR_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(E4) /* CPX $nn */ + CPX(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(E5) /* SBC $nn */ + SBC(3, ZERO_PAGE_BYTE); + OPCODE_END + + OPCODE_BEGIN(E6) /* INC $nn */ + INC(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(E7) /* ISB $nn */ + ISB(5, ZERO_PAGE, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(E8) /* INX */ + INX(); + OPCODE_END + + OPCODE_BEGIN(E9) /* SBC #$nn */ + OPCODE_BEGIN(EB) /* USBC #$nn */ + SBC(2, IMMEDIATE_BYTE); + OPCODE_END + + OPCODE_BEGIN(EA) /* NOP */ + NOP(); + OPCODE_END + + OPCODE_BEGIN(EC) /* CPX $nnnn */ + CPX(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(ED) /* SBC $nnnn */ + SBC(4, ABSOLUTE_BYTE); + OPCODE_END + + OPCODE_BEGIN(EE) /* INC $nnnn */ + INC(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(EF) /* ISB $nnnn */ + ISB(6, ABSOLUTE, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(F0) /* BEQ $nnnn */ + BEQ(); + OPCODE_END + + OPCODE_BEGIN(F1) /* SBC ($nn),Y */ + SBC(5, INDIR_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(F3) /* ISB ($nn),Y */ + ISB(8, INDIR_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(F5) /* SBC $nn,X */ + SBC(4, ZP_IND_X_BYTE); + OPCODE_END + + OPCODE_BEGIN(F6) /* INC $nn,X */ + INC(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(F7) /* ISB $nn,X */ + ISB(6, ZP_IND_X, ZP_WRITEBYTE, baddr); + OPCODE_END + + OPCODE_BEGIN(F8) /* SED */ + SED(); + OPCODE_END + + OPCODE_BEGIN(F9) /* SBC $nnnn,Y */ + SBC(4, ABS_IND_Y_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(FB) /* ISB $nnnn,Y */ + ISB(7, ABS_IND_Y, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(FD) /* SBC $nnnn,X */ + SBC(4, ABS_IND_X_BYTE_READ); + OPCODE_END + + OPCODE_BEGIN(FE) /* INC $nnnn,X */ + INC(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + + OPCODE_BEGIN(FF) /* ISB $nnnn,X */ + ISB(7, ABS_IND_X, mem_writebyte, addr); + OPCODE_END + +#ifdef NES6502_JUMPTABLE +end_execute: + +#else /* !NES6502_JUMPTABLE */ + } + } +#endif /* !NES6502_JUMPTABLE */ + + /* store local copy of regs */ + STORE_LOCAL_REGS(); + + /* Return our actual amount of executed cycles */ + return (cpu.total_cycles - old_cycles); +} + +/* Issue a CPU Reset */ +void nes6502_reset(void) +{ + cpu.p_reg = Z_FLAG | R_FLAG | I_FLAG; /* Reserved bit always 1 */ + cpu.int_pending = 0; /* No pending interrupts */ + cpu.int_latency = 0; /* No latent interrupts */ + cpu.pc_reg = bank_readword(RESET_VECTOR); /* Fetch reset vector */ + cpu.burn_cycles = RESET_CYCLES; + cpu.jammed = 0; +} + +/* following macro is used for below 2 functions */ +#define DECLARE_LOCAL_REGS \ + uint32 PC; \ + uint8 A, X, Y, S; \ + uint8 n_flag, v_flag, b_flag; \ + uint8 d_flag, i_flag, z_flag, c_flag; + +/* Non-maskable interrupt */ +void nes6502_nmi(void) +{ + DECLARE_LOCAL_REGS + + if (0 == cpu.jammed) + { + GET_GLOBAL_REGS(); + NMI_PROC(); + cpu.burn_cycles += INT_CYCLES; + STORE_LOCAL_REGS(); + } +} + +/* Interrupt request */ +void nes6502_irq(void) +{ + DECLARE_LOCAL_REGS + + if (0 == cpu.jammed) + { + GET_GLOBAL_REGS(); + if (0 == i_flag) + { + IRQ_PROC(); + cpu.burn_cycles += INT_CYCLES; + } + else + { + cpu.int_pending = 1; + } + STORE_LOCAL_REGS(); + } +} + +/* Set dead cycle period */ +void nes6502_burn(int cycles) +{ + cpu.burn_cycles += cycles; +} + +/* Release our timeslice */ +void nes6502_release(void) +{ + remaining_cycles = 0; +} + +/* +** $Log: nes6502.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:39 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.34 2000/11/27 19:33:07 matt +** concise interrupts +** +** Revision 1.33 2000/11/26 15:39:54 matt +** timing fixes +** +** Revision 1.32 2000/11/20 13:22:51 matt +** added note about word fetches across page boundaries +** +** Revision 1.31 2000/11/13 00:57:39 matt +** trying to add 1-instruction interrupt latency... and failing. +** +** Revision 1.30 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.29 2000/10/10 13:05:05 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.28 2000/10/08 17:55:41 matt +** check burn cycles before ints +** +** Revision 1.27 2000/09/15 03:42:32 matt +** nes6502_release to release current timeslice +** +** Revision 1.26 2000/09/15 03:16:17 matt +** optimized C flag handling, and ADC/SBC/ROL/ROR macros +** +** Revision 1.25 2000/09/14 02:12:03 matt +** disassembling now works with goto table, and removed memcpy from context get/set +** +** Revision 1.24 2000/09/11 03:55:57 matt +** cosmetics +** +** Revision 1.23 2000/09/11 01:45:45 matt +** flag optimizations. this thing is fast! +** +** Revision 1.22 2000/09/08 13:29:25 matt +** added switch()-less execution for gcc +** +** Revision 1.21 2000/09/08 11:54:48 matt +** optimize +** +** Revision 1.20 2000/09/07 21:58:18 matt +** api change for nes6502_burn, optimized core +** +** Revision 1.19 2000/09/07 13:39:01 matt +** resolved a few conflicts +** +** Revision 1.18 2000/09/07 01:34:55 matt +** nes6502_init deprecated, moved flag regs to separate vars +** +** Revision 1.17 2000/08/31 13:26:35 matt +** added DISASM flag, to sync with asm version +** +** Revision 1.16 2000/08/29 05:38:00 matt +** removed faulty failure note +** +** Revision 1.15 2000/08/28 12:53:44 matt +** fixes for disassembler +** +** Revision 1.14 2000/08/28 04:32:28 matt +** naming convention changes +** +** Revision 1.13 2000/08/28 01:46:15 matt +** moved some of them defines around, cleaned up jamming code +** +** Revision 1.12 2000/08/16 04:56:37 matt +** accurate CPU jamming, added dead page emulation +** +** Revision 1.11 2000/07/30 04:32:00 matt +** now emulates the NES frame IRQ +** +** Revision 1.10 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.9 2000/07/11 04:27:18 matt +** new disassembler calling convention +** +** Revision 1.8 2000/07/10 05:26:38 matt +** cosmetic +** +** Revision 1.7 2000/07/06 17:10:51 matt +** minor (er, spelling) error fixed +** +** Revision 1.6 2000/07/04 04:50:07 matt +** minor change to includes +** +** Revision 1.5 2000/07/03 02:18:16 matt +** added a few notes about potential failure cases +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/vid_drv.h =================================================================== --- apps/plugins/nofrendo/vid_drv.h (revision 0) +++ apps/plugins/nofrendo/vid_drv.h (revision 0) @@ -0,0 +1,145 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** vid_drv.h +** +** Video driver +** $Id: vid_drv.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _VID_DRV_H_ +#define _VID_DRV_H_ + +#include + +typedef struct viddriver_s +{ + /* name of driver */ + const char *name; + /* init function - return 0 on success, nonzero on failure */ + int (*init)(int width, int height); + /* clean up after driver (can be NULL) */ + void (*shutdown)(void); + /* set a video mode - return 0 on success, nonzero on failure */ + int (*set_mode)(int width, int height); + /* set up a palette */ + void (*set_palette)(rgb_t *palette); + /* custom bitmap clear (can be NULL) */ + void (*clear)(uint8 color); + /* lock surface for writing (required) */ + bitmap_t *(*lock_write)(void); + /* free a locked surface (can be NULL) */ + void (*free_write)(int num_dirties, rect_t *dirty_rects); + /* custom blitter - num_dirties == -1 if full blit required */ + void (*custom_blit)(bitmap_t *primary, int num_dirties, + rect_t *dirty_rects); + /* immediately invalidate the buffer, i.e. full redraw */ + int invalidate; +} viddriver_t; + +/* TODO: filth */ +extern bitmap_t *vid_getbuffer(void); + +extern int vid_init(int width, int height, viddriver_t *osd_driver); +extern void vid_shutdown(void); + +extern int vid_setmode(int width, int height); +extern void vid_setpalette(rgb_t *pal); + +extern void vid_blit(bitmap_t *bitmap, int src_x, int src_y, int dest_x, + int dest_y, int blit_width, int blit_height); +extern void vid_flush(void); + +#endif /* _VID_DRV_H_ */ + +/* +** $Log: vid_drv.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.22 2000/11/05 22:53:13 matt +** only one video driver per system, please +** +** Revision 1.21 2000/11/05 16:37:18 matt +** rolled rgb.h into bitmap.h +** +** Revision 1.20 2000/11/05 06:23:41 matt +** thinlib spawns changes +** +** Revision 1.19 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.18 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.17 2000/08/16 02:53:04 matt +** changed init() interface a wee bit +** +** Revision 1.16 2000/07/31 04:28:47 matt +** one million cleanups +** +** Revision 1.15 2000/07/28 07:25:49 neil +** Video driver has an invalidate flag, telling vid_drv not to calculate dirties for the next frame +** +** Revision 1.14 2000/07/27 23:49:52 matt +** no more getmode +** +** Revision 1.13 2000/07/27 04:30:37 matt +** change to get_mode api +** +** Revision 1.12 2000/07/27 04:08:04 matt +** char * -> const char * +** +** Revision 1.11 2000/07/27 04:05:58 matt +** changed place where name goes +** +** Revision 1.10 2000/07/27 01:16:22 matt +** api changes for new main and dirty rects +** +** Revision 1.9 2000/07/26 21:36:14 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.8 2000/07/24 04:33:57 matt +** skeleton of dirty rectangle code in place +** +** Revision 1.7 2000/07/10 19:07:57 matt +** added custom clear() member call to video driver +** +** Revision 1.6 2000/07/10 03:04:15 matt +** removed scanlines, backbuffer from custom blit +** +** Revision 1.5 2000/07/10 01:03:20 neil +** New video scheme allows for custom blitters to be determined by the driver at runtime +** +** Revision 1.4 2000/07/09 03:34:47 matt +** temporary cleanup +** +** Revision 1.3 2000/07/07 20:17:35 matt +** better custom blitting support +** +** Revision 1.2 2000/07/07 18:11:38 neil +** Generalizing the video driver +** +** Revision 1.1 2000/07/06 16:48:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/memguard.h =================================================================== --- apps/plugins/nofrendo/memguard.h (revision 0) +++ apps/plugins/nofrendo/memguard.h (revision 0) @@ -0,0 +1,94 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** memguard.h +** +** memory allocation wrapper routines +** $Id: memguard.h,v 1.1.1.1 2001/04/27 07:03:54 neil Exp $ +*/ + +#ifndef _MEMGUARD_H_ +#define _MEMGUARD_H_ + +#ifdef strdup +#undef strdup +#endif + +#ifdef NOFRENDO_DEBUG + +#define malloc(s) _my_malloc((s), __FILE__, __LINE__) +#define free(d) _my_free((void **) &(d), __FILE__, __LINE__) +#define strdup(s) _my_strdup((s), __FILE__, __LINE__) + +extern void *_my_malloc(int size, char *file, int line); +extern void _my_free(void **data, char *file, int line); +extern char *_my_strdup(const char *string, char *file, int line); + +#else /* !NORFRENDO_DEBUG */ + +/* Non-debugging versions of calls */ +#define malloc(s) _my_malloc((s)) +#define free(d) _my_free((void **) &(d)) +#define strdup(s) _my_strdup((s)) + +extern void *_my_malloc(int size); +extern void _my_free(void **data); +extern char *_my_strdup(const char *string); + +#endif /* !NOFRENDO_DEBUG */ + + +extern void mem_cleanup(void); +extern void mem_checkblocks(void); +extern void mem_checkleaks(void); + +extern int mem_debug; + +#endif /* _MEMGUARD_H_ */ + +/* +** $Log: memguard.h,v $ +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.11 2000/10/28 03:55:46 neil +** strdup redefined, previous definition here +** +** Revision 1.10 2000/10/25 13:41:29 matt +** added strdup +** +** Revision 1.9 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.8 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.7 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.6 2000/07/06 17:20:52 matt +** block manager space itself wasn't being freed - d'oh! +** +** Revision 1.5 2000/06/26 04:54:48 matt +** simplified and made more robust +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes6502.h =================================================================== --- apps/plugins/nofrendo/nes6502.h (revision 0) +++ apps/plugins/nofrendo/nes6502.h (revision 0) @@ -0,0 +1,175 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes6502.h +** +** NES custom 6502 CPU definitions / prototypes +** $Id: nes6502.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +/* NOTE: 16-bit addresses avoided like the plague: use 32-bit values +** wherever humanly possible +*/ +#ifndef _NES6502_H_ +#define _NES6502_H_ + +#include + +/* Define this to enable decimal mode in ADC / SBC (not needed in NES) */ +/*#define NES6502_DECIMAL*/ + +#define NES6502_NUMBANKS 16 +#define NES6502_BANKSHIFT 12 +#define NES6502_BANKSIZE (0x10000 / NES6502_NUMBANKS) +#define NES6502_BANKMASK (NES6502_BANKSIZE - 1) + +/* P (flag) register bitmasks */ +#define N_FLAG 0x80 +#define V_FLAG 0x40 +#define R_FLAG 0x20 /* Reserved, always 1 */ +#define B_FLAG 0x10 +#define D_FLAG 0x08 +#define I_FLAG 0x04 +#define Z_FLAG 0x02 +#define C_FLAG 0x01 + +/* Vector addresses */ +#define NMI_VECTOR 0xFFFA +#define RESET_VECTOR 0xFFFC +#define IRQ_VECTOR 0xFFFE + +/* cycle counts for interrupts */ +#define INT_CYCLES 7 +#define RESET_CYCLES 6 + +#define NMI_MASK 0x01 +#define IRQ_MASK 0x02 + +/* Stack is located on 6502 page 1 */ +#define STACK_OFFSET 0x0100 + +typedef struct +{ + uint32 min_range, max_range; + uint8 (*read_func)(uint32 address); +} nes6502_memread; + +typedef struct +{ + uint32 min_range, max_range; + void (*write_func)(uint32 address, uint8 value); +} nes6502_memwrite; + +typedef struct +{ + uint8 *mem_page[NES6502_NUMBANKS]; /* memory page pointers */ + + nes6502_memread *read_handler; + nes6502_memwrite *write_handler; + + uint32 pc_reg; + uint8 a_reg, p_reg; + uint8 x_reg, y_reg; + uint8 s_reg; + + uint8 jammed; /* is processor jammed? */ + + uint8 int_pending, int_latency; + + int32 total_cycles, burn_cycles; +} nes6502_context; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Functions which govern the 6502's execution */ +extern void nes6502_reset(void); +extern int nes6502_execute(int total_cycles); +extern void nes6502_nmi(void); +extern void nes6502_irq(void); +extern uint8 nes6502_getbyte(uint32 address); +extern uint32 nes6502_getcycles(int reset_flag); +extern void nes6502_burn(int cycles); +extern void nes6502_release(void); + +/* Context get/set */ +extern void nes6502_setcontext(nes6502_context *cpu); +extern void nes6502_getcontext(nes6502_context *cpu); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _NES6502_H_ */ + +/* +** $Log: nes6502.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:39 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.17 2000/11/13 00:57:39 matt +** trying to add 1-instruction interrupt latency... and failing. +** +** Revision 1.16 2000/10/27 12:53:36 matt +** banks are always 4kB now +** +** Revision 1.15 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.14 2000/09/15 03:42:32 matt +** nes6502_release to release current timeslice +** +** Revision 1.13 2000/09/11 03:55:32 matt +** cosmetics +** +** Revision 1.12 2000/09/08 11:54:48 matt +** optimize +** +** Revision 1.11 2000/09/07 21:58:18 matt +** api change for nes6502_burn, optimized core +** +** Revision 1.10 2000/09/07 01:34:55 matt +** nes6502_init deprecated, moved flag regs to separate vars +** +** Revision 1.9 2000/08/28 12:53:44 matt +** fixes for disassembler +** +** Revision 1.8 2000/08/28 01:46:15 matt +** moved some of them defines around, cleaned up jamming code +** +** Revision 1.7 2000/08/16 04:56:37 matt +** accurate CPU jamming, added dead page emulation +** +** Revision 1.6 2000/07/30 04:32:00 matt +** now emulates the NES frame IRQ +** +** Revision 1.5 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/keymaps.h =================================================================== --- apps/plugins/nofrendo/keymaps.h (revision 0) +++ apps/plugins/nofrendo/keymaps.h (revision 0) @@ -0,0 +1,192 @@ +#include + +#ifdef HAVE_TOUCHSCREEN +#define NES_BUTTON_LEFT BUTTON_MIDLEFT +#define NES_BUTTON_RIGHT BUTTON_MIDRIGHT +#else +#define NES_BUTTON_LEFT BUTTON_LEFT +#define NES_BUTTON_RIGHT BUTTON_RIGHT +#endif + +#ifdef HAVE_TOUCHSCREEN +#define NES_BUTTON_UP BUTTON_TOPMIDDLE +#define NES_BUTTON_DOWN BUTTON_BOTTOMMIDDLE +#define NES_BUTTON_START BUTTON_TOPRIGHT +#define NES_BUTTON_SELECT BUTTON_CENTER +#if CONFIG_KEYPAD != COWOND2_PAD +#define NES_BUTTON_A BUTTON_BOTTOMLEFT +#define NES_BUTTON_B BUTTON_BOTTOMRIGHT +#define NES_BUTTON_MENU BUTTON_TOPLEFT +#endif +#endif + +#if CONFIG_KEYPAD == IRIVER_H100_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_ON +#define NES_BUTTON_B BUTTON_OFF +#define NES_BUTTON_START BUTTON_REC +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_MODE + +#elif CONFIG_KEYPAD == IRIVER_H300_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_REC +#define NES_BUTTON_B BUTTON_MODE +#define NES_BUTTON_START BUTTON_ON +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_OFF + +#elif CONFIG_KEYPAD == RECORDER_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_F1 +#define NES_BUTTON_B BUTTON_F2 +#define NES_BUTTON_START BUTTON_F3 +#define NES_BUTTON_SELECT BUTTON_PLAY +#define NES_BUTTON_MENU BUTTON_OFF + +#elif CONFIG_KEYPAD == IPOD_4G_PAD + +#define NES_BUTTON_UP BUTTON_MENU +#define NES_BUTTON_DOWN BUTTON_PLAY +#define NES_BUTTON_A BUTTON_NONE +#define NES_BUTTON_B BUTTON_NONE +#define NES_BUTTON_START BUTTON_SELECT +#define NES_BUTTON_SELECT BUTTON_NONE +#define NES_BUTTON_MENU (BUTTON_SELECT | BUTTON_REPEAT) + +#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_PLAY +#define NES_BUTTON_B BUTTON_EQ +#define NES_BUTTON_START BUTTON_MODE +#define NES_BUTTON_SELECT (BUTTON_SELECT | BUTTON_REL) +#define NES_BUTTON_MENU (BUTTON_SELECT | BUTTON_REPEAT) + +#elif CONFIG_KEYPAD == GIGABEAT_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_VOL_UP +#define NES_BUTTON_B BUTTON_VOL_DOWN +#define NES_BUTTON_START BUTTON_A +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_MENU + +#elif CONFIG_KEYPAD == SANSA_E200_PAD + +#define HAVE_SCROLLWHEEL +#define SCROLL_CC BUTTON_SCROLL_BACK +#define SCROLL_CW BUTTON_SCROLL_FWD +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_SELECT +#define NES_BUTTON_B BUTTON_SCROLL_BACK +#define NES_BUTTON_START BUTTON_SCROLL_FWD +#define NES_BUTTON_SELECT BUTTON_REC +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == SANSA_FUZE_PAD + +#define HAVE_SCROLLWHEEL +#define SCROLL_CC BUTTON_SCROLL_BACK +#define SCROLL_CW BUTTON_SCROLL_FWD +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_SELECT +#define NES_BUTTON_B BUTTON_HOME +#define NES_BUTTON_START BUTTON_SCROLL_BACK +#define NES_BUTTON_SELECT BUTTON_SCROLL_FWD +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == SANSA_C200_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_SELECT +#define NES_BUTTON_B BUTTON_REC +#define NES_BUTTON_START BUTTON_VOL_DOWN +#define NES_BUTTON_SELECT BUTTON_VOL_UP +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_PLAY +#define NES_BUTTON_B BUTTON_REC +#define NES_BUTTON_START BUTTON_SELECT +#define NES_BUTTON_SELECT BUTTON_NONE +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD + +#define NES_BUTTON_UP BUTTON_SCROLL_UP +#define NES_BUTTON_DOWN BUTTON_SCROLL_DOWN +#define NES_BUTTON_A BUTTON_PLAY +#define NES_BUTTON_B BUTTON_FF +#define NES_BUTTON_START BUTTON_REW +#define NES_BUTTON_SELECT BUTTON_NONE +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == MROBE500_PAD + +#define NES_BUTTON_UP BUTTON_RC_PLAY +#define NES_BUTTON_DOWN BUTTON_RC_DOWN +#define NES_BUTTON_LEFT BUTTON_RC_REW +#define NES_BUTTON_RIGHT BUTTON_RC_FF +#define NES_BUTTON_A BUTTON_RC_VOL_DOWN +#define NES_BUTTON_B BUTTON_RC_VOL_UP +#define NES_BUTTON_START BUTTON_RC_HEART +#define NES_BUTTON_SELECT BUTTON_RC_MODE +#define NES_BUTTON_MENU BUTTON_POWER + +#elif CONFIG_KEYPAD == COWOND2_PAD + +#define NES_BUTTON_A BUTTON_PLUS +#define NES_BUTTON_B BUTTON_MINUS +#define NES_BUTTON_MENU BUTTON_MENU + +#elif CONFIG_KEYPAD == GIGABEAT_S_PAD +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_VOL_UP +#define NES_BUTTON_B BUTTON_VOL_DOWN +#define NES_BUTTON_START BUTTON_PLAY +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_MENU + +#elif CONFIG_KEYPAD == CREATIVEZVM_PAD +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_CUSTOM +#define NES_BUTTON_B BUTTON_PLAY +#define NES_BUTTON_START BUTTON_BACK +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_MENU + +#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD + +#define NES_BUTTON_UP BUTTON_UP +#define NES_BUTTON_DOWN BUTTON_DOWN +#define NES_BUTTON_A BUTTON_VOL_UP +#define NES_BUTTON_B BUTTON_VOL_DOWN +#define NES_BUTTON_START BUTTON_VIEW +#define NES_BUTTON_SELECT BUTTON_SELECT +#define NES_BUTTON_MENU BUTTON_MENU + +#elif CONFIG_KEYPAD == ONDAVX747_PAD +#define NES_BUTTON_A BUTTON_VOL_UP +#define NES_BUTTON_B BUTTON_VOL_DOWN +#define NES_BUTTON_MENU BUTTON_MENU + +#else +#error No keymap defined! +#endif Index: apps/plugins/nofrendo/nes_mmc.c =================================================================== --- apps/plugins/nofrendo/nes_mmc.c (revision 0) +++ apps/plugins/nofrendo/nes_mmc.c (revision 0) @@ -0,0 +1,353 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_mmc.c +** +** NES Memory Management Controller (mapper) emulation +** $Id: nes_mmc.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include "nes6502.h" +#include +#include +#include +#include +#include +#include + +#define MMC_8KROM (mmc.cart->rom_banks * 2) +#define MMC_16KROM (mmc.cart->rom_banks) +#define MMC_32KROM (mmc.cart->rom_banks / 2) +#define MMC_8KVROM (mmc.cart->vrom_banks) +#define MMC_4KVROM (mmc.cart->vrom_banks * 2) +#define MMC_2KVROM (mmc.cart->vrom_banks * 4) +#define MMC_1KVROM (mmc.cart->vrom_banks * 8) + +#define MMC_LAST8KROM (MMC_8KROM - 1) +#define MMC_LAST16KROM (MMC_16KROM - 1) +#define MMC_LAST32KROM (MMC_32KROM - 1) +#define MMC_LAST8KVROM (MMC_8KVROM - 1) +#define MMC_LAST4KVROM (MMC_4KVROM - 1) +#define MMC_LAST2KVROM (MMC_2KVROM - 1) +#define MMC_LAST1KVROM (MMC_1KVROM - 1) + +static mmc_t mmc; + +rominfo_t *mmc_getinfo(void) +{ + return mmc.cart; +} + +void mmc_setcontext(mmc_t *src_mmc) +{ + ASSERT(src_mmc); + + mmc = *src_mmc; +} + +void mmc_getcontext(mmc_t *dest_mmc) +{ + *dest_mmc = mmc; +} + +/* VROM bankswitching */ +void mmc_bankvrom(int size, uint32 address, int bank) +{ + if (0 == mmc.cart->vrom_banks) + return; + + switch (size) + { + case 1: + if (bank == MMC_LASTBANK) + bank = MMC_LAST1KVROM; + ppu_setpage(1, address >> 10, &mmc.cart->vrom[(bank % MMC_1KVROM) << 10] - address); + break; + + case 2: + if (bank == MMC_LASTBANK) + bank = MMC_LAST2KVROM; + ppu_setpage(2, address >> 10, &mmc.cart->vrom[(bank % MMC_2KVROM) << 11] - address); + break; + + case 4: + if (bank == MMC_LASTBANK) + bank = MMC_LAST4KVROM; + ppu_setpage(4, address >> 10, &mmc.cart->vrom[(bank % MMC_4KVROM) << 12] - address); + break; + + case 8: + if (bank == MMC_LASTBANK) + bank = MMC_LAST8KVROM; + ppu_setpage(8, 0, &mmc.cart->vrom[(bank % MMC_8KVROM) << 13]); + break; + + default: + log_printf("invalid VROM bank size %d\n", size); + } +} + +/* ROM bankswitching */ +void mmc_bankrom(int size, uint32 address, int bank) +{ + nes6502_context mmc_cpu; + + nes6502_getcontext(&mmc_cpu); + + switch (size) + { + case 8: + if (bank == MMC_LASTBANK) + bank = MMC_LAST8KROM; + { + int page = address >> NES6502_BANKSHIFT; + mmc_cpu.mem_page[page] = &mmc.cart->rom[(bank % MMC_8KROM) << 13]; + mmc_cpu.mem_page[page + 1] = mmc_cpu.mem_page[page] + 0x1000; + } + + break; + + case 16: + if (bank == MMC_LASTBANK) + bank = MMC_LAST16KROM; + { + int page = address >> NES6502_BANKSHIFT; + mmc_cpu.mem_page[page] = &mmc.cart->rom[(bank % MMC_16KROM) << 14]; + mmc_cpu.mem_page[page + 1] = mmc_cpu.mem_page[page] + 0x1000; + mmc_cpu.mem_page[page + 2] = mmc_cpu.mem_page[page] + 0x2000; + mmc_cpu.mem_page[page + 3] = mmc_cpu.mem_page[page] + 0x3000; + } + break; + + case 32: + if (bank == MMC_LASTBANK) + bank = MMC_LAST32KROM; + + mmc_cpu.mem_page[8] = &mmc.cart->rom[(bank % MMC_32KROM) << 15]; + mmc_cpu.mem_page[9] = mmc_cpu.mem_page[8] + 0x1000; + mmc_cpu.mem_page[10] = mmc_cpu.mem_page[8] + 0x2000; + mmc_cpu.mem_page[11] = mmc_cpu.mem_page[8] + 0x3000; + mmc_cpu.mem_page[12] = mmc_cpu.mem_page[8] + 0x4000; + mmc_cpu.mem_page[13] = mmc_cpu.mem_page[8] + 0x5000; + mmc_cpu.mem_page[14] = mmc_cpu.mem_page[8] + 0x6000; + mmc_cpu.mem_page[15] = mmc_cpu.mem_page[8] + 0x7000; + break; + + default: + log_printf("invalid ROM bank size %d\n", size); + break; + } + + nes6502_setcontext(&mmc_cpu); +} + +/* Check to see if this mapper is supported */ +int mmc_peek(int map_num) +{ + mapintf_t **map_ptr = mappers; + + while (NULL != *map_ptr) + { + if ((*map_ptr)->number == map_num) + return 1; + map_ptr++; + } + + return 0; +} + +static void mmc_setpages(void) +{ + log_printf("setting up mapper %d\n", mmc.intf->number); + + /* Switch ROM into CPU space, set VROM/VRAM (done for ALL ROMs) */ + mmc_bankrom(16, 0x8000, 0); + mmc_bankrom(16, 0xC000, MMC_LASTBANK); + mmc_bankvrom(8, 0x0000, 0); + + if (mmc.cart->flags & ROM_FLAG_FOURSCREEN) + { + ppu_mirror(0, 1, 2, 3); + } + else + { + if (MIRROR_VERT == mmc.cart->mirror) + ppu_mirror(0, 1, 0, 1); + else + ppu_mirror(0, 0, 1, 1); + } + + /* if we have no VROM, switch in VRAM */ + /* TODO: fix this hack implementation */ + if (0 == mmc.cart->vrom_banks) + { + ASSERT(mmc.cart->vram); + + ppu_setpage(8, 0, mmc.cart->vram); + ppu_mirrorhipages(); + } +} + +/* Mapper initialization routine */ +void mmc_reset(void) +{ + mmc_setpages(); + + ppu_setlatchfunc(NULL); + ppu_setvromswitch(NULL); + + if (mmc.intf->init) + mmc.intf->init(); + + log_printf("reset memory mapper\n"); +} + + +void mmc_destroy(mmc_t **nes_mmc) +{ + if (*nes_mmc) + free(*nes_mmc); +} + +mmc_t *mmc_create(rominfo_t *rominfo) +{ + mmc_t *temp; + mapintf_t **map_ptr; + + for (map_ptr = mappers; (*map_ptr)->number != rominfo->mapper_number; map_ptr++) + { + if (NULL == *map_ptr) + return NULL; /* Should *never* happen */ + } + + temp = malloc(sizeof(mmc_t)); + if (NULL == temp) + return NULL; + + memset(temp, 0, sizeof(mmc_t)); + + temp->intf = *map_ptr; + temp->cart = rominfo; + + mmc_setcontext(temp); + + log_printf("created memory mapper: %s\n", (*map_ptr)->name); + + return temp; +} + + +/* +** $Log: nes_mmc.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.4 2000/11/21 13:28:40 matt +** take care to zero allocated mem +** +** Revision 1.3 2000/10/27 12:55:58 matt +** nes6502 now uses 4kB banks across the boards +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.28 2000/10/22 19:17:24 matt +** mapper cleanups galore +** +** Revision 1.27 2000/10/22 15:02:32 matt +** simplified mirroring +** +** Revision 1.26 2000/10/21 19:38:56 matt +** that two year old crap code *was* flushed +** +** Revision 1.25 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.24 2000/10/17 03:22:57 matt +** cleaning up rom module +** +** Revision 1.23 2000/10/10 13:58:15 matt +** stroustrup squeezing his way in the door +** +** Revision 1.22 2000/08/16 02:51:55 matt +** random cleanups +** +** Revision 1.21 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.20 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.19 2000/07/23 15:11:45 matt +** removed unused variables +** +** Revision 1.18 2000/07/15 23:50:03 matt +** migrated state get/set from nes_mmc.c to state.c +** +** Revision 1.17 2000/07/11 03:15:09 melanson +** Added support for mappers 16, 34, and 231 +** +** Revision 1.16 2000/07/10 05:27:41 matt +** cleaned up mapper-specific callbacks +** +** Revision 1.15 2000/07/10 03:02:49 matt +** minor change on loading state +** +** Revision 1.14 2000/07/06 17:38:49 matt +** replaced missing string.h include +** +** Revision 1.13 2000/07/06 02:47:11 matt +** mapper addition madness +** +** Revision 1.12 2000/07/05 05:04:15 matt +** added more mappers +** +** Revision 1.11 2000/07/04 23:12:58 matt +** brand spankin' new mapper interface implemented +** +** Revision 1.10 2000/07/04 04:56:36 matt +** modifications for new SNSS +** +** Revision 1.9 2000/06/29 14:17:18 matt +** uses snsslib now +** +** Revision 1.8 2000/06/29 03:09:24 matt +** modified to support new snss code +** +** Revision 1.7 2000/06/26 04:57:54 matt +** bugfix - irqs/mmcstate not cleared on reset +** +** Revision 1.6 2000/06/23 11:01:10 matt +** updated for new external sound interface +** +** Revision 1.5 2000/06/20 04:04:57 matt +** hacked to use new external soundchip struct +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/COPYING.LGPL =================================================================== --- apps/plugins/nofrendo/COPYING.LGPL (revision 0) +++ apps/plugins/nofrendo/COPYING.LGPL (revision 0) @@ -0,0 +1,491 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307 USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! Index: apps/plugins/nofrendo/gui_elem.c =================================================================== --- apps/plugins/nofrendo/gui_elem.c (revision 0) +++ apps/plugins/nofrendo/gui_elem.c (revision 0) @@ -0,0 +1,200 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** gui_elem.c +** +** GUI elements (font, mouse pointer, etc.) +** $Id: gui_elem.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +#define SMALL_FONT_KERN 6 +#define SMALL_FONT_HEIGHT 6 + +static fontchar_t small_data[] = +{ + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, /* space */ + { { 0x20, 0x20, 0x20, 0x00, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x50, 0x50, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x78, 0x20, 0xF0, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0xC8, 0xD0, 0x20, 0x58, 0x98, 0x00 }, SMALL_FONT_KERN }, + { { 0x40, 0xA0, 0x58, 0x90, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x40, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x40, 0x40, 0x40, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x10, 0x10, 0x10, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x50, 0x20, 0x50, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x20, 0x70, 0x20, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x00, 0x00, 0x20, 0x40, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x00, 0x70, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x08, 0x10, 0x20, 0x40, 0x80, 0x00 }, SMALL_FONT_KERN }, + + /* 0-9 */ + { { 0x70, 0x98, 0xA8, 0xC8, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x60, 0x20, 0x20, 0x20, 0xF8, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x08, 0x70, 0x80, 0xF8, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x30, 0x88, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x30, 0x50, 0x90, 0xF8, 0x10, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x80, 0x70, 0x08, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x80, 0xF0, 0x88, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x08, 0x10, 0x20, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x70, 0x88, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x78, 0x08, 0x70, 0x00 }, SMALL_FONT_KERN }, + + { { 0x00, 0x20, 0x00, 0x20, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x20, 0x00, 0x20, 0x40, 0x00 }, SMALL_FONT_KERN }, + { { 0x10, 0x20, 0x40, 0x20, 0x10, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x70, 0x00, 0x70, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x40, 0x20, 0x10, 0x20, 0x40, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x30, 0x00, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0xA8, 0xB0, 0x78, 0x00 }, SMALL_FONT_KERN }, + + /* A-Z */ + { { 0x70, 0x88, 0xF8, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0x80, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x80, 0xF8, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0xF8, 0x80, 0x80, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0xB8, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x20, 0x20, 0x20, 0xF8, 0x00 }, SMALL_FONT_KERN }, + { { 0x08, 0x08, 0x08, 0x88, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x90, 0xE0, 0x90, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x80, 0x80, 0x80, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x80, 0x80, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x88, 0x90, 0x68, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0x70, 0x08, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x20, 0x20, 0x20, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x88, 0x88, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x88, 0x50, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0xA8, 0xA8, 0xA8, 0xA8, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x50, 0x20, 0x50, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x70, 0x20, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x08, 0x70, 0x80, 0xF8, 0x00 }, SMALL_FONT_KERN }, + + { { 0x70, 0x40, 0x40, 0x40, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x80, 0x40, 0x20, 0x10, 0x08, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x10, 0x10, 0x10, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x50, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0x00, 0x00, 0x00, 0x00, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x20, 0x10, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + + /* A-Z */ + { { 0x70, 0x88, 0xF8, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0x80, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x80, 0xF8, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0xF8, 0x80, 0x80, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0xB8, 0x88, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x20, 0x20, 0x20, 0xF8, 0x00 }, SMALL_FONT_KERN }, + { { 0x08, 0x08, 0x08, 0x88, 0x70, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x90, 0xE0, 0x90, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x80, 0x80, 0x80, 0x80, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0x88, 0x88, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x80, 0x80, 0x00 }, SMALL_FONT_KERN }, + { { 0x70, 0x88, 0x88, 0x90, 0x68, 0x00 }, SMALL_FONT_KERN }, + { { 0xF0, 0x88, 0xF0, 0x88, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x78, 0x80, 0x70, 0x08, 0xF0, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x20, 0x20, 0x20, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x88, 0x88, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x88, 0x50, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0xA8, 0xA8, 0xA8, 0xA8, 0x78, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x50, 0x20, 0x50, 0x88, 0x00 }, SMALL_FONT_KERN }, + { { 0x88, 0x88, 0x70, 0x20, 0x20, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x08, 0x70, 0x80, 0xF8, 0x00 }, SMALL_FONT_KERN }, + + { { 0x10, 0x20, 0x20, 0x20, 0x10, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00 }, SMALL_FONT_KERN }, + { { 0x40, 0x20, 0x20, 0x20, 0x40, 0x00 }, SMALL_FONT_KERN }, + { { 0x50, 0xA0, 0x00, 0x00, 0x00, 0x00 }, SMALL_FONT_KERN }, + { { 0xF8, 0x88, 0x88, 0x88, 0xF8, 0x00 }, SMALL_FONT_KERN }, +}; + +font_t small = { small_data, SMALL_FONT_HEIGHT }; + +const uint8 cursor_color[] = +{ + 0, + GUI_BLACK, + GUI_WHITE, + GUI_LTGRAY, + GUI_GRAY +}; + +const uint8 cursor[] = +{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 3, 3, 1, 0, 0, 0, 0, 0, 0, + 4, 2, 3, 3, 3, 1, 0, 0, 0, 0, 0, + 4, 2, 2, 3, 3, 3, 1, 0, 0, 0, 0, + 4, 2, 2, 3, 3, 3, 3, 1, 0, 0, 0, + 4, 2, 2, 2, 3, 3, 3, 3, 1, 0, 0, + 4, 2, 2, 2, 3, 3, 3, 3, 3, 1, 0, + 4, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 4, 2, 3, 1, 2, 2, 1, 0, 0, 0, 0, + 4, 3, 1, 0, 4, 2, 3, 1, 0, 0, 0, + 4, 1, 0, 0, 4, 2, 3, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 4, 2, 3, 1, 0, 0, + 0, 0, 0, 0, 0, 4, 2, 3, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 2, 3, 1, 0, + 0, 0, 0, 0, 0, 0, 4, 3, 3, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, +}; + +/* +** $Log: gui_elem.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.8 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.7 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.6 2000/07/17 04:21:18 neil +** warning: initialization makes integer from pointer without a cast +** +** Revision 1.5 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map001.c =================================================================== --- apps/plugins/nofrendo/mappers/map001.c (revision 0) +++ apps/plugins/nofrendo/mappers/map001.c (revision 0) @@ -0,0 +1,242 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map1.c +** +** mapper 1 interface +** $Id: map001.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +/* TODO: WRAM enable ala Mark Knibbs: + ================================== +The SNROM board uses 8K CHR-RAM. The CHR-RAM is paged (i.e. it can be split +into two 4Kbyte pages). + +The CRA16 line of the MMC1 is connected to the /CS1 pin of the WRAM. THIS MEANS +THAT THE WRAM CAN BE ENABLED OR DISABLED ACCORDING TO THE STATE OF THE CRA16 +LINE. The CRA16 line corresponds to bit 4 of MMC1 registers 1 & 2. + +The WRAM is enabled when the CRA16 line is low, and disabled when CRA16 is +high. This has implications when CHR page size is 4K, if the two page numbers +set have different CRA16 states (e.g. reg 1 bit 4 = 0, reg 2 bit 4 = 1). Then +the WRAM will be enabled and disabled depending on what CHR address is being +accessed. + +When CHR page size is 8K, bit 4 of MMC1 register 1 (and not register 2, because +page size is 8K) controls whether the WRAM is enabled or not. It must be low +to be enabled. When the WRAM is disabled, reading from and writing to it will +not be possible. +*/ + +/* TODO: roll this into something... */ +static int bitcount = 0; +static uint8 latch = 0; +static uint8 regs[4]; +static int bank_select; +static uint8 lastreg; + +static void map1_write(uint32 address, uint8 value) +{ + int regnum = (address >> 13) - 4; + + if (value & 0x80) + { + regs[0] |= 0x0C; + bitcount = 0; + latch = 0; + return; + } + + if (lastreg != regnum) + { + bitcount = 0; + latch = 0; + lastreg = regnum; + } + //lastreg = regnum; + + latch |= ((value & 1) << bitcount++); + + /* 5 bit registers */ + if (5 != bitcount) + return; + + regs[regnum] = latch; + value = latch; + bitcount = 0; + latch = 0; + + switch (regnum) + { + case 0: + { + if (0 == (value & 2)) + { + int mirror = value & 1; + ppu_mirror(mirror, mirror, mirror, mirror); + } + else + { + if (value & 1) + ppu_mirror(0, 0, 1, 1); + else + ppu_mirror(0, 1, 0, 1); + } + } + break; + + case 1: + if (regs[0] & 0x10) + mmc_bankvrom(4, 0x0000, value); + else + mmc_bankvrom(8, 0x0000, value >> 1); + break; + + case 2: + if (regs[0] & 0x10) + mmc_bankvrom(4, 0x1000, value); + break; + + case 3: + if (mmc_getinfo()->rom_banks == 0x20) + { + bank_select = (regs[1] & 0x10) ? 0 : 0x10; + } + else if (mmc_getinfo()->rom_banks == 0x40) + { + if (regs[0] & 0x10) + bank_select = (regs[1] & 0x10) | ((regs[2] & 0x10) << 1); + else + bank_select = (regs[1] & 0x10) << 1; + } + else + { + bank_select = 0; + } + + if (0 == (regs[0] & 0x08)) + mmc_bankrom(32, 0x8000, ((regs[3] >> 1) + (bank_select >> 1))); + else if (regs[0] & 0x04) + mmc_bankrom(16, 0x8000, ((regs[3] & 0xF) + bank_select)); + else + mmc_bankrom(16, 0xC000, ((regs[3] & 0xF) + bank_select)); + + default: + break; + } +} + +static void map1_init(void) +{ + bitcount = 0; + latch = 0; + + memset(regs, 0, sizeof(regs)); + + if (mmc_getinfo()->rom_banks == 0x20) + mmc_bankrom(16, 0xC000, 0x0F); + + map1_write(0x8000, 0x80); +} + +static void map1_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper1.registers[0] = regs[0]; + state->extraData.mapper1.registers[1] = regs[1]; + state->extraData.mapper1.registers[2] = regs[2]; + state->extraData.mapper1.registers[3] = regs[3]; + state->extraData.mapper1.latch = latch; + state->extraData.mapper1.numberOfBits = bitcount; +} + + +static void map1_setstate(SnssMapperBlock *state) +{ + regs[1] = state->extraData.mapper1.registers[0]; + regs[1] = state->extraData.mapper1.registers[1]; + regs[2] = state->extraData.mapper1.registers[2]; + regs[3] = state->extraData.mapper1.registers[3]; + latch = state->extraData.mapper1.latch; + bitcount = state->extraData.mapper1.numberOfBits; +} + +static map_memwrite map1_memwrite[] = +{ + { 0x8000, 0xFFFF, map1_write }, + { -1, -1, NULL } +}; + +mapintf_t map1_intf = +{ + 1, /* mapper number */ + "MMC1", /* mapper name */ + map1_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + map1_getstate, /* get state (snss) */ + map1_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map1_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map001.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.8 2000/10/22 19:46:50 matt +** mirroring bugfix +** +** Revision 1.7 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.6 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map002.c =================================================================== --- apps/plugins/nofrendo/mappers/map002.c (revision 0) +++ apps/plugins/nofrendo/mappers/map002.c (revision 0) @@ -0,0 +1,86 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map2.c +** +** mapper 2 interface +** $Id: map002.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 2: UNROM */ +static void map2_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(16, 0x8000, value); +} + +static map_memwrite map2_memwrite[] = +{ + { 0x8000, 0xFFFF, map2_write }, + { -1, -1, NULL } +}; + +mapintf_t map2_intf = +{ + 2, /* mapper number */ + "UNROM", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map2_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map002.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map003.c =================================================================== --- apps/plugins/nofrendo/mappers/map003.c (revision 0) +++ apps/plugins/nofrendo/mappers/map003.c (revision 0) @@ -0,0 +1,86 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map3.c +** +** mapper 3 interface +** $Id: map003.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 3: CNROM */ +static void map3_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankvrom(8, 0x0000, value); +} + +static map_memwrite map3_memwrite[] = +{ + { 0x8000, 0xFFFF, map3_write }, + { -1, -1, NULL } +}; + +mapintf_t map3_intf = +{ + 3, /* mapper number */ + "CNROM", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map3_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map003.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map004.c =================================================================== --- apps/plugins/nofrendo/mappers/map004.c (revision 0) +++ apps/plugins/nofrendo/mappers/map004.c (revision 0) @@ -0,0 +1,269 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map4.c +** +** mapper 4 interface +** $Id: map004.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +static struct +{ + int counter, latch; + int enabled, reset; +} irq; + +static uint8 reg; +static uint8 command; +static uint16 vrombase; + +/* mapper 4: MMC3 */ +static void map4_write(uint32 address, uint8 value) +{ + switch (address & 0xE001) + { + case 0x8000: + command = value; + vrombase = (command & 0x80) ? 0x1000 : 0x0000; + + if (reg != (value & 0x40)) + { + if (value & 0x40) + mmc_bankrom(8, 0x8000, (mmc_getinfo()->rom_banks * 2) - 2); + else + mmc_bankrom(8, 0xC000, (mmc_getinfo()->rom_banks * 2) - 2); + } + reg = value & 0x40; + break; + + case 0x8001: + switch (command & 0x07) + { + case 0: + value &= 0xFE; + mmc_bankvrom(1, vrombase ^ 0x0000, value); + mmc_bankvrom(1, vrombase ^ 0x0400, value + 1); + break; + + case 1: + value &= 0xFE; + mmc_bankvrom(1, vrombase ^ 0x0800, value); + mmc_bankvrom(1, vrombase ^ 0x0C00, value + 1); + break; + + case 2: + mmc_bankvrom(1, vrombase ^ 0x1000, value); + break; + + case 3: + mmc_bankvrom(1, vrombase ^ 0x1400, value); + break; + + case 4: + mmc_bankvrom(1, vrombase ^ 0x1800, value); + break; + + case 5: + mmc_bankvrom(1, vrombase ^ 0x1C00, value); + break; + + case 6: + mmc_bankrom(8, (command & 0x40) ? 0xC000 : 0x8000, value); + break; + + case 7: + mmc_bankrom(8, 0xA000, value); + break; + } + break; + + case 0xA000: + /* four screen mirroring crap */ + if (0 == (mmc_getinfo()->flags & ROM_FLAG_FOURSCREEN)) + { + if (value & 1) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); /* vertical */ + } + break; + + case 0xA001: + /* Save RAM enable / disable */ + /* Messes up Startropics I/II if implemented -- bah */ + break; + + case 0xC000: + irq.latch = value; +// if (irq.reset) +// irq.counter = irq.latch; + break; + + case 0xC001: + irq.reset = 1; + irq.counter = irq.latch; + break; + + case 0xE000: + irq.enabled = 0; +// if (irq.reset) +// irq.counter = irq.latch; + break; + + case 0xE001: + irq.enabled = 1; +// if (irq.reset) +// irq.counter = irq.latch; + break; + + default: + break; + } + + if (1 == irq.reset) + irq.counter = irq.latch; +} + +static void map4_hblank(int vblank) +{ + if (vblank) + return; + + if (ppu_enabled()) + { + if (irq.counter >= 0) + { + irq.reset = 0; + irq.counter--; + + if (irq.counter < 0) + { + if (irq.enabled) + { + irq.reset = 1; + nes_irq(); + } + } + } + } +} + +static void map4_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper4.irqCounter = irq.counter; + state->extraData.mapper4.irqLatchCounter = irq.latch; + state->extraData.mapper4.irqCounterEnabled = irq.enabled; + state->extraData.mapper4.last8000Write = command; +} + +static void map4_setstate(SnssMapperBlock *state) +{ + irq.counter = state->extraData.mapper4.irqCounter; + irq.latch = state->extraData.mapper4.irqLatchCounter; + irq.enabled = state->extraData.mapper4.irqCounterEnabled; + command = state->extraData.mapper4.last8000Write; +} + +static void map4_init(void) +{ + irq.counter = irq.latch = 0; + irq.enabled = irq.reset = 0; + reg = command = 0; + vrombase = 0x0000; +} + +static map_memwrite map4_memwrite[] = +{ + { 0x8000, 0xFFFF, map4_write }, + { -1, -1, NULL } +}; + +mapintf_t map4_intf = +{ + 4, /* mapper number */ + "MMC3", /* mapper name */ + map4_init, /* init routine */ + NULL, /* vblank callback */ + map4_hblank, /* hblank callback */ + map4_getstate, /* get state (snss) */ + map4_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map4_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map004.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/26 15:40:49 matt +** hey, it actually works now +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.12 2000/10/23 15:53:27 matt +** suppressed warnings +** +** Revision 1.11 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.10 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.9 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.8 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.7 2000/10/08 18:05:44 matt +** kept old version around, just in case.... +** +** Revision 1.6 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.5 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.4 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.3 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.2 2000/07/05 05:04:39 matt +** minor modifications +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map040.c =================================================================== --- apps/plugins/nofrendo/mappers/map040.c (revision 0) +++ apps/plugins/nofrendo/mappers/map040.c (revision 0) @@ -0,0 +1,163 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map40.c +** +** mapper 40 interface +** $Id: map040.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + +#define MAP40_IRQ_PERIOD (4096 / 113.666666) + +static struct +{ + int enabled, counter; +} irq; + +/* mapper 40: SMB 2j (hack) */ +static void map40_init(void) +{ + mmc_bankrom(8, 0x6000, 6); + mmc_bankrom(8, 0x8000, 4); + mmc_bankrom(8, 0xA000, 5); + mmc_bankrom(8, 0xE000, 7); + + irq.enabled = 0; + irq.counter = (int) MAP40_IRQ_PERIOD; +} + +static void map40_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.enabled && irq.counter) + { + irq.counter--; + if (0 == irq.counter) + { + nes_irq(); + irq.enabled = 0; + } + } +} + +static void map40_write(uint32 address, uint8 value) +{ + int range = (address >> 13) - 4; + + switch (range) + { + case 0: /* 0x8000-0x9FFF */ + irq.enabled = 0; + irq.counter = (int) MAP40_IRQ_PERIOD; + break; + + case 1: /* 0xA000-0xBFFF */ + irq.enabled = 1; + break; + + case 3: /* 0xE000-0xFFFF */ + mmc_bankrom(8, 0xC000, value & 7); + break; + + default: + break; + } +} + +static void map40_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper40.irqCounter = irq.counter; + state->extraData.mapper40.irqCounterEnabled = irq.enabled; +} + +static void map40_setstate(SnssMapperBlock *state) +{ + irq.counter = state->extraData.mapper40.irqCounter; + irq.enabled = state->extraData.mapper40.irqCounterEnabled; +} + +static map_memwrite map40_memwrite[] = +{ + { 0x8000, 0xFFFF, map40_write }, + { -1, -1, NULL } +}; + +mapintf_t map40_intf = +{ + 40, /* mapper number */ + "SMB 2j (pirate)", /* mapper name */ + map40_init, /* init routine */ + NULL, /* vblank callback */ + map40_hblank, /* hblank callback */ + map40_getstate, /* get state (snss) */ + map40_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map40_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map040.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.9 2000/10/23 15:53:27 matt +** suppressed warnings +** +** Revision 1.8 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.7 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.6 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.5 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.4 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.3 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map005.c =================================================================== --- apps/plugins/nofrendo/mappers/map005.c (revision 0) +++ apps/plugins/nofrendo/mappers/map005.c (revision 0) @@ -0,0 +1,326 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map5.c +** +** mapper 5 interface +** $Id: map005.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + +/* TODO: there's lots of info about this mapper now; +** let's implement it correctly/completely +*/ + +static struct +{ + int counter, enabled; + int reset, latch; +} irq; + +/* MMC5 - Castlevania III, etc */ +static void map5_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.counter == nes_getcontextptr()->scanline) + { + if (1 == irq.enabled) + { + nes_irq(); + irq.reset = 1; + } + //else + // irq.reset = 0; + irq.counter = irq.latch; + } +} + +static void map5_write(uint32 address, uint8 value) +{ + static int page_size = 8; + + /* ex-ram memory-- bleh! */ + if (address >= 0x5C00 && address <= 0x5FFF) + return; + + switch (address) + { + case 0x5100: + /* PRG page size setting */ + /* 0:32k 1:16k 2,3:8k */ + switch (value & 3) + { + case 0: + page_size = 32; + break; + + case 1: + page_size = 16; + break; + + case 2: + case 3: + page_size = 8; + break; + } + break; + + case 0x5101: + /* CHR page size setting */ + /* 0:8k 1:4k 2:2k 3:1k */ + break; + + case 0x5104: + /* GFX mode setting */ + /* + 00:split mode + 01:split & exgraffix + 10:ex-ram + 11:exram + write protect + */ + break; + + case 0x5105: + /* TODO: exram needs to fill in nametables 2-3 */ + ppu_mirror(value & 3, (value >> 2) & 3, (value >> 4) & 3, value >> 6); + break; + + case 0x5106: + case 0x5107: + /* ex-ram fill mode stuff */ + break; + + case 0x5113: + /* ram page for $6000-7FFF? bit 2*/ + break; + + case 0x5114: + mmc_bankrom(8, 0x8000, value); + //if (page_size == 8) + // mmc_bankrom(8, 0x8000, value); + break; + + case 0x5115: + mmc_bankrom(8, 0x8000, value); + mmc_bankrom(8, 0xA000, value + 1); + //if (page_size == 8) + // mmc_bankrom(8, 0xA000, value); + //else if (page_size == 16) + // mmc_bankrom(16, 0x8000, value >> 1); + //mmc_bankrom(16, 0x8000, value & 0xFE); + break; + + case 0x5116: + mmc_bankrom(8, 0xC000, value); + //if (page_size == 8) + // mmc_bankrom(8, 0xC000, value); + break; + + case 0x5117: + //if (page_size == 8) + // mmc_bankrom(8, 0xE000, value); + //else if (page_size == 16) + // mmc_bankrom(16, 0xC000, value >> 1); + //mmc_bankrom(16, 0xC000, value & 0xFE); + //else if (page_size == 32) + // mmc_bankrom(32, 0x8000, value >> 2); + //mmc_bankrom(32, 0x8000, value & 0xFC); + break; + + case 0x5120: + mmc_bankvrom(1, 0x0000, value); + break; + + case 0x5121: + mmc_bankvrom(1, 0x0400, value); + break; + + case 0x5122: + mmc_bankvrom(1, 0x0800, value); + break; + + case 0x5123: + mmc_bankvrom(1, 0x0C00, value); + break; + + case 0x5124: + case 0x5125: + case 0x5126: + case 0x5127: + /* more VROM shit? */ + break; + + case 0x5128: + mmc_bankvrom(1, 0x1000, value); + break; + + case 0x5129: + mmc_bankvrom(1, 0x1400, value); + break; + + case 0x512A: + mmc_bankvrom(1, 0x1800, value); + break; + + case 0x512B: + mmc_bankvrom(1, 0x1C00, value); + break; + + case 0x5203: + irq.counter = value; + irq.latch = value; +// irq.reset = 0; + break; + + case 0x5204: + irq.enabled = (value & 0x80) ? 1 : 0; +// irq.reset = 0; + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("unknown mmc5 write: $%02X to $%04X\n", value, address); +#endif /* NOFRENDO_DEBUG */ + break; + } +} + +static uint8 map5_read(uint32 address) +{ + /* Castlevania 3 IRQ counter */ + if (address == 0x5204) + { + /* if reset == 1, we've hit scanline */ + return (irq.reset ? 0x40 : 0x00); + } + else + { +#ifdef NOFRENDO_DEBUG + log_printf("invalid MMC5 read: $%04X", address); +#endif + return 0xFF; + } +} + +static void map5_init(void) +{ + mmc_bankrom(8, 0x8000, MMC_LASTBANK); + mmc_bankrom(8, 0xA000, MMC_LASTBANK); + mmc_bankrom(8, 0xC000, MMC_LASTBANK); + mmc_bankrom(8, 0xE000, MMC_LASTBANK); + + irq.counter = irq.enabled = 0; + irq.reset = irq.latch = 0; +} + +/* incomplete SNSS definition */ +static void map5_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper5.dummy = 0; +} + +static void map5_setstate(SnssMapperBlock *state) +{ + UNUSED(state); +} + +static map_memwrite map5_memwrite[] = +{ + /* $5000 - $5015 handled by sound */ + { 0x5016, 0x5FFF, map5_write }, + { 0x8000, 0xFFFF, map5_write }, + { -1, -1, NULL } +}; + +static map_memread map5_memread[] = +{ + { 0x5204, 0x5204, map5_read }, + { -1, -1, NULL } +}; + +mapintf_t map5_intf = +{ + 5, /* mapper number */ + "MMC5", /* mapper name */ + map5_init, /* init routine */ + NULL, /* vblank callback */ + map5_hblank, /* hblank callback */ + map5_getstate, /* get state (snss) */ + map5_setstate, /* set state (snss) */ + map5_memread, /* memory read structure */ + map5_memwrite, /* memory write structure */ + &mmc5_ext /* external sound device */ +}; +/* +** $Log: map005.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/25 20:32:33 matt +** scanline interface change +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.11 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.10 2000/10/21 19:33:37 matt +** many more cleanups +** +** Revision 1.9 2000/10/17 03:23:16 matt +** added mmc5 sound interface +** +** Revision 1.8 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.7 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.6 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.5 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.4 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.3 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.2 2000/07/05 05:04:51 matt +** fixed h-blank callback +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map041.c =================================================================== --- apps/plugins/nofrendo/mappers/map041.c (revision 0) +++ apps/plugins/nofrendo/mappers/map041.c (revision 0) @@ -0,0 +1,167 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map041.c +** +** Mapper #41 (Caltron 6 in 1) +** Implementation by Firebug +** Mapper information courtesy of Kevin Horton +** $Id: map041.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +static uint8 register_low; +static uint8 register_high; + +/*****************************************************/ +/* Set 8K CHR bank from the combined register values */ +/*****************************************************/ +static void map41_set_chr (void) +{ + /* Set the CHR bank from the appropriate register bits */ + mmc_bankvrom (8, 0x0000, ((register_low >> 1) & 0x0C) | (register_high)); + + /* Done */ + return; +} + +/******************************/ +/* Mapper #41: Caltron 6 in 1 */ +/******************************/ +static void map41_init (void) +{ + /* Both registers set to zero at power on */ + /* TODO: Registers should also be cleared on a soft reset */ + register_low = 0x00; + register_high = 0x00; + mmc_bankrom (32, 0x8000, 0x00); + map41_set_chr (); + + /* Done */ + return; +} + +/******************************************/ +/* Mapper #41 write handler ($6000-$67FF) */ +/******************************************/ +static void map41_low_write (uint32 address, uint8 value) +{ + /* Within this range the value written is irrelevant */ + UNUSED (value); + + /* $6000-$67FF: A5 = mirroring (1=horizontal, 0=vertical) */ + /* A4-A3 = high two bits of 8K CHR bank */ + /* A2 = register 1 enable (0=disabled, 1=enabled) */ + /* A2-A0 = 32K PRG bank */ + register_low = (uint8) (address & 0x3F); + mmc_bankrom (32, 0x8000, register_low & 0x07); + map41_set_chr (); + if (register_low & 0x20) ppu_mirror(0, 0, 1, 1); /* horizontal */ + else ppu_mirror(0, 1, 0, 1); /* vertical */ + + /* Done */ + return; +} + +/******************************************/ +/* Mapper #41 write handler ($8000-$FFFF) */ +/******************************************/ +static void map41_high_write (uint32 address, uint8 value) +{ + /* Address doesn't matter within this range */ + UNUSED (address); + + /* $8000-$FFFF: D1-D0 = low two bits of 8K CHR bank */ + if (register_low & 0x04) + { + register_high = value & 0x03; + map41_set_chr (); + } + + /* Done */ + return; +} + +/****************************************************/ +/* Shove extra mapper information into a SNSS block */ +/****************************************************/ +static void map41_setstate (SnssMapperBlock *state) +{ + /* TODO: Store SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +/*****************************************************/ +/* Pull extra mapper information out of a SNSS block */ +/*****************************************************/ +static void map41_getstate (SnssMapperBlock *state) +{ + /* TODO: Retrieve SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +static map_memwrite map41_memwrite [] = +{ + { 0x6000, 0x67FF, map41_low_write }, + { 0x8000, 0xFFFF, map41_high_write }, + { -1, -1, NULL } +}; + +mapintf_t map41_intf = +{ + 41, /* Mapper number */ + "Caltron 6 in 1", /* Mapper name */ + map41_init, /* Initialization routine */ + NULL, /* VBlank callback */ + NULL, /* HBlank callback */ + map41_getstate, /* Get state (SNSS) */ + map41_setstate, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map41_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map041.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/30 00:33:15 firebug +** initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map024.c =================================================================== --- apps/plugins/nofrendo/mappers/map024.c (revision 0) +++ apps/plugins/nofrendo/mappers/map024.c (revision 0) @@ -0,0 +1,235 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map24.c +** +** mapper 24 interface +** $Id: map024.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + +static struct +{ + int counter, enabled; + int latch, wait_state; +} irq; + +static void map24_init(void) +{ + irq.counter = irq.enabled = 0; + irq.latch = irq.wait_state = 0; +} + +static void map24_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.enabled) + { + if (256 == ++irq.counter) + { + irq.counter = irq.latch; + nes_irq(); + //irq.enabled = 0; + irq.enabled = irq.wait_state; + } + } +} + +static void map24_write(uint32 address, uint8 value) +{ + switch (address & 0xF003) + { + case 0x8000: + mmc_bankrom(16, 0x8000, value); + break; + + case 0x9003: + /* ??? */ + break; + + case 0xB003: + switch (value & 0x0C) + { + case 0x00: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 0x04: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 0x08: + ppu_mirror(0, 0, 0, 0); + break; + + case 0x0C: + ppu_mirror(1, 1, 1, 1); + break; + + default: + break; + } + break; + + + case 0xC000: + mmc_bankrom(8, 0xC000, value); + break; + + case 0xD000: + mmc_bankvrom(1, 0x0000, value); + break; + + case 0xD001: + mmc_bankvrom(1, 0x0400, value); + break; + + case 0xD002: + mmc_bankvrom(1, 0x0800, value); + break; + + case 0xD003: + mmc_bankvrom(1, 0x0C00, value); + break; + + case 0xE000: + mmc_bankvrom(1, 0x1000, value); + break; + + case 0xE001: + mmc_bankvrom(1, 0x1400, value); + break; + + case 0xE002: + mmc_bankvrom(1, 0x1800, value); + break; + + case 0xE003: + mmc_bankvrom(1, 0x1C00, value); + break; + + case 0xF000: + irq.latch = value; + break; + + case 0xF001: + irq.enabled = (value >> 1) & 0x01; + irq.wait_state = value & 0x01; + if (irq.enabled) + irq.counter = irq.latch; + break; + + case 0xF002: + irq.enabled = irq.wait_state; + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("invalid VRC6 write: $%02X to $%04X", value, address); +#endif + break; + } +} + +static void map24_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper24.irqCounter = irq.counter; + state->extraData.mapper24.irqCounterEnabled = irq.enabled; +} + +static void map24_setstate(SnssMapperBlock *state) +{ + irq.counter = state->extraData.mapper24.irqCounter; + irq.enabled = state->extraData.mapper24.irqCounterEnabled; +} + +static map_memwrite map24_memwrite[] = +{ + { 0x8000, 0xF002, map24_write }, + { -1, -1, NULL } +}; + +mapintf_t map24_intf = +{ + 24, /* mapper number */ + "Konami VRC6", /* mapper name */ + map24_init, /* init routine */ + NULL, /* vblank callback */ + map24_hblank, /* hblank callback */ + map24_getstate, /* get state (snss) */ + map24_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map24_memwrite, /* memory write structure */ + &vrcvi_ext /* external sound device */ +}; + +/* +** $Log: map024.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.11 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.10 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.9 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.8 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.7 2000/10/09 12:00:53 matt +** removed old code +** +** Revision 1.6 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.5 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.4 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map042.c =================================================================== --- apps/plugins/nofrendo/mappers/map042.c (revision 0) +++ apps/plugins/nofrendo/mappers/map042.c (revision 0) @@ -0,0 +1,188 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map042.c +** +** Mapper #42 (Baby Mario bootleg) +** Implementation by Firebug +** Mapper information courtesy of Kevin Horton +** $Id: map042.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +static struct +{ + int enabled; + uint32 counter; +} irq; + +/********************************/ +/* Mapper #42 IRQ reset routine */ +/********************************/ +static void map42_irq_reset (void) +{ + /* Turn off IRQs */ + irq.enabled = 0; + irq.counter = 0x0000; + + /* Done */ + return; +} + +/********************************************/ +/* Mapper #42: Baby Mario bootleg cartridge */ +/********************************************/ +static void map42_init (void) +{ + /* Set the hardwired pages */ + mmc_bankrom (8, 0x8000, 0x0C); + mmc_bankrom (8, 0xA000, 0x0D); + mmc_bankrom (8, 0xC000, 0x0E); + mmc_bankrom (8, 0xE000, 0x0F); + + /* Reset the IRQ counter */ + map42_irq_reset (); + + /* Done */ + return; +} + +/****************************************/ +/* Mapper #42 callback for IRQ handling */ +/****************************************/ +static void map42_hblank (int vblank) +{ + /* Counter is M2 based so it doesn't matter whether */ + /* the PPU is in its VBlank period or not */ + UNUSED(vblank); + + /* Increment the counter if it is enabled and check for strike */ + if (irq.enabled) + { + /* Is there a constant for cycles per scanline? */ + /* If so, someone ought to substitute it here */ + irq.counter = irq.counter + 114; + + /* IRQ is triggered after 24576 M2 cycles */ + if (irq.counter >= 0x6000) + { + /* Trigger the IRQ */ + nes_irq (); + + /* Reset the counter */ + map42_irq_reset (); + } + } +} + +/******************************************/ +/* Mapper #42 write handler ($E000-$FFFF) */ +/******************************************/ +static void map42_write (uint32 address, uint8 value) +{ + switch (address & 0x03) + { + /* Register 0: Select ROM page at $6000-$7FFF */ + case 0x00: mmc_bankrom (8, 0x6000, value & 0x0F); + break; + + /* Register 1: mirroring */ + case 0x01: if (value & 0x08) ppu_mirror(0, 0, 1, 1); /* horizontal */ + else ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + /* Register 2: IRQ */ + case 0x02: if (value & 0x02) irq.enabled = 1; + else map42_irq_reset (); + break; + + /* Register 3: unused */ + default: break; + } + + /* Done */ + return; +} + +/****************************************************/ +/* Shove extra mapper information into a SNSS block */ +/****************************************************/ +static void map42_setstate (SnssMapperBlock *state) +{ + /* TODO: Store SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +/*****************************************************/ +/* Pull extra mapper information out of a SNSS block */ +/*****************************************************/ +static void map42_getstate (SnssMapperBlock *state) +{ + /* TODO: Retrieve SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +static map_memwrite map42_memwrite [] = +{ + { 0xE000, 0xFFFF, map42_write }, + { -1, -1, NULL } +}; + +mapintf_t map42_intf = +{ + 42, /* Mapper number */ + "Baby Mario (bootleg)", /* Mapper name */ + map42_init, /* Initialization routine */ + NULL, /* VBlank callback */ + map42_hblank, /* HBlank callback */ + map42_getstate, /* Get state (SNSS) */ + map42_setstate, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map42_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map042.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/27 19:23:30 firebug +** initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map160.c =================================================================== --- apps/plugins/nofrendo/mappers/map160.c (revision 0) +++ apps/plugins/nofrendo/mappers/map160.c (revision 0) @@ -0,0 +1,140 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map160.c +** +** mapper 160 interface +** $Id: map160.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +static struct +{ + int enabled, expired; + int counter; + int latch_c005, latch_c003; +} irq; + +static void map160_write(uint32 address, uint8 value) +{ + if (address >= 0x8000 && address <= 0x8003) + { + mmc_bankrom(8, 0x8000 + 0x2000 * (address & 3), value); + } + else if (address >= 0x9000 && address <= 0x9007) + { + mmc_bankvrom(1, 0x400 * (address & 7), value); + } + else if (0xC002 == address) + { + irq.enabled = 0; + irq.latch_c005 = irq.latch_c003; + } + else if (0xC003 == address) + { + if (0 == irq.expired) + { + irq.counter = value; + } + else + { + irq.expired = 0; + irq.enabled = 1; + irq.counter = irq.latch_c005; + } + } + else if (0xC005 == address) + { + irq.latch_c005 = value; + irq.counter = value; + } +#ifdef NOFRENDO_DEBUG + else + { + log_printf("mapper 160: untrapped write $%02X to $%04X\n", value, address); + } +#endif /* NOFRENDO_DEBUG */ +} + +static void map160_hblank(int vblank) +{ + if (!vblank) + { + if (ppu_enabled() && irq.enabled) + { + if (0 == irq.counter && 0 == irq.expired) + { + irq.expired = 1; + nes_irq(); + } + else + { + irq.counter--; + } + } + } +} + +static void map160_init(void) +{ + irq.enabled = 0; + irq.expired = 0; + irq.counter = 0; + irq.latch_c003 = irq.latch_c005 = 0; +} + +static map_memwrite map160_memwrite[] = +{ + { 0x8000, 0xFFFF, map160_write }, + { -1, -1, NULL } +}; + +mapintf_t map160_intf = +{ + 160, /* mapper number */ + "Aladdin (pirate)", /* mapper name */ + map160_init, /* init routine */ + NULL, /* vblank callback */ + map160_hblank, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map160_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map160.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/27 04:24:46 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map007.c =================================================================== --- apps/plugins/nofrendo/mappers/map007.c (revision 0) +++ apps/plugins/nofrendo/mappers/map007.c (revision 0) @@ -0,0 +1,99 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map7.c +** +** mapper 7 interface +** $Id: map007.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +/* mapper 7: AOROM */ +static void map7_write(uint32 address, uint8 value) +{ + int mirror; + UNUSED(address); + + mmc_bankrom(32, 0x8000, value); + mirror = (value & 0x10) >> 4; + ppu_mirror(mirror, mirror, mirror, mirror); +} + +static void map7_init(void) +{ + mmc_bankrom(32, 0x8000, 0); +} + +static map_memwrite map7_memwrite[] = +{ + { 0x8000, 0xFFFF, map7_write }, + { -1, -1, NULL } +}; + +mapintf_t map7_intf = +{ + 7, /* mapper number */ + "AOROM", /* mapper name */ + map7_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map7_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map007.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map008.c =================================================================== --- apps/plugins/nofrendo/mappers/map008.c (revision 0) +++ apps/plugins/nofrendo/mappers/map008.c (revision 0) @@ -0,0 +1,94 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map8.c +** +** mapper 8 interface +** $Id: map008.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 8: FFE F3xxx -- what the hell uses this? */ +static void map8_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(16, 0x8000, value >> 3); + mmc_bankvrom(8, 0x0000, value & 7); +} + +static void map8_init(void) +{ + mmc_bankrom(16, 0x8000, 0); + mmc_bankrom(16, 0xC000, 1); + mmc_bankvrom(8, 0x0000, 0); +} + +static map_memwrite map8_memwrite[] = +{ + { 0x8000, 0xFFFF, map8_write }, + { -1, -1, NULL } +}; + +mapintf_t map8_intf = +{ + 8, /* mapper number */ + "FFE F3xxx", /* mapper name */ + map8_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map8_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map008.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:47 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map009.c =================================================================== --- apps/plugins/nofrendo/mappers/map009.c (revision 0) +++ apps/plugins/nofrendo/mappers/map009.c (revision 0) @@ -0,0 +1,199 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map9.c +** +** mapper 9 interface +** $Id: map009.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + +static uint8 latch[2]; +static uint8 regs[4]; + +/* Used when tile $FD/$FE is accessed */ +static void mmc9_latchfunc(uint32 address, uint8 value) +{ + if (0xFD == value || 0xFE == value) + { + int reg; + + if (address) + { + latch[1] = value; + reg = 2 + (value - 0xFD); + } + else + { + latch[0] = value; + reg = value - 0xFD; + } + + mmc_bankvrom(4, address, regs[reg]); + } +} + +/* mapper 9: MMC2 */ +/* MMC2: Punch-Out! */ +static void map9_write(uint32 address, uint8 value) +{ + switch ((address & 0xF000) >> 12) + { + case 0xA: + mmc_bankrom(8, 0x8000, value); + break; + + case 0xB: + regs[0] = value; + if (0xFD == latch[0]) + mmc_bankvrom(4, 0x0000, value); + break; + + case 0xC: + regs[1] = value; + if (0xFE == latch[0]) + mmc_bankvrom(4, 0x0000, value); + break; + + case 0xD: + regs[2] = value; + if (0xFD == latch[1]) + mmc_bankvrom(4, 0x1000, value); + break; + + case 0xE: + regs[3] = value; + if (0xFE == latch[1]) + mmc_bankvrom(4, 0x1000, value); + break; + + case 0xF: + if (value & 1) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + default: + break; + } +} + +static void map9_init(void) +{ + memset(regs, 0, sizeof(regs)); + + mmc_bankrom(8, 0x8000, 0); + mmc_bankrom(8, 0xA000, (mmc_getinfo()->rom_banks * 2) - 3); + mmc_bankrom(8, 0xC000, (mmc_getinfo()->rom_banks * 2) - 2); + mmc_bankrom(8, 0xE000, (mmc_getinfo()->rom_banks * 2) - 1); + + latch[0] = 0xFE; + latch[1] = 0xFE; + + ppu_setlatchfunc(mmc9_latchfunc); +} + +static void map9_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper9.latch[0] = latch[0]; + state->extraData.mapper9.latch[1] = latch[1]; + state->extraData.mapper9.lastB000Write = regs[0]; + state->extraData.mapper9.lastC000Write = regs[1]; + state->extraData.mapper9.lastD000Write = regs[2]; + state->extraData.mapper9.lastE000Write = regs[3]; +} + +static void map9_setstate(SnssMapperBlock *state) +{ + latch[0] = state->extraData.mapper9.latch[0]; + latch[1] = state->extraData.mapper9.latch[1]; + regs[0] = state->extraData.mapper9.lastB000Write; + regs[1] = state->extraData.mapper9.lastC000Write; + regs[2] = state->extraData.mapper9.lastD000Write; + regs[3] = state->extraData.mapper9.lastE000Write; +} + +static map_memwrite map9_memwrite[] = +{ + { 0x8000, 0xFFFF, map9_write }, + { -1, -1, NULL } +}; + +mapintf_t map9_intf = +{ + 9, /* mapper number */ + "MMC2", /* mapper name */ + map9_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + map9_getstate, /* get state (snss) */ + map9_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map9_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map009.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.9 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.8 2000/10/22 15:03:14 matt +** simplified mirroring +** +** Revision 1.7 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.6 2000/07/17 05:11:35 matt +** minor update from making PPU code less filthy +** +** Revision 1.5 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.4 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.3 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.2 2000/07/05 22:50:33 matt +** fixed punchout -- works 100% now +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map064.c =================================================================== --- apps/plugins/nofrendo/mappers/map064.c (revision 0) +++ apps/plugins/nofrendo/mappers/map064.c (revision 0) @@ -0,0 +1,234 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map64.c +** +** mapper 64 interface +** $Id: map064.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +static struct +{ + int counter, latch; + int enabled, reset; +} irq; + +static uint8 command = 0; +static uint16 vrombase = 0x0000; + +static void map64_hblank(int vblank) +{ + if (vblank) + return; + + irq.reset = 0; + + if (ppu_enabled()) + { + if (0 == irq.counter--) + { + irq.counter = irq.latch; + + if (1 == irq.enabled) + nes_irq(); + + irq.reset = 1; + } + } +} + +/* mapper 64: Tengen RAMBO-1 */ +static void map64_write(uint32 address, uint8 value) +{ + switch (address & 0xE001) + { + case 0x8000: + command = value; + vrombase = (value & 0x80) ? 0x1000 : 0x0000; + break; + + case 0x8001: + switch (command & 0xF) + { + case 0: + mmc_bankvrom(1, 0x0000 ^ vrombase, value); + mmc_bankvrom(1, 0x0400 ^ vrombase, value); + break; + + case 1: + mmc_bankvrom(1, 0x0800 ^ vrombase, value); + mmc_bankvrom(1, 0x0C00 ^ vrombase, value); + break; + + case 2: + mmc_bankvrom(1, 0x1000 ^ vrombase, value); + break; + + case 3: + mmc_bankvrom(1, 0x1400 ^ vrombase, value); + break; + + case 4: + mmc_bankvrom(1, 0x1800 ^ vrombase, value); + break; + + case 5: + mmc_bankvrom(1, 0x1C00 ^ vrombase, value); + break; + + case 6: + mmc_bankrom(8, (command & 0x40) ? 0xA000 : 0x8000, value); + break; + + case 7: + mmc_bankrom(8, (command & 0x40) ? 0xC000 : 0xA000, value); + break; + + case 8: + mmc_bankvrom(1, 0x0400, value); + break; + + case 9: + mmc_bankvrom(1, 0x0C00, value); + break; + + case 15: + mmc_bankrom(8, (command & 0x40) ? 0x8000 : 0xC000, value); + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("mapper 64: unknown command #%d", command & 0xF); +#endif + break; + } + break; + + case 0xA000: + if (value & 1) + ppu_mirror(0, 0, 1, 1); + else + ppu_mirror(0, 1, 0, 1); + break; + + case 0xC000: + //irq.counter = value; + irq.latch = value; + break; + + case 0xC001: + //irq.latch = value; + irq.reset = 1; + break; + + case 0xE000: + //irq.counter = irq.latch; + irq.enabled = 0; + break; + + case 0xE001: + irq.enabled = 1; + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("mapper 64: Wrote $%02X to $%04X", value, address); +#endif + break; + } + + if (1 == irq.reset) + irq.counter = irq.latch; +} + +static void map64_init(void) +{ + mmc_bankrom(8, 0x8000, MMC_LASTBANK); + mmc_bankrom(8, 0xA000, MMC_LASTBANK); + mmc_bankrom(8, 0xC000, MMC_LASTBANK); + mmc_bankrom(8, 0xE000, MMC_LASTBANK); + + irq.counter = irq.latch = 0; + irq.reset = irq.enabled = 0; +} + +static map_memwrite map64_memwrite[] = +{ + { 0x8000, 0xFFFF, map64_write }, + { -1, -1, NULL } +}; + +mapintf_t map64_intf = +{ + 64, /* mapper number */ + "Tengen RAMBO-1", /* mapper name */ + map64_init, /* init routine */ + NULL, /* vblank callback */ + map64_hblank, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map64_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map064.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.8 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.7 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.6 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.5 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.4 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map046.c =================================================================== --- apps/plugins/nofrendo/mappers/map046.c (revision 0) +++ apps/plugins/nofrendo/mappers/map046.c (revision 0) @@ -0,0 +1,152 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map046.c +** +** Mapper #46 (Pelican Game Station) +** Implementation by Firebug +** Mapper information courtesy of Kevin Horton +** $Id: map046.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +static uint8 prg_low_bank; +static uint8 chr_low_bank; +static uint8 prg_high_bank; +static uint8 chr_high_bank; + +/*************************************************/ +/* Set banks from the combined register values */ +/*************************************************/ +static void map46_set_banks (void) +{ + /* Set the PRG and CHR pages */ + mmc_bankrom (32, 0x8000, (prg_high_bank << 1) | (prg_low_bank)); + mmc_bankvrom (8, 0x0000, (chr_high_bank << 3) | (chr_low_bank)); + + /* Done */ + return; +} + +/*********************************************************/ +/* Mapper #46: Pelican Game Station (aka Rumble Station) */ +/*********************************************************/ +static void map46_init (void) +{ + /* High bank switch register is set to zero on reset */ + prg_high_bank = 0x00; + chr_high_bank = 0x00; + map46_set_banks (); + + /* Done */ + return; +} + +/******************************************/ +/* Mapper #46 write handler ($6000-$FFFF) */ +/******************************************/ +static void map46_write (uint32 address, uint8 value) +{ + /* $8000-$FFFF: D6-D4 = lower three bits of CHR bank */ + /* D0 = low bit of PRG bank */ + /* $6000-$7FFF: D7-D4 = high four bits of CHR bank */ + /* D3-D0 = high four bits of PRG bank */ + if (address & 0x8000) + { + prg_low_bank = value & 0x01; + chr_low_bank = (value >> 4) & 0x07; + map46_set_banks (); + } + else + { + prg_high_bank = value & 0x0F; + chr_high_bank = (value >> 4) & 0x0F; + map46_set_banks (); + } + + /* Done */ + return; +} + +/****************************************************/ +/* Shove extra mapper information into a SNSS block */ +/****************************************************/ +static void map46_setstate (SnssMapperBlock *state) +{ + /* TODO: Store SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +/*****************************************************/ +/* Pull extra mapper information out of a SNSS block */ +/*****************************************************/ +static void map46_getstate (SnssMapperBlock *state) +{ + /* TODO: Retrieve SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +static map_memwrite map46_memwrite [] = +{ + { 0x6000, 0xFFFF, map46_write }, + { -1, -1, NULL } +}; + +mapintf_t map46_intf = +{ + 46, /* Mapper number */ + "Pelican Game Station", /* Mapper name */ + map46_init, /* Initialization routine */ + NULL, /* VBlank callback */ + NULL, /* HBlank callback */ + map46_getstate, /* Get state (SNSS) */ + map46_setstate, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map46_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map046.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/27 19:23:05 firebug +** initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map065.c =================================================================== --- apps/plugins/nofrendo/mappers/map065.c (revision 0) +++ apps/plugins/nofrendo/mappers/map065.c (revision 0) @@ -0,0 +1,144 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map65.c +** +** mapper 65 interface +** $Id: map065.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +static struct +{ + int counter; + int enabled; + int cycles; + uint8 low, high; +} irq; + +static void map65_init(void) +{ + irq.counter = 0; + irq.enabled = 0; + irq.low = irq.high = 0; + irq.cycles = 0; +} + +/* TODO: shouldn't there be some kind of HBlank callback??? */ + +/* mapper 65: Irem H-3001*/ +static void map65_write(uint32 address, uint8 value) +{ + int range = address & 0xF000; + int reg = address & 7; + + switch (range) + { + case 0x8000: + case 0xA000: + case 0xC000: + mmc_bankrom(8, range, value); + break; + + case 0xB000: + mmc_bankvrom(1, reg << 10, value); + break; + + case 0x9000: + switch (reg) + { + case 4: + irq.enabled = (value & 0x01) ? 0 : 1; + break; + + case 5: + irq.high = value; + irq.cycles = (irq.high << 8) | irq.low; + irq.counter = (uint8)(irq.cycles / 128); + break; + + case 6: + irq.low = value; + irq.cycles = (irq.high << 8) | irq.low; + irq.counter = (uint8)(irq.cycles / 128); + break; + + default: + break; + } + break; + + default: + break; + } +} + +static map_memwrite map65_memwrite[] = +{ + { 0x8000, 0xFFFF, map65_write }, + { -1, -1, NULL } +}; + +mapintf_t map65_intf = +{ + 65, /* mapper number */ + "Irem H-3001", /* mapper name */ + map65_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map65_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map065.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map066.c =================================================================== --- apps/plugins/nofrendo/mappers/map066.c (revision 0) +++ apps/plugins/nofrendo/mappers/map066.c (revision 0) @@ -0,0 +1,94 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map66.c +** +** mapper 66 interface +** $Id: map066.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 66: GNROM */ +static void map66_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(32, 0x8000, (value >> 4) & 3); + mmc_bankvrom(8, 0x0000, value & 3); +} + +static void map66_init(void) +{ + mmc_bankrom(32, 0x8000, 0); + mmc_bankvrom(8, 0x0000, 0); +} + + +static map_memwrite map66_memwrite[] = +{ + { 0x8000, 0xFFFF, map66_write }, + { -1, -1, NULL } +}; + +mapintf_t map66_intf = +{ + 66, /* mapper number */ + "GNROM", /* mapper name */ + map66_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map66_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map066.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map085.c =================================================================== --- apps/plugins/nofrendo/mappers/map085.c (revision 0) +++ apps/plugins/nofrendo/mappers/map085.c (revision 0) @@ -0,0 +1,232 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map85.c +** +** mapper 85 interface +** $Id: map085.c,v 1.3 2001/05/06 01:42:03 neil Exp $ +*/ + +#include +#include +#include +#include + +static struct +{ + int counter, latch; + int wait_state; + int enabled; +} irq; + +/* mapper 85: Konami VRC7 */ +static void map85_write(uint32 address, uint8 value) +{ + uint8 bank = address >> 12; + uint8 reg = (address & 0x10) | ((address & 0x08) << 1); + + switch (bank) + { + case 0x08: + if (0x10 == reg) + mmc_bankrom(8, 0xA000, value); + else + mmc_bankrom(8, 0x8000, value); + break; + + case 0x09: + /* 0x10 & 0x30 should be trapped by sound emulation */ + mmc_bankrom(8, 0xC000, value); + break; + + case 0x0A: + if (0x10 == reg) + mmc_bankvrom(1, 0x0400, value); + else + mmc_bankvrom(1, 0x0000, value); + break; + + case 0x0B: + if (0x10 == reg) + mmc_bankvrom(1, 0x0C00, value); + else + mmc_bankvrom(1, 0x0800, value); + break; + + case 0x0C: + if (0x10 == reg) + mmc_bankvrom(1, 0x1400, value); + else + mmc_bankvrom(1, 0x1000, value); + break; + + case 0x0D: + if (0x10 == reg) + mmc_bankvrom(1, 0x1C00, value); + else + mmc_bankvrom(1, 0x1800, value); + break; + + case 0x0E: + if (0x10 == reg) + { + irq.latch = value; + } + else + { + switch (value & 3) + { + case 0: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 1: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 2: + ppu_mirror(0, 0, 0, 0); + break; + + case 3: + ppu_mirror(1, 1, 1, 1); + break; + } + } + break; + + case 0x0F: + if (0x10 == reg) + { + irq.enabled = irq.wait_state; + } + else + { + irq.wait_state = value & 0x01; + irq.enabled = (value & 0x02) ? 1 : 0; + if (1 == irq.enabled) + irq.counter = irq.latch; + } + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("unhandled vrc7 write: $%02X to $%04X\n", value, address); +#endif /* NOFRENDO_DEBUG */ + break; + } +} + +static void map85_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.enabled) + { + if (++irq.counter > 0xFF) + { + irq.counter = irq.latch; + nes_irq(); + + //return; + } + //irq.counter++; + } +} + +static map_memwrite map85_memwrite[] = +{ + { 0x8000, 0xFFFF, map85_write }, + { -1, -1, NULL } +}; + +static void map85_init(void) +{ + mmc_bankrom(16, 0x8000, 0); + mmc_bankrom(16, 0xC000, MMC_LASTBANK); + + mmc_bankvrom(8, 0x0000, 0); + + irq.counter = irq.latch = 0; + irq.wait_state = 0; + irq.enabled = 0; +} + +mapintf_t map85_intf = +{ + 85, /* mapper number */ + "Konami VRC7", /* mapper name */ + map85_init, /* init routine */ + NULL, /* vblank callback */ + map85_hblank, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map85_memwrite, /* memory write structure */ + NULL +}; + +/* +** $Log: map085.c,v $ +** Revision 1.3 2001/05/06 01:42:03 neil +** boooo +** +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.10 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.9 2000/10/22 15:03:14 matt +** simplified mirroring +** +** Revision 1.8 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.7 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.6 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.5 2000/07/23 14:37:21 matt +** added a break statement +** +** Revision 1.4 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.3 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.2 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.1 2000/07/06 02:47:47 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map229.c =================================================================== --- apps/plugins/nofrendo/mappers/map229.c (revision 0) +++ apps/plugins/nofrendo/mappers/map229.c (revision 0) @@ -0,0 +1,114 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map229.c +** +** Mapper #229 (31 in 1) +** Implementation by Firebug +** Mapper information courtesy of Mark Knibbs +** $Id: map229.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +/************************/ +/* Mapper #229: 31 in 1 */ +/************************/ +static void map229_init (void) +{ + /* On reset, PRG is set to first 32K and CHR to first 8K */ + mmc_bankrom (32, 0x8000, 0x00); + mmc_bankvrom (8, 0x0000, 0x00); + + /* Done */ + return; +} + +/*******************************************/ +/* Mapper #229 write handler ($8000-$FFFF) */ +/*******************************************/ +static void map229_write (uint32 address, uint8 value) +{ + /* Value written is irrelevant */ + UNUSED (value); + + /* A4-A0 sets 8K CHR page */ + mmc_bankvrom (8, 0x0000, (uint8) (address & 0x1F)); + + /* If A4-A1 are all low then select the first 32K, */ + /* otherwise select a 16K bank at both $8000 and $C000 */ + if ((address & 0x1E) == 0x00) + { + mmc_bankrom (32, 0x8000, 0x00); + } + else + { + mmc_bankrom (16, 0x8000, (uint8) (address & 0x1F)); + mmc_bankrom (16, 0xC000, (uint8) (address & 0x1F)); + } + + /* A5: mirroring (low = vertical, high = horizontal) */ + if (address & 0x20) ppu_mirror(0, 0, 1, 1); + else ppu_mirror(0, 1, 0, 1); + + /* Done */ + return; +} + +static map_memwrite map229_memwrite [] = +{ + { 0x8000, 0xFFFF, map229_write }, + { -1, -1, NULL } +}; + +mapintf_t map229_intf = +{ + 229, /* Mapper number */ + "31 in 1 (bootleg)", /* Mapper name */ + map229_init, /* Initialization routine */ + NULL, /* VBlank callback */ + NULL, /* HBlank callback */ + NULL, /* Get state (SNSS) */ + NULL, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map229_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map229.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/30 06:34:31 firebug +** Initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map087.c =================================================================== --- apps/plugins/nofrendo/mappers/map087.c (revision 0) +++ apps/plugins/nofrendo/mappers/map087.c (revision 0) @@ -0,0 +1,85 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map087.c +** +** Mapper #87 (16K VROM switch) +** Implementation by Firebug +** $Id: map087.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +/******************************************/ +/* Mapper #87 write handler ($6000-$7FFF) */ +/******************************************/ +static void map87_write (uint32 address, uint8 value) +{ + /* Within range, address written to is irrelevant */ + UNUSED (address); + + /* Very simple: 8K CHR page is selected by D1 */ + if (value & 0x02) mmc_bankvrom (8, 0x0000, 0x01); + else mmc_bankvrom (8, 0x0000, 0x00); + + /* Done */ + return; +} + +static map_memwrite map87_memwrite [] = +{ + { 0x6000, 0x7FFF, map87_write }, + { -1, -1, NULL } +}; + +mapintf_t map87_intf = +{ + 87, /* Mapper number */ + "16K VROM switch", /* Mapper name */ + NULL, /* Initialization routine */ + NULL, /* VBlank callback */ + NULL, /* HBlank callback */ + NULL, /* Get state (SNSS) */ + NULL, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map87_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map087.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/30 06:34:44 firebug +** Initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map011.c =================================================================== --- apps/plugins/nofrendo/mappers/map011.c (revision 0) +++ apps/plugins/nofrendo/mappers/map011.c (revision 0) @@ -0,0 +1,93 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map11.c +** +** mapper 11 interface +** $Id: map011.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 11: Color Dreams, Wisdom Tree */ +static void map11_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(32, 0x8000, value & 0x0F); + mmc_bankvrom(8, 0x0000, value >> 4); +} + +static void map11_init(void) +{ + mmc_bankrom(32, 0x8000, 0); + mmc_bankvrom(8, 0x0000, 0); +} + +static map_memwrite map11_memwrite[] = +{ + { 0x8000, 0xFFFF, map11_write }, + { -1, -1, NULL } +}; + +mapintf_t map11_intf = +{ + 11, /* mapper number */ + "Color Dreams", /* mapper name */ + map11_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map11_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map011.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map032.c =================================================================== --- apps/plugins/nofrendo/mappers/map032.c (revision 0) +++ apps/plugins/nofrendo/mappers/map032.c (revision 0) @@ -0,0 +1,121 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map32.c +** +** mapper 32 interface +** $Id: map032.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +static int select_c000 = 0; + +/* mapper 32: Irem G-101 */ +static void map32_write(uint32 address, uint8 value) +{ + switch (address >> 12) + { + case 0x08: + if (select_c000) + mmc_bankrom(8, 0xC000, value); + else + mmc_bankrom(8, 0x8000, value); + break; + + case 0x09: + if (value & 1) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); /* vertical */ + + select_c000 = (value & 0x02); + break; + + case 0x0A: + mmc_bankrom(8, 0xA000, value); + break; + + case 0x0B: + { + int loc = (address & 0x07) << 10; + mmc_bankvrom(1, loc, value); + } + break; + + default: + break; + } +} + +static map_memwrite map32_memwrite[] = +{ + { 0x8000, 0xFFFF, map32_write }, + { -1, -1, NULL } +}; + +mapintf_t map32_intf = +{ + 32, /* mapper number */ + "Irem G-101", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map32_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map032.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map050.c =================================================================== --- apps/plugins/nofrendo/mappers/map050.c (revision 0) +++ apps/plugins/nofrendo/mappers/map050.c (revision 0) @@ -0,0 +1,192 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map050.c +** +** Mapper #50 (SMB2j - 3rd discovered variation) +** Implementation by Firebug +** Mapper information courtesy of Kevin Horton +** $Id: map050.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +static struct +{ + int enabled; + uint32 counter; +} irq; + +/********************************/ +/* Mapper #50 IRQ reset routine */ +/********************************/ +static void map50_irq_reset (void) +{ + /* Turn off IRQs */ + irq.enabled = 0; + irq.counter = 0x0000; + + /* Done */ + return; +} + +/**************************************************************/ +/* Mapper #50: 3rd discovered variation of SMB2j cart bootleg */ +/**************************************************************/ +static void map50_init (void) +{ + /* Set the hardwired pages */ + mmc_bankrom (8, 0x6000, 0x0F); + mmc_bankrom (8, 0x8000, 0x08); + mmc_bankrom (8, 0xA000, 0x09); + mmc_bankrom (8, 0xE000, 0x0B); + + /* Reset the IRQ counter */ + map50_irq_reset (); + + /* Done */ + return; +} + +/****************************************/ +/* Mapper #50 callback for IRQ handling */ +/****************************************/ +static void map50_hblank (int vblank) +{ + /* Counter is M2 based so it doesn't matter whether */ + /* the PPU is in its VBlank period or not */ + UNUSED(vblank); + + /* Increment the counter if it is enabled and check for strike */ + if (irq.enabled) + { + /* Is there a constant for cycles per scanline? */ + /* If so, someone ought to substitute it here */ + irq.counter = irq.counter + 114; + + /* IRQ line is hooked to Q12 of the counter */ + if (irq.counter & 0x1000) + { + /* Trigger the IRQ */ + nes_irq (); + + /* Reset the counter */ + map50_irq_reset (); + } + } +} + +/******************************************/ +/* Mapper #50 write handler ($4000-$5FFF) */ +/******************************************/ +static void map50_write (uint32 address, uint8 value) +{ + uint8 selectable_bank; + + /* For address to be decoded, A5 must be high and A6 low */ + if ((address & 0x60) != 0x20) return; + + /* A8 low = $C000-$DFFF page selection */ + /* A8 high = IRQ timer toggle */ + if (address & 0x100) + { + /* IRQ settings */ + if (value & 0x01) irq.enabled = 1; + else map50_irq_reset (); + } + else + { + /* Stupid data line swapping */ + selectable_bank = 0x00; + if (value & 0x08) selectable_bank |= 0x08; + if (value & 0x04) selectable_bank |= 0x02; + if (value & 0x02) selectable_bank |= 0x01; + if (value & 0x01) selectable_bank |= 0x04; + mmc_bankrom (8, 0xC000, selectable_bank); + } + + /* Done */ + return; +} + +/****************************************************/ +/* Shove extra mapper information into a SNSS block */ +/****************************************************/ +static void map50_setstate (SnssMapperBlock *state) +{ + /* TODO: Store SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +/*****************************************************/ +/* Pull extra mapper information out of a SNSS block */ +/*****************************************************/ +static void map50_getstate (SnssMapperBlock *state) +{ + /* TODO: Retrieve SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +static map_memwrite map50_memwrite [] = +{ + { 0x4000, 0x5FFF, map50_write }, + { -1, -1, NULL } +}; + +mapintf_t map50_intf = +{ + 50, /* Mapper number */ + "SMB2j (3rd discovered variant)", /* Mapper name */ + map50_init, /* Initialization routine */ + NULL, /* VBlank callback */ + map50_hblank, /* HBlank callback */ + map50_getstate, /* Get state (SNSS) */ + map50_setstate, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map50_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map050.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/27 19:22:13 firebug +** initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map015.c =================================================================== --- apps/plugins/nofrendo/mappers/map015.c (revision 0) +++ apps/plugins/nofrendo/mappers/map015.c (revision 0) @@ -0,0 +1,144 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map15.c +** +** mapper 15 interface +** $Id: map015.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* mapper 15: Contra 100-in-1 */ +static void map15_write(uint32 address, uint8 value) +{ + int bank = value & 0x3F; + uint8 swap = (value & 0x80) >> 7; + + switch (address & 0x3) + { + case 0: + mmc_bankrom(8, 0x8000, (bank << 1) + swap); + mmc_bankrom(8, 0xA000, (bank << 1) + (swap ^ 1)); + mmc_bankrom(8, 0xC000, ((bank + 1) << 1) + swap); + mmc_bankrom(8, 0xE000, ((bank + 1) << 1) + (swap ^ 1)); + + if (value & 0x40) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 1: + mmc_bankrom(8, 0xC000, (bank << 1) + swap); + mmc_bankrom(8, 0xE000, (bank << 1) + (swap ^ 1)); + break; + + case 2: + if (swap) + { + mmc_bankrom(8, 0x8000, (bank << 1) + 1); + mmc_bankrom(8, 0xA000, (bank << 1) + 1); + mmc_bankrom(8, 0xC000, (bank << 1) + 1); + mmc_bankrom(8, 0xE000, (bank << 1) + 1); + } + else + { + mmc_bankrom(8, 0x8000, (bank << 1)); + mmc_bankrom(8, 0xA000, (bank << 1)); + mmc_bankrom(8, 0xC000, (bank << 1)); + mmc_bankrom(8, 0xE000, (bank << 1)); + } + break; + + case 3: + mmc_bankrom(8, 0xC000, (bank << 1) + swap); + mmc_bankrom(8, 0xE000, (bank << 1) + (swap ^ 1)); + + if (value & 0x40) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + default: + break; + } +} + +static void map15_init(void) +{ + mmc_bankrom(32, 0x8000, 0); +} + +static map_memwrite map15_memwrite[] = +{ + { 0x8000, 0xFFFF, map15_write }, + { -1, -1, NULL } +}; + +mapintf_t map15_intf = +{ + 15, /* mapper number */ + "Contra 100-in-1", /* mapper name */ + map15_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map15_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map015.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map033.c =================================================================== --- apps/plugins/nofrendo/mappers/map033.c (revision 0) +++ apps/plugins/nofrendo/mappers/map033.c (revision 0) @@ -0,0 +1,145 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map33.c +** +** mapper 33 interface +** $Id: map033.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* mapper 33: Taito TC0190*/ +static void map33_write(uint32 address, uint8 value) +{ + int page = (address >> 13) & 3; + int reg = address & 3; + + switch (page) + { + case 0: /* $800X */ + switch (reg) + { + case 0: + mmc_bankrom(8, 0x8000, value); + break; + + case 1: + mmc_bankrom(8, 0xA000, value); + break; + + case 2: + mmc_bankvrom(2, 0x0000, value); + break; + + case 3: + mmc_bankvrom(2, 0x0800, value); + break; + } + break; + + case 1: /* $A00X */ + { + int loc = 0x1000 + (reg << 10); + mmc_bankvrom(1, loc, value); + } + break; + + case 2: /* $C00X */ + case 3: /* $E00X */ + switch (reg) + { + case 0: + /* irqs maybe ? */ + //break; + + case 1: + /* this doesn't seem to work just right */ + if (value & 1) + ppu_mirror(0, 0, 1, 1); /* horizontal */ + else + ppu_mirror(0, 1, 0, 1); + break; + + default: + break; + } + break; + } +} + + +static map_memwrite map33_memwrite[] = +{ + { 0x8000, 0xFFFF, map33_write }, + { -1, -1, NULL } +}; + +mapintf_t map33_intf = +{ + 33, /* mapper number */ + "Taito TC0190", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map33_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map033.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.7 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.6 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map231.c =================================================================== --- apps/plugins/nofrendo/mappers/map231.c (revision 0) +++ apps/plugins/nofrendo/mappers/map231.c (revision 0) @@ -0,0 +1,95 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map231.c +** +** mapper 231 interface +** $Id: map231.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 231: NINA-07, used in Wally Bear and the NO! Gang */ + +static void map231_init(void) +{ + mmc_bankrom(32, 0x8000, MMC_LASTBANK); +} + +static void map231_write(uint32 address, uint8 value) +{ + int bank, vbank; + UNUSED(address); + + bank = ((value & 0x80) >> 5) | (value & 0x03); + vbank = (value >> 4) & 0x07; + + mmc_bankrom(32, 0x8000, bank); + mmc_bankvrom(8, 0x0000, vbank); +} + +static map_memwrite map231_memwrite[] = +{ + { 0x8000, 0xFFFF, map231_write }, + { -1, -1, NULL } +}; + +mapintf_t map231_intf = +{ + 231, /* mapper number */ + "NINA-07", /* mapper name */ + map231_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map231_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map231.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.4 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.3 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.2 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.1 2000/07/11 03:14:18 melanson +** Initial commit for mappers 16, 34, and 231 +** +** +*/ Index: apps/plugins/nofrendo/mappers/map034.c =================================================================== --- apps/plugins/nofrendo/mappers/map034.c (revision 0) +++ apps/plugins/nofrendo/mappers/map034.c (revision 0) @@ -0,0 +1,100 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map34.c +** +** mapper 34 interface +** $Id: map034.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +static void map34_init(void) +{ + mmc_bankrom(32, 0x8000, MMC_LASTBANK); +} + +static void map34_write(uint32 address, uint8 value) +{ + if ((address & 0x8000) || (0x7FFD == address)) + { + mmc_bankrom(32, 0x8000, value); + } + else if (0x7FFE == address) + { + mmc_bankvrom(4, 0x0000, value); + } + else if (0x7FFF == address) + { + mmc_bankvrom(4, 0x1000, value); + } +} + +static map_memwrite map34_memwrite[] = +{ + { 0x7FFD, 0xFFFF, map34_write }, + { -1, -1, NULL } +}; + +mapintf_t map34_intf = +{ + 34, /* mapper number */ + "Nina-1", /* mapper name */ + map34_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map34_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map034.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/07/11 05:03:49 matt +** value masking isn't necessary for the banking routines +** +** Revision 1.2 2000/07/11 03:35:08 bsittler +** Fixes to make mikes new mappers compile. +** +** Revision 1.1 2000/07/11 03:14:18 melanson +** Initial commit for mappers 16, 34, and 231 +** +** +*/ Index: apps/plugins/nofrendo/mappers/map070.c =================================================================== --- apps/plugins/nofrendo/mappers/map070.c (revision 0) +++ apps/plugins/nofrendo/mappers/map070.c (revision 0) @@ -0,0 +1,115 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map70.c +** +** mapper 70 interface +** $Id: map070.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* mapper 70: Arkanoid II, Kamen Rider Club, etc. */ +/* ($8000-$FFFF) D6-D4 = switch $8000-$BFFF */ +/* ($8000-$FFFF) D3-D0 = switch PPU $0000-$1FFF */ +/* ($8000-$FFFF) D7 = switch mirroring */ +static void map70_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(16, 0x8000, (value >> 4) & 0x07); + mmc_bankvrom(8, 0x0000, value & 0x0F); + + /* Argh! FanWen used the 4-screen bit to determine + ** whether the game uses D7 to switch between + ** horizontal and vertical mirroring, or between + ** one-screen mirroring from $2000 or $2400. + */ + if (mmc_getinfo()->flags & ROM_FLAG_FOURSCREEN) + { + if (value & 0x80) + ppu_mirror(0, 0, 1, 1); /* horiz */ + else + ppu_mirror(0, 1, 0, 1); /* vert */ + } + else + { + int mirror = (value & 0x80) >> 7; + ppu_mirror(mirror, mirror, mirror, mirror); + } +} + +static map_memwrite map70_memwrite[] = +{ + { 0x8000, 0xFFFF, map70_write }, + { -1, -1, NULL } +}; + +mapintf_t map70_intf = +{ + 70, /* mapper number */ + "Mapper 70", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map70_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map070.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.7 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.6 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map016.c =================================================================== --- apps/plugins/nofrendo/mappers/map016.c (revision 0) +++ apps/plugins/nofrendo/mappers/map016.c (revision 0) @@ -0,0 +1,192 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map16.c +** +** mapper 16 interface +** $Id: map016.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +static struct +{ + int counter; + int enabled; +} irq; + +/* mapper 16: Bandai */ + +static void map16_init(void) +{ + mmc_bankrom(16, 0x8000, 0); + mmc_bankrom(16, 0xC000, MMC_LASTBANK); + irq.counter = 0; + irq.enabled = 0; +} + +static void map16_write(uint32 address, uint8 value) +{ + int reg = address & 0xF; + + if (reg < 8) + { + mmc_bankvrom(1, reg << 10, value); + } + else + { + switch (address & 0x000F) + { + case 0x8: + mmc_bankrom(16, 0x8000, value); + break; + + case 0x9: + switch (value & 3) + { + case 0: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 1: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 2: + ppu_mirror(0, 0, 0, 0); + break; + + case 3: + ppu_mirror(1, 1, 1, 1); + break; + } + break; + + case 0xA: + irq.enabled = (value & 1) ? 1 : 0; + break; + + case 0xB: + irq.counter = (irq.counter & 0xFF00) | value; + break; + + case 0xC: + irq.counter = (value << 8) | (irq.counter & 0xFF); + break; + + case 0xD: + /* eeprom I/O port? */ + break; + } + } +} + +static void map16_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.enabled) + { + if (irq.counter) + { + if (0 == --irq.counter) + nes_irq(); + } + } +} + +static void map16_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper16.irqCounterLowByte = irq.counter & 0xFF; + state->extraData.mapper16.irqCounterHighByte = irq.counter >> 8; + state->extraData.mapper16.irqCounterEnabled = irq.enabled; +} + +static void map16_setstate(SnssMapperBlock *state) +{ + irq.counter = (state->extraData.mapper16.irqCounterHighByte << 8) + | state->extraData.mapper16.irqCounterLowByte; + irq.enabled = state->extraData.mapper16.irqCounterEnabled; +} + +static map_memwrite map16_memwrite[] = +{ + { 0x6000, 0x600D, map16_write }, + { 0x7FF0, 0x7FFD, map16_write }, + { 0x8000, 0x800D, map16_write }, + { -1, -1, NULL } +}; + +mapintf_t map16_intf = +{ + 16, /* mapper number */ + "Bandai", /* mapper name */ + map16_init, /* init routine */ + NULL, /* vblank callback */ + map16_hblank, /* hblank callback */ + map16_getstate, /* get state (snss) */ + map16_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map16_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map016.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.8 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.7 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.6 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.5 2000/10/10 13:58:16 matt +** stroustrup squeezing his way in the door +** +** Revision 1.4 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.3 2000/07/15 23:52:20 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.2 2000/07/11 05:03:49 matt +** value masking isn't necessary for the banking routines +** +** Revision 1.1 2000/07/11 03:14:18 melanson +** Initial commit for mappers 16, 34, and 231 +** +** +*/ Index: apps/plugins/nofrendo/mappers/map018.c =================================================================== --- apps/plugins/nofrendo/mappers/map018.c (revision 0) +++ apps/plugins/nofrendo/mappers/map018.c (revision 0) @@ -0,0 +1,215 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map18.c +** +** mapper 18 interface +** $Id: map018.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* mapper 18: Jaleco SS8806 */ +#define VRC_PBANK(bank, value, high) \ +do { \ + if ((high)) \ + highprgnybbles[(bank)] = (value) & 0x0F; \ + else \ + lowprgnybbles[(bank)] = (value) & 0x0F; \ + mmc_bankrom(8, 0x8000 + ((bank) << 13), (highprgnybbles[(bank)] << 4)+lowprgnybbles[(bank)]); \ +} while (0) + +#define VRC_VBANK(bank, value, high) \ +{ \ + if ((high)) \ + highnybbles[(bank)] = (value) & 0x0F; \ + else \ + lownybbles[(bank)] = (value) & 0x0F; \ + mmc_bankvrom(1, (bank) << 10, (highnybbles[(bank)] << 4)+lownybbles[(bank)]); \ +} + +static struct +{ + int counter, enabled; + uint8 nybbles[4]; + int clockticks; +} irq; + +static void map18_init(void) +{ + irq.counter = irq.enabled = 0; +} + +static uint8 lownybbles[8]; +static uint8 highnybbles[8]; +static uint8 lowprgnybbles[3]; +static uint8 highprgnybbles[3]; + + +static void map18_write(uint32 address, uint8 value) +{ + switch (address) + { + case 0x8000: VRC_PBANK(0, value, 0); break; + case 0x8001: VRC_PBANK(0, value, 1); break; + case 0x8002: VRC_PBANK(1, value, 0); break; + case 0x8003: VRC_PBANK(1, value, 1); break; + case 0x9000: VRC_PBANK(2, value, 0); break; + case 0x9001: VRC_PBANK(2, value, 1); break; + case 0xA000: VRC_VBANK(0, value, 0); break; + case 0xA001: VRC_VBANK(0, value, 1); break; + case 0xA002: VRC_VBANK(1, value, 0); break; + case 0xA003: VRC_VBANK(1, value, 1); break; + case 0xB000: VRC_VBANK(2, value, 0); break; + case 0xB001: VRC_VBANK(2, value, 1); break; + case 0xB002: VRC_VBANK(3, value, 0); break; + case 0xB003: VRC_VBANK(3, value, 1); break; + case 0xC000: VRC_VBANK(4, value, 0); break; + case 0xC001: VRC_VBANK(4, value, 1); break; + case 0xC002: VRC_VBANK(5, value, 0); break; + case 0xC003: VRC_VBANK(5, value, 1); break; + case 0xD000: VRC_VBANK(6, value, 0); break; + case 0xD001: VRC_VBANK(6, value, 1); break; + case 0xD002: VRC_VBANK(7, value, 0); break; + case 0xD003: VRC_VBANK(7, value, 1); break; + case 0xE000: + irq.nybbles[0]=value&0x0F; + irq.clockticks= (irq.nybbles[0]) | (irq.nybbles[1]<<4) | + (irq.nybbles[2]<<8) | (irq.nybbles[3]<<12); + irq.counter=(uint8)(irq.clockticks/114); + if(irq.counter>15) irq.counter-=16; + break; + case 0xE001: + irq.nybbles[1]=value&0x0F; + irq.clockticks= (irq.nybbles[0]) | (irq.nybbles[1]<<4) | + (irq.nybbles[2]<<8) | (irq.nybbles[3]<<12); + irq.counter=(uint8)(irq.clockticks/114); + if(irq.counter>15) irq.counter-=16; + break; + case 0xE002: + irq.nybbles[2]=value&0x0F; + irq.clockticks= (irq.nybbles[0]) | (irq.nybbles[1]<<4) | + (irq.nybbles[2]<<8) | (irq.nybbles[3]<<12); + irq.counter=(uint8)(irq.clockticks/114); + if(irq.counter>15) irq.counter-=16; + break; + case 0xE003: + irq.nybbles[3]=value&0x0F; + irq.clockticks= (irq.nybbles[0]) | (irq.nybbles[1]<<4) | + (irq.nybbles[2]<<8) | (irq.nybbles[3]<<12); + irq.counter=(uint8)(irq.clockticks/114); + if(irq.counter>15) irq.counter-=16; + break; + case 0xF000: + if(value&0x01) irq.enabled=1; + break; + case 0xF001: + irq.enabled=value&0x01; + break; + case 0xF002: + switch(value&0x03) + { + case 0: ppu_mirror(0, 0, 1, 1); break; + case 1: ppu_mirror(0, 1, 0, 1); break; + case 2: ppu_mirror(1,1,1,1);break; + case 3: ppu_mirror(1,1,1,1);break; // should this be zero? + default: break; + } + break; + default: + break; + } +} + + +static map_memwrite map18_memwrite[] = +{ + { 0x8000, 0xFFFF, map18_write }, + { -1, -1, NULL } +}; + +static void map18_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper18.irqCounterLowByte = irq.counter & 0xFF; + state->extraData.mapper18.irqCounterHighByte = irq.counter >> 8; + state->extraData.mapper18.irqCounterEnabled = irq.enabled; +} + +static void map18_setstate(SnssMapperBlock *state) +{ + irq.counter = (state->extraData.mapper18.irqCounterHighByte << 8) + | state->extraData.mapper18.irqCounterLowByte; + irq.enabled = state->extraData.mapper18.irqCounterEnabled; +} + +mapintf_t map18_intf = +{ + 18, /* mapper number */ + "Jaleco SS8806", /* mapper name */ + map18_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + map18_getstate, /* get state (snss) */ + map18_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map18_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map018.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.8 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.7 2000/10/22 15:03:13 matt +** simplified mirroring +** +** Revision 1.6 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.5 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.4 2000/07/15 23:52:19 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:42 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map019.c =================================================================== --- apps/plugins/nofrendo/mappers/map019.c (revision 0) +++ apps/plugins/nofrendo/mappers/map019.c (revision 0) @@ -0,0 +1,170 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map19.c +** +** mapper 19 interface +** $Id: map019.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* TODO: shouldn't there be an h-blank IRQ handler??? */ + +/* Special mirroring macro for mapper 19 */ +#define N_BANK1(table, value) \ +{ \ + if ((value) < 0xE0) \ + ppu_setpage(1, (table) + 8, &mmc_getinfo()->vrom[((value) % (mmc_getinfo()->vrom_banks * 8)) << 10] - (0x2000 + ((table) << 10))); \ + else \ + ppu_setpage(1, (table) + 8, &mmc_getinfo()->vram[((value) & 7) << 10] - (0x2000 + ((table) << 10))); \ + ppu_mirrorhipages(); \ +} + +static struct +{ + int counter, enabled; +} irq; + +static void map19_init(void) +{ + irq.counter = irq.enabled = 0; +} + +/* mapper 19: Namcot 106 */ +static void map19_write(uint32 address, uint8 value) +{ + int reg = address >> 11; + switch (reg) + { + case 0xA: + irq.counter &= ~0xFF; + irq.counter |= value; + break; + + case 0xB: + irq.counter = ((value & 0x7F) << 8) | (irq.counter & 0xFF); + irq.enabled = (value & 0x80) ? 1 : 0; + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + mmc_bankvrom(1, (reg & 7) << 10, value); + break; + + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + N_BANK1(reg & 3, value); + break; + + case 0x1C: + mmc_bankrom(8, 0x8000, value); + break; + + case 0x1D: + mmc_bankrom(8, 0xA000, value); + break; + + case 0x1E: + mmc_bankrom(8, 0xC000, value); + break; + + default: + break; + } +} + +static void map19_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper19.irqCounterLowByte = irq.counter & 0xFF; + state->extraData.mapper19.irqCounterHighByte = irq.counter >> 8; + state->extraData.mapper19.irqCounterEnabled = irq.enabled; +} + +static void map19_setstate(SnssMapperBlock *state) +{ + irq.counter = (state->extraData.mapper19.irqCounterHighByte << 8) + | state->extraData.mapper19.irqCounterLowByte; + irq.enabled = state->extraData.mapper19.irqCounterEnabled; +} + +static map_memwrite map19_memwrite[] = +{ + { 0x5000, 0x5FFF, map19_write }, + { 0x8000, 0xFFFF, map19_write }, + { -1, -1, NULL } +}; + +mapintf_t map19_intf = +{ + 19, /* mapper number */ + "Namcot 106", /* mapper name */ + map19_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + map19_getstate, /* get state (snss) */ + map19_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map19_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map019.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.3 2000/07/15 23:52:20 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map073.c =================================================================== --- apps/plugins/nofrendo/mappers/map073.c (revision 0) +++ apps/plugins/nofrendo/mappers/map073.c (revision 0) @@ -0,0 +1,173 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map073.c +** +** Mapper #73 (Konami VRC3) +** Implementation by Firebug +** $Id: map073.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include + +static struct +{ + int enabled; + uint32 counter; +} irq; + +/**************************/ +/* Mapper #73: Salamander */ +/**************************/ +static void map73_init (void) +{ + /* Turn off IRQs */ + irq.enabled = 0; + irq.counter = 0x0000; + + /* Done */ + return; +} + +/****************************************/ +/* Mapper #73 callback for IRQ handling */ +/****************************************/ +static void map73_hblank (int vblank) +{ + /* Counter is M2 based so it doesn't matter whether */ + /* the PPU is in its VBlank period or not */ + UNUSED (vblank); + + /* Increment the counter if it is enabled and check for strike */ + if (irq.enabled) + { + /* Is there a constant for cycles per scanline? */ + /* If so, someone ought to substitute it here */ + irq.counter = irq.counter + 114; + + /* Counter triggered on overflow into Q16 */ + if (irq.counter & 0x10000) + { + /* Clip to sixteen-bit word */ + irq.counter &= 0xFFFF; + + /* Trigger the IRQ */ + nes_irq (); + + /* Shut off IRQ counter */ + irq.enabled = 0; + } + } +} + +/******************************************/ +/* Mapper #73 write handler ($8000-$FFFF) */ +/******************************************/ +static void map73_write (uint32 address, uint8 value) +{ + switch (address & 0xF000) + { + case 0x8000: irq.counter &= 0xFFF0; + irq.counter |= (uint32) (value); + break; + case 0x9000: irq.counter &= 0xFF0F; + irq.counter |= (uint32) (value << 4); + break; + case 0xA000: irq.counter &= 0xF0FF; + irq.counter |= (uint32) (value << 8); + break; + case 0xB000: irq.counter &= 0x0FFF; + irq.counter |= (uint32) (value << 12); + break; + case 0xC000: if (value & 0x02) irq.enabled = 1; + else irq.enabled = 0; + break; + case 0xF000: mmc_bankrom (16, 0x8000, value); + default: break; + } + + /* Done */ + return; +} + +/****************************************************/ +/* Shove extra mapper information into a SNSS block */ +/****************************************************/ +static void map73_setstate (SnssMapperBlock *state) +{ + /* TODO: Store SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +/*****************************************************/ +/* Pull extra mapper information out of a SNSS block */ +/*****************************************************/ +static void map73_getstate (SnssMapperBlock *state) +{ + /* TODO: Retrieve SNSS information */ + UNUSED (state); + + /* Done */ + return; +} + +static map_memwrite map73_memwrite [] = +{ + { 0x8000, 0xFFFF, map73_write }, + { -1, -1, NULL } +}; + +mapintf_t map73_intf = +{ + 73, /* Mapper number */ + "Konami VRC3", /* Mapper name */ + map73_init, /* Initialization routine */ + NULL, /* VBlank callback */ + map73_hblank, /* HBlank callback */ + map73_getstate, /* Get state (SNSS) */ + map73_setstate, /* Set state (SNSS) */ + NULL, /* Memory read structure */ + map73_memwrite, /* Memory write structure */ + NULL /* External sound device */ +}; + +/* +** $Log: map073.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1 2001/04/27 10:57:41 neil +** wheee +** +** Revision 1.1 2000/12/30 06:35:05 firebug +** Initial revision +** +** +*/ Index: apps/plugins/nofrendo/mappers/map093.c =================================================================== --- apps/plugins/nofrendo/mappers/map093.c (revision 0) +++ apps/plugins/nofrendo/mappers/map093.c (revision 0) @@ -0,0 +1,77 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map93.c +** +** mapper 93 interface +** $Id: map093.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +static void map93_write(uint32 address, uint8 value) +{ + UNUSED(address); + + /* ($8000-$FFFF) D7-D4 = switch $8000-$BFFF D0: mirror */ + mmc_bankrom(16, 0x8000, value >> 4); + + if (value & 1) + ppu_mirror(0, 1, 0, 1); /* vert */ + else + ppu_mirror(0, 0, 1, 1); /* horiz */ +} + +static map_memwrite map93_memwrite[] = +{ + { 0x8000, 0xFFFF, map93_write }, + { -1, -1, NULL } +}; + +mapintf_t map93_intf = +{ + 93, /* mapper number */ + "Mapper 93", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map93_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map093.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/12/11 12:33:48 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map075.c =================================================================== --- apps/plugins/nofrendo/mappers/map075.c (revision 0) +++ apps/plugins/nofrendo/mappers/map075.c (revision 0) @@ -0,0 +1,131 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map75.c +** +** mapper 75 interface +** $Id: map075.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + + +static uint8 latch[2]; +static uint8 hibits; + +/* mapper 75: Konami VRC1 */ +static void map75_write(uint32 address, uint8 value) +{ + switch ((address & 0xF000) >> 12) + { + case 0x8: + mmc_bankrom(8, 0x8000, value); + break; + + case 0x9: + hibits = (value & 0x06); + + mmc_bankvrom(4, 0x0000, ((hibits & 0x02) << 3) | latch[0]); + mmc_bankvrom(4, 0x1000, ((hibits & 0x04) << 2) | latch[1]); + + if (value & 1) + ppu_mirror(0, 1, 0, 1); /* vert */ + else + ppu_mirror(0, 0, 1, 1); /* horiz */ + + break; + + case 0xA: + mmc_bankrom(8, 0xA000, value); + break; + + case 0xC: + mmc_bankrom(8, 0xC000, value); + break; + + case 0xE: + latch[0] = (value & 0x0F); + mmc_bankvrom(4, 0x0000, ((hibits & 0x02) << 3) | latch[0]); + break; + + case 0xF: + latch[1] = (value & 0x0F); + mmc_bankvrom(4, 0x1000, ((hibits & 0x04) << 2) | latch[1]); + break; + + default: + break; + } +} + +static map_memwrite map75_memwrite[] = +{ + { 0x8000, 0xFFFF, map75_write }, + { -1, -1, NULL } +}; + +mapintf_t map75_intf = +{ + 75, /* mapper number */ + "Konami VRC1", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map75_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map075.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/22 15:03:14 matt +** simplified mirroring +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map094.c =================================================================== --- apps/plugins/nofrendo/mappers/map094.c (revision 0) +++ apps/plugins/nofrendo/mappers/map094.c (revision 0) @@ -0,0 +1,87 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map94.c +** +** mapper 94 interface +** $Id: map094.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 94: Senjou no Ookami */ +static void map94_write(uint32 address, uint8 value) +{ + UNUSED(address); + + /* ($8000-$FFFF) D7-D2 = switch $8000-$BFFF */ + mmc_bankrom(16, 0x8000, value >> 2); +} + +static map_memwrite map94_memwrite[] = +{ + { 0x8000, 0xFFFF, map94_write }, + { -1, -1, NULL } +}; + +mapintf_t map94_intf = +{ + 94, /* mapper number */ + "Mapper 94", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map94_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map094.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.5 2000/10/22 19:17:47 matt +** mapper cleanups galore +** +** Revision 1.4 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.3 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map078.c =================================================================== --- apps/plugins/nofrendo/mappers/map078.c (revision 0) +++ apps/plugins/nofrendo/mappers/map078.c (revision 0) @@ -0,0 +1,111 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map78.c +** +** mapper 78 interface +** $Id: map078.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* mapper 78: Holy Diver, Cosmo Carrier */ +/* ($8000-$FFFF) D2-D0 = switch $8000-$BFFF */ +/* ($8000-$FFFF) D7-D4 = switch PPU $0000-$1FFF */ +/* ($8000-$FFFF) D3 = switch mirroring */ +static void map78_write(uint32 address, uint8 value) +{ + UNUSED(address); + + mmc_bankrom(16, 0x8000, value & 7); + mmc_bankvrom(8, 0x0000, (value >> 4) & 0x0F); + + /* Ugh! Same abuse of the 4-screen bit as with Mapper #70 */ + if (mmc_getinfo()->flags & ROM_FLAG_FOURSCREEN) + { + if (value & 0x08) + ppu_mirror(0, 1, 0, 1); /* vert */ + else + ppu_mirror(0, 0, 1, 1); /* horiz */ + } + else + { + int mirror = (value >> 3) & 1; + ppu_mirror(mirror, mirror, mirror, mirror); + } +} + +static map_memwrite map78_memwrite[] = +{ + { 0x8000, 0xFFFF, map78_write }, + { -1, -1, NULL } +}; + +mapintf_t map78_intf = +{ + 78, /* mapper number */ + "Mapper 78", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map78_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map078.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.7 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.6 2000/10/22 15:03:14 matt +** simplified mirroring +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map079.c =================================================================== --- apps/plugins/nofrendo/mappers/map079.c (revision 0) +++ apps/plugins/nofrendo/mappers/map079.c (revision 0) @@ -0,0 +1,91 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map78.c +** +** mapper 78 interface +** $Id: map079.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +/* mapper 79: NINA-03/06 */ +static void map79_write(uint32 address, uint8 value) +{ + if ((address & 0x5100) == 0x4100) + { + mmc_bankrom(32, 0x8000, (value >> 3) & 1); + mmc_bankvrom(8, 0x0000, value & 7); + } +} + +static void map79_init(void) +{ + mmc_bankrom(32, 0x8000, 0); + mmc_bankvrom(8, 0x0000, 0); +} + +static map_memwrite map79_memwrite[] = +{ + { 0x4100, 0x5FFF, map79_write }, /* ????? incorrect range ??? */ + { -1, -1, NULL } +}; + +mapintf_t map79_intf = +{ + 79, /* mapper number */ + "NINA-03/06", /* mapper name */ + map79_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map79_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map079.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.4 2000/10/22 19:17:47 matt +** mapper cleanups galore +** +** Revision 1.3 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map099.c =================================================================== --- apps/plugins/nofrendo/mappers/map099.c (revision 0) +++ apps/plugins/nofrendo/mappers/map099.c (revision 0) @@ -0,0 +1,90 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map99.c +** +** mapper 99 interface +** $Id: map099.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include + +/* Switch VROM for VS games */ +static void map99_vromswitch(uint8 value) +{ + int bank = (value & 0x04) >> 2; + mmc_bankvrom(8, 0x0000, bank); +} + +/* mapper 99: VS. System */ +static void map99_init(void) +{ + ppu_mirror(0, 1, 2, 3); + ppu_setvromswitch(map99_vromswitch); +} + +mapintf_t map99_intf = +{ + 99, /* mapper number */ + "VS. System", /* mapper name */ + map99_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + NULL, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map099.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.6 2000/10/22 19:17:47 matt +** mapper cleanups galore +** +** Revision 1.5 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.4 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/05 05:05:18 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/mapvrc.c =================================================================== --- apps/plugins/nofrendo/mappers/mapvrc.c (revision 0) +++ apps/plugins/nofrendo/mappers/mapvrc.c (revision 0) @@ -0,0 +1,452 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map_vrc.c +** +** VRC mapper interface +** $Id: mapvrc.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +#define VRC_VBANK(bank, value, high) \ +{ \ + if ((high)) \ + highnybbles[(bank)] = (value) & 0x0F; \ + else \ + lownybbles[(bank)] = (value) & 0x0F; \ + mmc_bankvrom(1, (bank) << 10, (highnybbles[(bank)] << 4)+lownybbles[(bank)]); \ +} + +static struct +{ + int counter, enabled; + int latch, wait_state; +} irq; + +static int select_c000 = 0; +static uint8 lownybbles[8]; +static uint8 highnybbles[8]; + +static void vrc_init(void) +{ + irq.counter = irq.enabled = 0; + irq.latch = irq.wait_state = 0; +} + +static void map21_write(uint32 address, uint8 value) +{ + switch (address) + { + case 0x8000: + if (select_c000) + mmc_bankrom(8, 0xC000,value); + else + mmc_bankrom(8, 0x8000,value); + break; + + case 0x9000: + switch (value & 3) + { + case 0: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 1: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 2: + ppu_mirror(0, 0, 0, 0); + break; + + case 3: + ppu_mirror(1, 1, 1, 1); + break; + + default: + break; + } + break; + case 0x9002: select_c000=(value&0x02)>>1; break; + case 0xA000: mmc_bankrom(8, 0xA000,value); break; + + case 0xB000: VRC_VBANK(0,value,0); break; + case 0xB002: + case 0xB040: VRC_VBANK(0,value,1); break; + case 0xB001: + case 0xB004: + case 0xB080: VRC_VBANK(1,value,0); break; + case 0xB003: + case 0xB006: + case 0xB0C0: VRC_VBANK(1,value,1); break; + case 0xC000: VRC_VBANK(2,value,0); break; + case 0xC002: + case 0xC040: VRC_VBANK(2,value,1); break; + case 0xC001: + case 0xC004: + case 0xC080: VRC_VBANK(3,value,0); break; + case 0xC003: + case 0xC006: + case 0xC0C0: VRC_VBANK(3,value,1); break; + case 0xD000: VRC_VBANK(4,value,0); break; + case 0xD002: + case 0xD040: VRC_VBANK(4,value,1); break; + case 0xD001: + case 0xD004: + case 0xD080: VRC_VBANK(5,value,0); break; + case 0xD003: + case 0xD006: + case 0xD0C0: VRC_VBANK(5,value,1); break; + case 0xE000: VRC_VBANK(6,value,0); break; + case 0xE002: + case 0xE040: VRC_VBANK(6,value,1); break; + case 0xE001: + case 0xE004: + case 0xE080: VRC_VBANK(7,value,0); break; + case 0xE003: + case 0xE006: + case 0xE0C0: VRC_VBANK(7,value,1); break; + + case 0xF000: + irq.latch &= 0xF0; + irq.latch |= (value & 0x0F); + break; + case 0xF002: + case 0xF040: + irq.latch &= 0x0F; + irq.latch |= ((value & 0x0F) << 4); + break; + case 0xF004: + case 0xF001: + case 0xF080: + irq.enabled = (value >> 1) & 0x01; + irq.wait_state = value & 0x01; + irq.counter = irq.latch; + break; + case 0xF006: + case 0xF003: + case 0xF0C0: + irq.enabled = irq.wait_state; + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("wrote $%02X to $%04X", value, address); +#endif + break; + } +} + +static void map22_write(uint32 address, uint8 value) +{ + int reg = address >> 12; + + switch (reg) + { + case 0x8: + mmc_bankrom(8, 0x8000, value); + break; + + case 0xA: + mmc_bankrom(8, 0xA000, value); + break; + + case 0x9: + switch (value & 3) + { + case 0: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 1: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 2: + ppu_mirror(1, 1, 1, 1); + break; + + case 3: + ppu_mirror(0, 0, 0, 0); + break; + } + break; + + case 0xB: + case 0xC: + case 0xD: + case 0xE: + { + int loc = (((reg - 0xB) << 1) + (address & 1)) << 10; + mmc_bankvrom(1, loc, value >> 1); + } + break; + + default: + break; + } +} + +static void map23_write(uint32 address, uint8 value) +{ + switch (address) + { + case 0x8000: + case 0x8FFF: + mmc_bankrom(8, 0x8000, value); + break; + + case 0xA000: + case 0xAFFF: + mmc_bankrom(8, 0xA000, value); + break; + + case 0x9000: + case 0x9004: + case 0x9008: + switch(value & 3) + { + case 0: + ppu_mirror(0, 1, 0, 1); /* vertical */ + break; + + case 1: + ppu_mirror(0, 0, 1, 1); /* horizontal */ + break; + + case 2: + ppu_mirror(0, 0, 0, 0); + break; + + case 3: + ppu_mirror(1, 1, 1, 1); + break; + } + break; + + case 0xB000: VRC_VBANK(0,value,0); break; + case 0xB001: + case 0xB004: VRC_VBANK(0,value,1); break; + case 0xB002: + case 0xB008: VRC_VBANK(1,value,0); break; + case 0xB003: + case 0xB00C: VRC_VBANK(1,value,1); break; + case 0xC000: VRC_VBANK(2,value,0); break; + case 0xC001: + case 0xC004: VRC_VBANK(2,value,1); break; + case 0xC002: + case 0xC008: VRC_VBANK(3,value,0); break; + case 0xC003: + case 0xC00C: VRC_VBANK(3,value,1); break; + case 0xD000: VRC_VBANK(4,value,0); break; + case 0xD001: + case 0xD004: VRC_VBANK(4,value,1); break; + case 0xD002: + case 0xD008: VRC_VBANK(5,value,0); break; + case 0xD003: + case 0xD00C: VRC_VBANK(5,value,1); break; + case 0xE000: VRC_VBANK(6,value,0); break; + case 0xE001: + case 0xE004: VRC_VBANK(6,value,1); break; + case 0xE002: + case 0xE008: VRC_VBANK(7,value,0); break; + case 0xE003: + case 0xE00C: VRC_VBANK(7,value,1); break; + + case 0xF000: + irq.latch &= 0xF0; + irq.latch |= (value & 0x0F); + break; + + case 0xF004: + irq.latch &= 0x0F; + irq.latch |= ((value & 0x0F) << 4); + break; + + case 0xF008: + irq.enabled = (value >> 1) & 0x01; + irq.wait_state = value & 0x01; + irq.counter = irq.latch; + break; + + case 0xF00C: + irq.enabled = irq.wait_state; + break; + + default: +#ifdef NOFRENDO_DEBUG + log_printf("wrote $%02X to $%04X",value,address); +#endif + break; + } +} + +static void vrc_hblank(int vblank) +{ + UNUSED(vblank); + + if (irq.enabled) + { + if (256 == ++irq.counter) + { + irq.counter = irq.latch; + nes_irq(); + //irq.enabled = false; + irq.enabled = irq.wait_state; + } + } +} + + + +static map_memwrite map21_memwrite[] = +{ + { 0x8000, 0xFFFF, map21_write }, + { -1, -1, NULL } +}; + +static map_memwrite map22_memwrite[] = +{ + { 0x8000, 0xFFFF, map22_write }, + { -1, -1, NULL } +}; + +static map_memwrite map23_memwrite[] = +{ + { 0x8000, 0xFFFF, map23_write }, + { -1, -1, NULL } +}; + +static void map21_getstate(SnssMapperBlock *state) +{ + state->extraData.mapper21.irqCounter = irq.counter; + state->extraData.mapper21.irqCounterEnabled = irq.enabled; +} + +static void map21_setstate(SnssMapperBlock *state) +{ + irq.counter = state->extraData.mapper21.irqCounter; + irq.enabled = state->extraData.mapper21.irqCounterEnabled; +} + +mapintf_t map21_intf = +{ + 21, /* mapper number */ + "Konami VRC4 A", /* mapper name */ + vrc_init, /* init routine */ + NULL, /* vblank callback */ + vrc_hblank, /* hblank callback */ + map21_getstate, /* get state (snss) */ + map21_setstate, /* set state (snss) */ + NULL, /* memory read structure */ + map21_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +mapintf_t map22_intf = +{ + 22, /* mapper number */ + "Konami VRC2 A", /* mapper name */ + vrc_init, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map22_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +mapintf_t map23_intf = +{ + 23, /* mapper number */ + "Konami VRC2 B", /* mapper name */ + vrc_init, /* init routine */ + NULL, /* vblank callback */ + vrc_hblank, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map23_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +mapintf_t map25_intf = +{ + 25, /* mapper number */ + "Konami VRC4 B", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + vrc_hblank, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + map21_memwrite, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: mapvrc.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:33 matt +** changed directory structure +** +** Revision 1.10 2000/10/22 19:17:46 matt +** mapper cleanups galore +** +** Revision 1.9 2000/10/22 15:03:14 matt +** simplified mirroring +** +** Revision 1.8 2000/10/21 19:33:38 matt +** many more cleanups +** +** Revision 1.7 2000/10/10 13:58:17 matt +** stroustrup squeezing his way in the door +** +** Revision 1.6 2000/08/16 02:50:11 matt +** random mapper cleanups +** +** Revision 1.5 2000/07/15 23:52:20 matt +** rounded out a bunch more mapper interfaces +** +** Revision 1.4 2000/07/10 13:51:25 matt +** using generic nes_irq() routine now +** +** Revision 1.3 2000/07/10 05:29:03 matt +** cleaned up some mirroring issues +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/06 01:01:56 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/mappers/map000.c =================================================================== --- apps/plugins/nofrendo/mappers/map000.c (revision 0) +++ apps/plugins/nofrendo/mappers/map000.c (revision 0) @@ -0,0 +1,63 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** map0.c +** +** mapper 0 interface +** $Id: map000.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include + +mapintf_t map0_intf = +{ + 0, /* mapper number */ + "None", /* mapper name */ + NULL, /* init routine */ + NULL, /* vblank callback */ + NULL, /* hblank callback */ + NULL, /* get state (snss) */ + NULL, /* set state (snss) */ + NULL, /* memory read structure */ + NULL, /* memory write structure */ + NULL /* external sound device */ +}; + +/* +** $Log: map000.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:32 matt +** changed directory structure +** +** Revision 1.2 2000/07/06 02:48:43 matt +** clearly labelled structure members +** +** Revision 1.1 2000/07/04 23:11:45 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_mmc.h =================================================================== --- apps/plugins/nofrendo/nes_mmc.h (revision 0) +++ apps/plugins/nofrendo/nes_mmc.h (revision 0) @@ -0,0 +1,146 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_mmc.h +** +** NES Memory Management Controller (mapper) defines / prototypes +** $Id: nes_mmc.h,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#ifndef _NES_MMC_H_ +#define _NES_MMC_H_ + +#include +#include + +#define MMC_LASTBANK -1 + +typedef struct +{ + uint32 min_range, max_range; + uint8 (*read_func)(uint32 address); +} map_memread; + +typedef struct +{ + uint32 min_range, max_range; + void (*write_func)(uint32 address, uint8 value); +} map_memwrite; + + +typedef struct mapintf_s +{ + int number; + char *name; + void (*init)(void); + void (*vblank)(void); + void (*hblank)(int vblank); + void (*get_state)(SnssMapperBlock *state); + void (*set_state)(SnssMapperBlock *state); + map_memread *mem_read; + map_memwrite *mem_write; + apuext_t *sound_ext; +} mapintf_t; + + +#include +typedef struct mmc_s +{ + mapintf_t *intf; + rominfo_t *cart; /* link it back to the cart */ +} mmc_t; + +extern rominfo_t *mmc_getinfo(void); + +extern void mmc_bankvrom(int size, uint32 address, int bank); +extern void mmc_bankrom(int size, uint32 address, int bank); + +/* Prototypes */ +extern mmc_t *mmc_create(rominfo_t *rominfo); +extern void mmc_destroy(mmc_t **nes_mmc); + +extern void mmc_getcontext(mmc_t *dest_mmc); +extern void mmc_setcontext(mmc_t *src_mmc); + +extern int mmc_peek(int map_num); + +extern void mmc_reset(void); + +#endif /* _NES_MMC_H_ */ + +/* +** $Log: nes_mmc.h,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/10/25 00:23:16 matt +** makefiles updated for new directory structure +** +** Revision 1.1 2000/10/24 12:20:28 matt +** changed directory structure +** +** Revision 1.18 2000/10/22 19:17:24 matt +** mapper cleanups galore +** +** Revision 1.17 2000/10/21 19:26:59 matt +** many more cleanups +** +** Revision 1.16 2000/10/17 03:22:58 matt +** cleaning up rom module +** +** Revision 1.15 2000/10/10 13:58:15 matt +** stroustrup squeezing his way in the door +** +** Revision 1.14 2000/07/31 04:27:59 matt +** one million cleanups +** +** Revision 1.13 2000/07/25 02:25:53 matt +** safer xxx_destroy calls +** +** Revision 1.12 2000/07/17 01:52:28 matt +** made sure last line of all source files is a newline +** +** Revision 1.11 2000/07/15 23:50:03 matt +** migrated state get/set from nes_mmc.c to state.c +** +** Revision 1.10 2000/07/11 02:38:01 matt +** added setcontext() routine +** +** Revision 1.9 2000/07/10 05:27:41 matt +** cleaned up mapper-specific callbacks +** +** Revision 1.8 2000/07/04 23:12:58 matt +** brand spankin' new mapper interface implemented +** +** Revision 1.7 2000/07/04 04:56:36 matt +** modifications for new SNSS +** +** Revision 1.6 2000/06/29 14:17:18 matt +** uses snsslib now +** +** Revision 1.5 2000/06/29 03:09:24 matt +** modified to support new snss code +** +** Revision 1.4 2000/06/09 15:12:26 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/gui_elem.h =================================================================== --- apps/plugins/nofrendo/gui_elem.h (revision 0) +++ apps/plugins/nofrendo/gui_elem.h (revision 0) @@ -0,0 +1,68 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** gui_elem.h +** +** GUI elements (font, mouse pointer, etc.) +** $Id: gui_elem.h,v 1.1.1.1 2001/04/27 07:03:54 neil Exp $ +*/ + +#ifndef _GUI_ELEM_H_ +#define _GUI_ELEM_H_ + +typedef struct fontchar_s +{ + uint8 lines[6]; + uint8 spacing; +} fontchar_t; + +typedef struct font_s +{ + fontchar_t *character; + uint8 height; +} font_t; + +extern font_t small; + +#define CURSOR_WIDTH 11 +#define CURSOR_HEIGHT 19 + +extern const uint8 cursor_color[]; +extern const uint8 cursor[]; + +#endif /* _GUI_ELEM_H_ */ + +/* +** $Log: gui_elem.h,v $ +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.7 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.6 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.5 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/SOURCES =================================================================== --- apps/plugins/nofrendo/SOURCES (revision 0) +++ apps/plugins/nofrendo/SOURCES (revision 0) @@ -0,0 +1,67 @@ +bitmap.c +config.c +dis6502.c +event.c +fds_snd.c +gui.c +gui_elem.c +intro.c +libsnss.c +log.c +memguard.c +mmc5_snd.c +mmclist.c +nes6502.c +nes_apu.c +nes.c +nesinput.c +nes_mmc.c +nes_pal.c +nes_ppu.c +nes_rom.c +nesstate.c +nofrendo.c +pcx.c +sys_rockbox.c +vid_drv.c +vrcvisnd.c +mappers/map000.c +mappers/map001.c +mappers/map002.c +mappers/map003.c +mappers/map004.c +mappers/map005.c +mappers/map007.c +mappers/map008.c +mappers/map009.c +mappers/map011.c +mappers/map015.c +mappers/map016.c +mappers/map018.c +mappers/map019.c +mappers/map024.c +mappers/map032.c +mappers/map033.c +mappers/map034.c +mappers/map040.c +mappers/map041.c +mappers/map042.c +mappers/map046.c +mappers/map050.c +mappers/map064.c +mappers/map065.c +mappers/map066.c +mappers/map070.c +mappers/map073.c +mappers/map075.c +mappers/map078.c +mappers/map079.c +mappers/map085.c +mappers/map087.c +mappers/map093.c +mappers/map094.c +mappers/map099.c +mappers/map160.c +mappers/map229.c +mappers/map231.c +mappers/mapvrc.c Index: apps/plugins/nofrendo/sys_rockbox.c =================================================================== --- apps/plugins/nofrendo/sys_rockbox.c (revision 0) +++ apps/plugins/nofrendo/sys_rockbox.c (revision 0) @@ -0,0 +1,401 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "plugin.h" +PLUGIN_HEADER + +/*-----------*\ +**---MAIN----** +\*-----------*/ + +enum plugin_status plugin_start(const void* parameter) +{ + rb->lcd_clear_display(); + if ( !start(parameter) ) + { + rb->splash(HZ, "I'm afraid I can't do that, Dave..."); + extern shutdown_everything(); + return PLUGIN_ERROR; + } + return PLUGIN_OK; +} + +/*-----------*\ +**---VIDEO---** +\*-----------*/ + +#define DEFAULT_WIDTH 256 +#define DEFAULT_HEIGHT NES_VISIBLE_HEIGHT + +static int init(int width, int height); +static void shutdown(void); +static int set_mode(int width, int height); +static void set_palette(rgb_t *pal); +static void clear(uint8 color); +static bitmap_t *lock_write(void); +static void free_write(int num_dirties, rect_t *dirty_rects); + +viddriver_t lcdDriver = +{ + "Rockbox", /* name */ + init, /* init */ + shutdown, /* shutdown */ + set_mode, /* set_mode */ + set_palette, /* set_palette */ + clear, /* clear */ + lock_write, /* lock_write */ + free_write, /* free_write */ + NULL, /* custom_blit */ + false /* invalidate flag */ +}; + +static bitmap_t *myBitmap = NULL; + +static int init(int width, int height) +{ +} + +static void shutdown(void) +{ +} + +static int set_mode(int width, int height) +{ +} + +static void set_palette(rgb_t *pal) +{ + +} + +static void clear(uint8 color) +{ + rb->lcd_set_foreground(color); +} + +static bitmap_t *lock_write(void) +{ + myBitmap = rb->lcd_framebuffer; + return myBitmap; +} + +static void free_write(int num_dirties, rect_t *dirty_rects) +{ + bmp_destroy(&myBitmap); + +} + +void osd_getvideoinfo(vidinfo_t *info) +{ + info->default_width = DEFAULT_WIDTH; + info->default_height = DEFAULT_HEIGHT; + info->driver = &lcdDriver; +} + +/*-----------*\ +**---SOUND---** +\*-----------*/ + +#define DEFAULT_SAMPLERATE 22050 +#define DEFAULT_BPS 8 +#define DEFAULT_FRAGSIZE 1024 + +static int sound_bps = DEFAULT_BPS; +static int sound_samplerate = DEFAULT_SAMPLERATE; +static int sound_fragsize = DEFAULT_FRAGSIZE; +static unsigned char *audioBuffer = NULL; +static void (*audio_callback)(void *buffer, int length) = NULL; + +static int osd_init_sound(void) +{ +} + +void osd_setsound(void (*playfunc)(void *buffer, int length)) +{ + audio_callback = playfunc; +} + +static void osd_stopsound(void) +{ + +} + +void osd_getsoundinfo(sndinfo_t *info) +{ + info->sample_rate = sound_samplerate; + info->bps = sound_bps; +} + +/*-----------*\ +**---MISC----** +\*-----------*/ + +int osd_installtimer(int frequency, void *func, int funcsize, void *counter, int countersize) +{ + return 0; +} + +/* path must be a valid path, and therefore no longer than PATH_MAX */ +static void addSlash(char *path) +{ + int len = strlen(path); + if(path[len - 1] != '/' && len + 1 <= PATH_MAX) + { + path[len] = '/'; + path[++len] = 0; + } +} + +/* filename must be a valid filename, and therefore no longer than PATH_MAX */ +static void removePath(char *filename) +{ + char temp[PATH_MAX + 1]; + int i; + + i = strlen(filename); + while(filename[--i] != '/' && i > 0); + + if(filename[i] == '/') + { + strncpy(temp, (filename + i + 1), PATH_MAX); + strncpy(filename, temp, PATH_MAX); + } +} + +/* if filename ends in extension, cut it off of filename */ +static void removeExtension(char *filename, const char *extension) +{ + int i = strlen(filename); + int j = strlen(extension); + + if(i <= j) return; + + while(i && j) + { + i--; + j--; + if(filename[i] != extension[j]) return; + } + filename[i] = 0; +} + +/* this determines where to store our data files */ +static const char *dataDirectory(void) +{ + static char dataPath[PATH_MAX + 1]; + static bool checked = false; + + if(!checked) + { + checked = true; + char temp[PATH_MAX + 1]; + addSlash(temp); + strcat(temp, ".rockbox/nofrendo"); + strncpy(dataPath, temp, PATH_MAX); + addSlash(dataPath); + } + return dataPath; +} + +/* File system interface */ +void osd_fullname(char *fullname, const char *shortname) +{ + strncpy(fullname, shortname, PATH_MAX); +} + +/* This gives filenames for storage of saves */ +char *osd_newextension(char *string, char *ext) +{ + char name[PATH_MAX + 1]; + + removePath(string); + removeExtension(string, ".gz"); + removeExtension(string, ".bz2"); + + strncpy(name, dataDirectory(), PATH_MAX); + strcat(name, string); + strcat(name, ext); + strcpy(string, name); + + return string; +} + +int osd_makesnapname(char *filename, int len) +{ + return -1; +} + +/*-----------*\ +**---INPUT---** +\*-----------*/ + +static void osd_initinput() +{ +} + +#ifdef HAVE_SCROLLWHEEL +/* Scrollwheel events are posted directly and not polled by the button + driver - synthesize polling */ +static inline unsigned int read_scroll_wheel(void) +{ + unsigned int buttons = BUTTON_NONE; + unsigned int btn; + + /* Empty out the button queue and see if any scrollwheel events were + posted */ + do + { + btn = rb->button_get_w_tmo(0); + buttons |= btn; + } + while (btn != BUTTON_NONE); + + return buttons & (SCROLL_CC | SCROLL_CW); +} +#endif + +void osd_getinput(void) +{ + int status; + status = rb->button_status(); + +#ifdef HAVE_SCROLLWHEEL + status |= read_scroll_wheel(); +#endif + + switch (status) + { + case NES_BUTTON_UP: + event_joypad1_up; + break; + case NES_BUTTON_DOWN: + event_joypad1_down; + break; + case NES_BUTTON_LEFT: + event_joypad1_left; + break; + case NES_BUTTON_RIGHT: + event_joypad1_right; + break; + case NES_BUTTON_A: + event_joypad1_a; + break; + case NES_BUTTON_B: + event_joypad1_b; + break; + case NES_BUTTON_SELECT: + event_joypad1_select; + break; + case NES_BUTTON_START: + event_joypad1_start; + break; + case NES_BUTTON_MENU: + menu(); + break; + default: + break; + } +} + +static void osd_freeinput(void) +{ +} + +int osd_main(int filename) +{ + static char configfilename[PATH_MAX + 1]; + strncpy(configfilename, dataDirectory(), PATH_MAX); + strcat(configfilename, "config"); + config.filename = configfilename; + return main_loop(filename, system_autodetect); +} + +void osd_shutdown() +{ + osd_stopsound(); + osd_freeinput(); +} + +int osd_init() +{ + if (osd_init_sound()) + return -1; + + osd_initinput(); + + return 0; +} + +/*-----------*\ +**---MENU----** +\*-----------*/ + +void menu(void) +{ + MENUITEM_STRINGLIST(menu, "Menu", NULL, "Load", "Save", "Video", "Sound", "Quit"); + + switch (rb->do_menu(&menu, NULL, NULL, false)) + { + case 0: + //load_state(); + break; + case 1: + //save_state(); + break; + case 2: + video_menu(); + break; + case 3: + sound_menu(); + break; + case 4: + return PLUGIN_OK; + default: + break; + } + return; +} + +void sound_menu(void) +{ + MENUITEM_STRINGLIST(smenu, "Sound", NULL, "On", "Off"); + + switch(rb->do_menu(&smenu, NULL, NULL, false)) + { + case 0: + //sound_enable(); + break; + case 1: + //sound_disable(); + break; + default: + break; + } +} + +void video_menu(void) +{ + MENUITEM_STRINGLIST(smenu, "Video", NULL, "Display Size", "Frameskip"); + + switch(rb->do_menu(&smenu, NULL, NULL, false)) + { + case 0: + //set_display_size(); + break; + case 1: + //set_frameskip(); + break; + default: + break; + } +} Index: apps/plugins/nofrendo/README =================================================================== --- apps/plugins/nofrendo/README (revision 0) +++ apps/plugins/nofrendo/README (revision 0) @@ -0,0 +1,115 @@ +Nofrendo 2.0pre1 - May 5, 2001 + +Nofrendo (c) Matt Conte +Nofrendo SDL release by Neil Stevens + +To compile and install, do configure, then make, then make install +as you would any other GNU automake-using source release. You may +want to try passing --enable-optimize to configure. + +SDL 1.2 is required because recent SDL releases can speed nofrendo +a lot on X displays with more colors. + +The key to an enjoyable Nofrendo experience is $HOME/.nofrendo. In +there are all the saves, snapshots (still PCX, but that'll be fixed), +and the config. + +config is auto-generated, so don't edit it while nofrendo is running. +Do feel free to edit it while nofrendo is not running, however. Comments +are not preserved, but the data is preserved. The enum in src/event.h is +of interest to those who want to configure their joysticks and keyboard +input. + +Nope, it's not easy to configure yet, but that will come in time. This +release is long overdue, so a nice UI will have to wait for a later +release. + +In the meantime, here are the default controls, and some hints for +joystick configuration. Forgive if they are unclear, for this is hastily +done, and will be improved later. + +(KP means numeric keypad. non-KP numbers refer to the numbers above the +letters on a standard keyboard) + +Esc - quit +F1 - soft reset +F2 - hard reset +F3 - toggle FPS display +F4 - take snapshot +F6 - toggle sprites +F10 - toggle fullscreen +Pause - Pause emulation +Space - toggle GUI +KP+ - toggle speed regulation + +0-9 - set save state 0-9 +F5 - save state +F7 - load state + +Backspace - display information + +q - toggle sound channel 0 +w - toggle sound channel 1 +e - toggle sound channel 2 +r - toggle sound channel 3 +t - toggle sound channel 4 +y - toggle sound channel 5 +a - toggle wave display +s - sound filter off +d - sound filter mode 1 +f - sound filter mode 2 + +KP2 - Joypad 1 down +Down - Joypad 1 down +KP4 - Joypad 1 left +Left - Joypad 1 left +KP6 - Joypad 1 right +Right - Joypad 1 right +KP8 - Joypad 1 up +Up - Joypad 1 up + +Return - Joypad 1 Start +Tab - Joypad 1 Select + +z - Joypad 1 b +x - Joypad 1 a +c - Joypad 1 Select +v - Joypad 1 Start + +Ctrl - Joypad 1 b +Alt - Joypad 1 a +Shift - Joypad 1 a + +b - Joypad 2 b +n - Joypad 2 a +m - Joypad 2 Select +, - Joypad 2 Start + + +Here's an excerpt from Neil's config, for use with an SNES pad: + +[sdljoystick0] +button0=45 +button1=46 +button2=0 +button3=0 +button4=0 +button5=0 +button6=48 +button7=47 +negativeaxis0=51 +negativeaxis1=49 +positiveaxis0=52 +positiveaxis1=50 + +Your joystick probably varies, so here are the numbers to use, if you're not +comfortable with reading the C code to find them out: + +45 - Joypad 1 a +46 - Joypad 1 b +47 - Joypad 1 start +48 - Joypad 1 select +49 - Joypad 1 right +50 - Joypad 1 down +51 - Joypad 1 left +52 - Joypad 1 right Index: apps/plugins/nofrendo/libsnss.c =================================================================== --- apps/plugins/nofrendo/libsnss.c (revision 0) +++ apps/plugins/nofrendo/libsnss.c (revision 0) @@ -0,0 +1,805 @@ +/**************************************************************************/ +/* + libsnss.c + + (C) 2000 The SNSS Group + See README.TXT file for license and terms of use. + + $Id: libsnss.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ +/**************************************************************************/ + +#include +#include +#include +#include +#include + +/**************************************************************************/ +/* support functions */ +/**************************************************************************/ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadBlockHeader (SnssBlockHeader *header, SNSS_FILE *snssFile) +{ + char headerBytes[12]; + + if (read (snssFile->fp, headerBytes, 12) != 1) + { + return SNSS_READ_FAILED; + } + + strncpy (header->tag, &headerBytes[0], TAG_LENGTH); + header->tag[4] = '\0'; + header->blockVersion = *((unsigned int *) &headerBytes[4]); + header->blockVersion = swap32 (header->blockVersion); + header->blockLength = *((unsigned int *) &headerBytes[8]); + header->blockLength = swap32 (header->blockLength); + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteBlockHeader (SnssBlockHeader *header, SNSS_FILE *snssFile) +{ + char headerBytes[12]; + unsigned int tempInt; + + strncpy (&headerBytes[0], header->tag, TAG_LENGTH); + + tempInt = swap32 (header->blockVersion); + headerBytes[4] = ((char *) &tempInt)[0]; + headerBytes[5] = ((char *) &tempInt)[1]; + headerBytes[6] = ((char *) &tempInt)[2]; + headerBytes[7] = ((char *) &tempInt)[3]; + + tempInt = swap32 (header->blockLength); + headerBytes[8] = ((char *) &tempInt)[0]; + headerBytes[9] = ((char *) &tempInt)[1]; + headerBytes[10] = ((char *) &tempInt)[2]; + headerBytes[11] = ((char *) &tempInt)[3]; + + if (write (snssFile->fp, headerBytes, 12) != 1) + { + return SNSS_WRITE_FAILED; + } + + return SNSS_OK; +} + +/**************************************************************************/ + +const char * +SNSS_GetErrorString (SNSS_RETURN_CODE code) +{ + switch (code) + { + case SNSS_OK: + return "no error"; + + case SNSS_BAD_FILE_TAG: + return "not an SNSS file"; + + case SNSS_OPEN_FAILED: + return "could not open SNSS file"; + + case SNSS_CLOSE_FAILED: + return "could not close SNSS file"; + + case SNSS_READ_FAILED: + return "could not read from SNSS file"; + + case SNSS_WRITE_FAILED: + return "could not write to SNSS file"; + + case SNSS_OUT_OF_MEMORY: + return "out of memory"; + + case SNSS_UNSUPPORTED_BLOCK: + return "unsupported block type"; + + default: + return "unknown error"; + } +} + +/**************************************************************************/ +/* functions for reading and writing SNSS file headers */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadFileHeader (SNSS_FILE *snssFile) +{ + if (read (snssFile->fp, snssFile->headerBlock.tag, 4) != 1) + { + return SNSS_READ_FAILED; + } + + if (0 != strncmp(snssFile->headerBlock.tag, "SNSS", 4)) + { + return SNSS_BAD_FILE_TAG; + } + + snssFile->headerBlock.tag[4] = '\0'; + + if (read (snssFile->fp, &snssFile->headerBlock.numberOfBlocks, sizeof (unsigned int)) != 1) + { + return SNSS_READ_FAILED; + } + + snssFile->headerBlock.numberOfBlocks = swap32 (snssFile->headerBlock.numberOfBlocks); + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteFileHeader (SNSS_FILE *snssFile) +{ + unsigned int tempInt; + char writeBuffer[8]; + + /* always place the SNSS tag in this field */ + strncpy (&writeBuffer[0], "SNSS", 4); + tempInt = swap32 (snssFile->headerBlock.numberOfBlocks); + writeBuffer[4] = ((char *) &tempInt)[0]; + writeBuffer[5] = ((char *) &tempInt)[1]; + writeBuffer[6] = ((char *) &tempInt)[2]; + writeBuffer[7] = ((char *) &tempInt)[3]; + + if (write (snssFile->fp, writeBuffer, 8) != 1) + { + return SNSS_WRITE_FAILED; + } + + return SNSS_OK; +} + +/**************************************************************************/ +/* general file manipulation functions */ +/**************************************************************************/ +SNSS_RETURN_CODE +SNSS_OpenFile (SNSS_FILE **snssFile, const char *filename, SNSS_OPEN_MODE mode) +{ + *snssFile = malloc(sizeof(SNSS_FILE)); + if (NULL == *snssFile) + { + return SNSS_OUT_OF_MEMORY; + } + + /* zero the memory */ + memset (*snssFile, 0, sizeof(SNSS_FILE)); + + (*snssFile)->mode = mode; + + if (SNSS_OPEN_READ == mode) + { + (*snssFile)->fp = rb->open(filename, O_RDONLY); + } + else + { + (*snssFile)->fp = rb->open(filename, O_WRONLY); + (*snssFile)->headerBlock.numberOfBlocks = 0; + } + + if (NULL == (*snssFile)->fp) + { + free(*snssFile); + *snssFile = NULL; + return SNSS_OPEN_FAILED; + } + + if (SNSS_OPEN_READ == mode) + { + return SNSS_ReadFileHeader(*snssFile); + } + else + { + return SNSS_WriteFileHeader(*snssFile); + } +} + +/**************************************************************************/ + +SNSS_RETURN_CODE +SNSS_CloseFile (SNSS_FILE **snssFile) +{ + int prevLoc; + SNSS_RETURN_CODE code; + + /* file was never open, so this should indicate success- kinda. */ + if (NULL == *snssFile) + { + return SNSS_OK; + } + + if (SNSS_OPEN_WRITE == (*snssFile)->mode) + { + //prevLoc = ftell((*snssFile)->fp); + lseek((*snssFile)->fp, 0, SEEK_SET); + + /* write the header again to update block count */ + if (SNSS_OK != (code = SNSS_WriteFileHeader(*snssFile))) + { + return SNSS_CLOSE_FAILED; + } + + lseek((*snssFile)->fp, prevLoc, SEEK_SET); + } + + if (rb->close ((*snssFile)->fp) != 0) + { + return SNSS_CLOSE_FAILED; + } + + free(*snssFile); + *snssFile = NULL; + + return SNSS_OK; +} + +/**************************************************************************/ + +SNSS_RETURN_CODE +SNSS_GetNextBlockType (SNSS_BLOCK_TYPE *blockType, SNSS_FILE *snssFile) +{ + char tagBuffer[TAG_LENGTH + 1]; + + if (read(snssFile->fp, tagBuffer, TAG_LENGTH) != 1) + { + return SNSS_READ_FAILED; + } + tagBuffer[TAG_LENGTH] = '\0'; + + /* reset the file pointer to the start of the block */ + if (lseek (snssFile->fp, -TAG_LENGTH, SEEK_CUR) != 0) + { + return SNSS_READ_FAILED; + } + + /* figure out which type of block it is */ + if (strcmp (tagBuffer, "BASR") == 0) + { + *blockType = SNSS_BASR; + } + else if (strcmp (tagBuffer, "VRAM") == 0) + { + *blockType = SNSS_VRAM; + } + else if (strcmp (tagBuffer, "SRAM") == 0) + { + *blockType = SNSS_SRAM; + } + else if (strcmp (tagBuffer, "MPRD") == 0) + { + *blockType = SNSS_MPRD; + } + else if (strcmp (tagBuffer, "CNTR") == 0) + { + *blockType = SNSS_CNTR; + } + else if (strcmp (tagBuffer, "SOUN") == 0) + { + *blockType = SNSS_SOUN; + } + else + { + *blockType = SNSS_UNKNOWN_BLOCK; + } + + return SNSS_OK; +} + +/**************************************************************************/ + +SNSS_RETURN_CODE +SNSS_SkipNextBlock (SNSS_FILE *snssFile) +{ + unsigned int blockLength; + + /* skip the block's tag and version */ + if (lseek (snssFile->fp, TAG_LENGTH + sizeof (unsigned int), SEEK_CUR) != 0) + { + return SNSS_READ_FAILED; + } + + /* get the block data length */ + if (read(snssFile->fp, &blockLength, sizeof (unsigned int)) != 1) + { + return SNSS_READ_FAILED; + } + blockLength = swap32 (blockLength); + + /* skip over the block data */ + if (lseek (snssFile->fp, blockLength, SEEK_CUR) != 0) + { + return SNSS_READ_FAILED; + } + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing base register blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadBaseBlock (SNSS_FILE *snssFile) +{ + char blockBytes[BASE_BLOCK_LENGTH]; + SnssBlockHeader header; + + if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) + { + return SNSS_READ_FAILED; + } + + if (read(snssFile->fp, blockBytes, MIN (header.blockLength, BASE_BLOCK_LENGTH)) != 1) + { + return SNSS_READ_FAILED; + } + + snssFile->baseBlock.regA = blockBytes[0x0]; + snssFile->baseBlock.regX = blockBytes[0x1]; + snssFile->baseBlock.regY = blockBytes[0x2]; + snssFile->baseBlock.regFlags = blockBytes[0x3]; + snssFile->baseBlock.regStack = blockBytes[0x4]; + snssFile->baseBlock.regPc = *((unsigned short *) &blockBytes[0x5]); + snssFile->baseBlock.regPc = swap16 (snssFile->baseBlock.regPc); + snssFile->baseBlock.reg2000 = blockBytes[0x7]; + snssFile->baseBlock.reg2001 = blockBytes[0x8]; + memcpy (&snssFile->baseBlock.cpuRam, &blockBytes[0x9], 0x800); + memcpy (&snssFile->baseBlock.spriteRam, &blockBytes[0x809], 0x100); + memcpy (&snssFile->baseBlock.ppuRam, &blockBytes[0x909], 0x1000); + memcpy (&snssFile->baseBlock.palette, &blockBytes[0x1909], 0x20); + memcpy (&snssFile->baseBlock.mirrorState, &blockBytes[0x1929], 0x4); + snssFile->baseBlock.vramAddress = *((unsigned short *) &blockBytes[0x192D]); + snssFile->baseBlock.vramAddress = swap16 (snssFile->baseBlock.vramAddress); + snssFile->baseBlock.spriteRamAddress = blockBytes[0x192F]; + snssFile->baseBlock.tileXOffset = blockBytes[0x1930]; + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteBaseBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + SNSS_RETURN_CODE returnCode; + char blockBytes[BASE_BLOCK_LENGTH]; + unsigned short tempShort; + + strcpy (header.tag, "BASR"); + header.blockVersion = SNSS_BLOCK_VERSION; + header.blockLength = BASE_BLOCK_LENGTH; + + if ((returnCode = SNSS_WriteBlockHeader (&header, snssFile)) != SNSS_OK) + { + return returnCode; + } + + blockBytes[0x0] = snssFile->baseBlock.regA; + blockBytes[0x1] = snssFile->baseBlock.regX; + blockBytes[0x2] = snssFile->baseBlock.regY; + blockBytes[0x3] = snssFile->baseBlock.regFlags; + blockBytes[0x4] = snssFile->baseBlock.regStack; + tempShort = swap16 (snssFile->baseBlock.regPc); + blockBytes[0x5] = ((char *) &tempShort)[0]; + blockBytes[0x6] = ((char *) &tempShort)[1]; + blockBytes[0x7] = snssFile->baseBlock.reg2000; + blockBytes[0x8] = snssFile->baseBlock.reg2001; + memcpy (&blockBytes[0x9], &snssFile->baseBlock.cpuRam, 0x800); + memcpy (&blockBytes[0x809], &snssFile->baseBlock.spriteRam, 0x100); + memcpy (&blockBytes[0x909], &snssFile->baseBlock.ppuRam, 0x1000); + memcpy (&blockBytes[0x1909], &snssFile->baseBlock.palette, 0x20); + memcpy (&blockBytes[0x1929], &snssFile->baseBlock.mirrorState, 0x4); + tempShort = swap16 (snssFile->baseBlock.vramAddress); + blockBytes[0x192D] = ((char *) &tempShort)[0]; + blockBytes[0x192E] = ((char *) &tempShort)[1]; + blockBytes[0x192F] = snssFile->baseBlock.spriteRamAddress; + blockBytes[0x1930] = snssFile->baseBlock.tileXOffset; + + if (write (snssFile->fp, blockBytes, BASE_BLOCK_LENGTH) != 1) + { + return SNSS_WRITE_FAILED; + } + + snssFile->headerBlock.numberOfBlocks++; + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing VRAM blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadVramBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + + if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) + { + return SNSS_READ_FAILED; + } + + if (read(snssFile->fp, snssFile->vramBlock.vram, MIN (header.blockLength, VRAM_16K)) != 1) + { + return SNSS_READ_FAILED; + } + + snssFile->vramBlock.vramSize = header.blockLength; + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteVramBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + SNSS_RETURN_CODE returnCode; + + strcpy (header.tag, "VRAM"); + header.blockVersion = SNSS_BLOCK_VERSION; + header.blockLength = snssFile->vramBlock.vramSize; + + if ((returnCode = SNSS_WriteBlockHeader (&header, snssFile)) != SNSS_OK) + { + return returnCode; + } + + if (write (snssFile->fp, snssFile->vramBlock.vram, snssFile->vramBlock.vramSize) != 1) + { + return SNSS_WRITE_FAILED; + } + + snssFile->headerBlock.numberOfBlocks++; + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing SRAM blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadSramBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + + if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) + { + return SNSS_READ_FAILED; + } + + if (read (snssFile->fp, &snssFile->sramBlock.sramEnabled, 1) != 1) + { + return SNSS_READ_FAILED; + } + + /* read blockLength - 1 bytes to get all of the SRAM */ + if (read (snssFile->fp, &snssFile->sramBlock.sram, MIN (header.blockLength - 1, SRAM_8K)) != 1) + { + return SNSS_READ_FAILED; + } + + /* SRAM size is the size of the block - 1 (SRAM enabled byte) */ + snssFile->sramBlock.sramSize = header.blockLength - 1; + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteSramBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + SNSS_RETURN_CODE returnCode; + + strcpy (header.tag, "SRAM"); + header.blockVersion = SNSS_BLOCK_VERSION; + /* length of block is size of SRAM plus SRAM enabled byte */ + header.blockLength = snssFile->sramBlock.sramSize + 1; + if ((returnCode = SNSS_WriteBlockHeader (&header, snssFile)) != SNSS_OK) + { + return returnCode; + } + + if (write (snssFile->fp, &snssFile->sramBlock.sramEnabled, 1) != 1) + { + return SNSS_WRITE_FAILED; + } + + if (write (snssFile->fp, snssFile->sramBlock.sram, snssFile->sramBlock.sramSize) != 1) + { + return SNSS_WRITE_FAILED; + } + + snssFile->headerBlock.numberOfBlocks++; + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing mapper data blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadMapperBlock (SNSS_FILE *snssFile) +{ + char *blockBytes; + int i; + SnssBlockHeader header; + + if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) + { + return SNSS_READ_FAILED; + } + + if ((blockBytes = (char *) malloc (0x8 + 0x10 + 0x80)) == NULL) + { + return SNSS_OUT_OF_MEMORY; + } + + if (read (snssFile->fp, blockBytes, MIN (0x8 + 0x10 + 0x80, header.blockLength)) != 1) + { + free(blockBytes); + return SNSS_READ_FAILED; + } + + for (i = 0; i < 4; i++) + { + snssFile->mapperBlock.prgPages[i] = *((unsigned short *) &blockBytes[i * 2]); + snssFile->mapperBlock.prgPages[i] = swap16 (snssFile->mapperBlock.prgPages[i]); + } + + for (i = 0; i < 8; i++) + { + snssFile->mapperBlock.chrPages[i] = *((unsigned short *) &blockBytes[0x8 + (i * 2)]); + snssFile->mapperBlock.chrPages[i] = swap16 (snssFile->mapperBlock.chrPages[i]); + } + + memcpy (&snssFile->mapperBlock.extraData.mapperData, &blockBytes[0x18], 0x80); + + free (blockBytes); + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteMapperBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + char blockBytes[MAPPER_BLOCK_LENGTH]; + unsigned short tempShort; + int i; + SNSS_RETURN_CODE returnCode; + + strcpy (header.tag, "MPRD"); + header.blockVersion = SNSS_BLOCK_VERSION; + header.blockLength = MAPPER_BLOCK_LENGTH; + + if ((returnCode = SNSS_WriteBlockHeader (&header, snssFile)) != SNSS_OK) + { + return returnCode; + } + + for (i = 0; i < 4; i++) + { + tempShort = swap16 (snssFile->mapperBlock.prgPages[i]); + blockBytes[(i * 2) + 0] = ((char *) &tempShort)[0]; + blockBytes[(i * 2) + 1] = ((char *) &tempShort)[1]; + } + + for (i = 0; i < 8; i++) + { + tempShort = swap16 (snssFile->mapperBlock.chrPages[i]); + blockBytes[0x8 + (i * 2) + 0] = ((char *) &tempShort)[0]; + blockBytes[0x8 + (i * 2) + 1] = ((char *) &tempShort)[1]; + } + + memcpy (&blockBytes[0x18], &snssFile->mapperBlock.extraData.mapperData, 0x80); + + if (write (snssFile->fp, blockBytes, MAPPER_BLOCK_LENGTH) != 1) + { + return SNSS_WRITE_FAILED; + } + + snssFile->headerBlock.numberOfBlocks++; + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing controller data blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadControllersBlock (SNSS_FILE *snssFile) +{ + /* quell warnings */ + snssFile = snssFile; + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteControllersBlock (SNSS_FILE *snssFile) +{ + /* quell warnings */ + snssFile = snssFile; + + return SNSS_OK; +} + +/**************************************************************************/ +/* functions for reading and writing sound blocks */ +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_ReadSoundBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + + if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) + { + return SNSS_READ_FAILED; + } + + if (read (snssFile->fp, snssFile->soundBlock.soundRegisters, MIN (header.blockLength, 0x16)) != 1) + { + return SNSS_READ_FAILED; + } + + return SNSS_OK; +} + +/**************************************************************************/ + +static SNSS_RETURN_CODE +SNSS_WriteSoundBlock (SNSS_FILE *snssFile) +{ + SnssBlockHeader header; + SNSS_RETURN_CODE returnCode; + + strcpy (header.tag, "SOUN"); + header.blockVersion = SNSS_BLOCK_VERSION; + header.blockLength = SOUND_BLOCK_LENGTH; + + if ((returnCode = SNSS_WriteBlockHeader (&header, snssFile)) != SNSS_OK) + { + return returnCode; + } + + if (write (snssFile->fp, snssFile->soundBlock.soundRegisters, SOUND_BLOCK_LENGTH) != 1) + { + return SNSS_WRITE_FAILED; + } + + snssFile->headerBlock.numberOfBlocks++; + + return SNSS_OK; +} + +/**************************************************************************/ +/* general functions for reading and writing SNSS data blocks */ +/**************************************************************************/ + +SNSS_RETURN_CODE +SNSS_ReadBlock (SNSS_FILE *snssFile, SNSS_BLOCK_TYPE blockType) +{ + switch (blockType) + { + case SNSS_BASR: + return SNSS_ReadBaseBlock (snssFile); + + case SNSS_VRAM: + return SNSS_ReadVramBlock (snssFile); + + case SNSS_SRAM: + return SNSS_ReadSramBlock (snssFile); + + case SNSS_MPRD: + return SNSS_ReadMapperBlock (snssFile); + + case SNSS_CNTR: + return SNSS_ReadControllersBlock (snssFile); + + case SNSS_SOUN: + return SNSS_ReadSoundBlock (snssFile); + + case SNSS_UNKNOWN_BLOCK: + default: + return SNSS_UNSUPPORTED_BLOCK; + } +} + +/**************************************************************************/ + +SNSS_RETURN_CODE +SNSS_WriteBlock (SNSS_FILE *snssFile, SNSS_BLOCK_TYPE blockType) +{ + switch (blockType) + { + case SNSS_BASR: + return SNSS_WriteBaseBlock (snssFile); + + case SNSS_VRAM: + return SNSS_WriteVramBlock (snssFile); + + case SNSS_SRAM: + return SNSS_WriteSramBlock (snssFile); + + case SNSS_MPRD: + return SNSS_WriteMapperBlock (snssFile); + + case SNSS_CNTR: + return SNSS_WriteControllersBlock (snssFile); + + case SNSS_SOUN: + return SNSS_WriteSoundBlock (snssFile); + + case SNSS_UNKNOWN_BLOCK: + default: + return SNSS_UNSUPPORTED_BLOCK; + } +} + +/* +** $Log: libsnss.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.1 2000/10/24 12:19:01 matt +** changed directory structure +** +** Revision 1.9 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.8 2000/08/16 02:58:34 matt +** random cleanups +** +** Revision 1.7 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.6 2000/07/10 01:54:16 matt +** state is now zeroed when it is allocated +** +** Revision 1.5 2000/07/09 15:37:21 matt +** all block read/write calls now pass through a common handler +** +** Revision 1.4 2000/07/09 03:39:06 matt +** minor modifications +** +** Revision 1.3 2000/07/08 16:01:39 matt +** added bald's changes, made error checking more robust +** +** Revision 1.2 2000/07/04 04:46:06 matt +** simplified handling of SNSS states +** +** Revision 1.1 2000/06/29 14:13:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/log.c =================================================================== --- apps/plugins/nofrendo/log.c (revision 0) +++ apps/plugins/nofrendo/log.c (revision 0) @@ -0,0 +1,176 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** log.c +** +** Error logging functions +** $Id: log.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include + + +static int *errorlog = NULL; +static int (*log_func)(const char *string) = NULL; + +/* first up: debug versions of calls */ +#ifdef NOFRENDO_DEBUG +int log_init(void) +{ + errorlog = rb->open("errorlog.txt", O_WRONLY); + if (NULL == errorlog) + return (-1); + + return 0; +} + +void log_shutdown(void) +{ + /* Snoop around for unallocated blocks */ + mem_checkblocks(); + mem_checkleaks(); + mem_cleanup(); + + if (NULL != errorlog) + rb->close(errorlog); +} + +int log_print(const char *string) +{ + /* if we have a custom logging function, use that */ + if (NULL != log_func) + log_func(string); + + /* Log it to disk, as well */ + fputs(string, errorlog); + + return 0; +} + +int log_printf(const char *format, ... ) +{ + /* don't allocate on stack every call */ + static char buffer[1024 + 1]; + va_list arg; + + va_start(arg, format); + + if (NULL != log_func) + { + vsprintf(buffer, format, arg); + log_func(buffer); + } + + vfprintf(errorlog, format, arg); + va_end(arg); + + return 0; /* should be number of chars written */ +} + +#else /* !NOFRENDO_DEBUG */ + +int log_init(void) +{ + return 0; +} + +void log_shutdown(void) +{ +} + +int log_print(const char *string) +{ + UNUSED(string); + + return 0; +} + +int log_printf(const char *format, ... ) +{ + UNUSED(format); + + return 0; /* should be number of chars written */ +} +#endif /* !NOFRENDO_DEBUG */ + +void log_chain_logfunc(int (*func)(const char *string)) +{ + log_func = func; +} + +void log_assert(int expr, int line, const char *file, char *msg) +{ + if (expr) + return; + + if (NULL != msg) + log_printf("ASSERT: line %d of %s, %s\n", line, file, msg); + else + log_printf("ASSERT: line %d of %s\n", line, file); + + return -1; +} + + +/* +** $Log: log.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.14 2000/11/13 00:56:17 matt +** doesn't look as nasty now +** +** Revision 1.13 2000/11/06 02:15:07 matt +** more robust logging routines +** +** Revision 1.12 2000/10/15 13:28:12 matt +** need stdlib.h for exit() +** +** Revision 1.11 2000/10/10 13:13:13 matt +** dumb bug in log_chain_logfunc +** +** Revision 1.10 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.9 2000/08/28 01:47:10 matt +** quelled fricking compiler complaints +** +** Revision 1.8 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.7 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.6 2000/07/06 17:20:52 matt +** block manager space itself wasn't being freed - d'oh! +** +** Revision 1.5 2000/06/26 04:55:33 matt +** minor change +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/libsnss.h =================================================================== --- apps/plugins/nofrendo/libsnss.h (revision 0) +++ apps/plugins/nofrendo/libsnss.h (revision 0) @@ -0,0 +1,397 @@ +/**************************************************************************/ +/* + libsnss.h + + (C) 2000 The SNSS Group + See README.TXT file for license and terms of use. + + $Id: libsnss.h,v 1.1 2001/04/27 12:54:40 neil Exp $ +*/ +/**************************************************************************/ + +#ifndef _LIBSNSS_H_ +#define _LIBSNSS_H_ + +#include + +/**************************************************************************/ +/* endian customization */ +/**************************************************************************/ +/* + Endian-ness quick reference: + the number is: + $12345678 + the little-endian representation (e.g.: 6502, Intel x86) is: + 78 56 34 12 + the big-endian representation (e.g.: Motorola 68000) is: + 12 34 56 78 + the SNSS file format uses big-endian representation +*/ + +/* comment/uncomment depending on your processor architecture */ +/* commenting this out implies BIG ENDIAN */ +#define USE_LITTLE_ENDIAN + +/**************************************************************************/ +/* SNSS constants */ +/**************************************************************************/ + +typedef enum _SNSS_OPEN_MODES +{ + SNSS_OPEN_READ, + SNSS_OPEN_WRITE +} SNSS_OPEN_MODE; + +/* block types */ +typedef enum _SNSS_BLOCK_TYPES +{ + SNSS_BASR, + SNSS_VRAM, + SNSS_SRAM, + SNSS_MPRD, + SNSS_CNTR, + SNSS_SOUN, + SNSS_UNKNOWN_BLOCK +} SNSS_BLOCK_TYPE; + +/* function return types */ +typedef enum _SNSS_RETURN_CODES +{ + SNSS_OK, + SNSS_BAD_FILE_TAG, + SNSS_OPEN_FAILED, + SNSS_CLOSE_FAILED, + SNSS_READ_FAILED, + SNSS_WRITE_FAILED, + SNSS_OUT_OF_MEMORY, + SNSS_UNSUPPORTED_BLOCK +} SNSS_RETURN_CODE; + + +#define TAG_LENGTH 4 +#define SNSS_BLOCK_VERSION 1 + +/**************************************************************************/ +/* SNSS data structures */ +/**************************************************************************/ + +struct mapper1Data +{ + unsigned char registers[4]; + unsigned char latch; + unsigned char numberOfBits; +}; + +struct mapper4Data +{ + unsigned char irqCounter; + unsigned char irqLatchCounter; + unsigned char irqCounterEnabled; + unsigned char last8000Write; +}; + +struct mapper5Data +{ + unsigned char dummy; /* needed for some compilers; remove if any members are added */ +}; + +struct mapper6Data +{ + unsigned char irqCounter; + unsigned char irqLatchCounter; + unsigned char irqCounterEnabled; + unsigned char last43FEWrite; + unsigned char last4500Write; +}; + +struct mapper9Data +{ + unsigned char latch[2]; + unsigned char lastB000Write; + unsigned char lastC000Write; + unsigned char lastD000Write; + unsigned char lastE000Write; +}; + +struct mapper10Data +{ + unsigned char latch[2]; + unsigned char lastB000Write; + unsigned char lastC000Write; + unsigned char lastD000Write; + unsigned char lastE000Write; +}; + +struct mapper16Data +{ + unsigned char irqCounterLowByte; + unsigned char irqCounterHighByte; + unsigned char irqCounterEnabled; +}; + +struct mapper17Data +{ + unsigned char irqCounterLowByte; + unsigned char irqCounterHighByte; + unsigned char irqCounterEnabled; +}; + +struct mapper18Data +{ + unsigned char irqCounterLowByte; + unsigned char irqCounterHighByte; + unsigned char irqCounterEnabled; +}; + +struct mapper19Data +{ + unsigned char irqCounterLowByte; + unsigned char irqCounterHighByte; + unsigned char irqCounterEnabled; +}; + +struct mapper21Data +{ + unsigned char irqCounter; + unsigned char irqCounterEnabled; +}; + +struct mapper24Data +{ + unsigned char irqCounter; + unsigned char irqCounterEnabled; +}; + +struct mapper40Data +{ + unsigned char irqCounter; + unsigned char irqCounterEnabled; +}; + +struct mapper69Data +{ + unsigned char irqCounterLowByte; + unsigned char irqCounterHighByte; + unsigned char irqCounterEnabled; +}; + +struct mapper90Data +{ + unsigned char irqCounter; + unsigned char irqLatchCounter; + unsigned char irqCounterEnabled; +}; + +struct mapper224Data +{ + unsigned char chrRamWriteable; +}; + +struct mapper225Data +{ + unsigned char prgSize; + unsigned char registers[4]; +}; + +struct mapper226Data +{ + unsigned char chrRamWriteable; +}; + +struct mapper228Data +{ + unsigned char prgChipSelected; +}; + +struct mapper230Data +{ + unsigned char numberOfResets; +}; + +typedef struct _SnssFileHeader +{ + char tag[TAG_LENGTH + 1]; + unsigned int numberOfBlocks; +} SnssFileHeader; + +/* this block appears before every block in the SNSS file */ +typedef struct _SnssBlockHeader +{ + char tag[TAG_LENGTH + 1]; + unsigned int blockVersion; + unsigned int blockLength; +} SnssBlockHeader; + +#define BASE_BLOCK_LENGTH 0x1931 +typedef struct _SnssBaseBlock +{ + unsigned char regA; + unsigned char regX; + unsigned char regY; + unsigned char regFlags; + unsigned char regStack; + unsigned short regPc; + unsigned char reg2000; + unsigned char reg2001; + unsigned char cpuRam[0x800]; + unsigned char spriteRam[0x100]; + unsigned char ppuRam[0x1000]; + unsigned char palette[0x20]; + unsigned char mirrorState[4]; + unsigned short vramAddress; + unsigned char spriteRamAddress; + unsigned char tileXOffset; +} SnssBaseBlock; + +#define VRAM_8K 0x2000 +#define VRAM_16K 0x4000 +typedef struct _SnssVramBlock +{ + unsigned short vramSize; + unsigned char vram[VRAM_16K]; +} SnssVramBlock; + +#define SRAM_1K 0x0400 +#define SRAM_2K 0x0800 +#define SRAM_3K 0x0C00 +#define SRAM_4K 0x1000 +#define SRAM_5K 0x1400 +#define SRAM_6K 0x1800 +#define SRAM_7K 0x1C00 +#define SRAM_8K 0x2000 +typedef struct _SnssSramBlock +{ + unsigned short sramSize; + unsigned char sramEnabled; + unsigned char sram[SRAM_8K]; +} SnssSramBlock; + +#define MAPPER_BLOCK_LENGTH 0x98 +typedef struct _SnssMapperBlock +{ + unsigned short prgPages[4]; + unsigned short chrPages[8]; + + union _extraData + { + unsigned char mapperData[128]; + struct mapper1Data mapper1; + struct mapper4Data mapper4; + struct mapper5Data mapper5; + struct mapper6Data mapper6; + struct mapper9Data mapper9; + struct mapper10Data mapper10; + struct mapper16Data mapper16; + struct mapper17Data mapper17; + struct mapper18Data mapper18; + struct mapper19Data mapper19; + struct mapper21Data mapper21; + struct mapper24Data mapper24; + struct mapper40Data mapper40; + struct mapper69Data mapper69; + struct mapper90Data mapper90; + struct mapper224Data mapper224; + struct mapper225Data mapper225; + struct mapper226Data mapper226; + struct mapper228Data mapper228; + struct mapper230Data mapper230; + } extraData; +} SnssMapperBlock; + +typedef struct _SnssControllersBlock +{ + unsigned char dummy; /* needed for some compilers; remove if any members are added */ +} SnssControllersBlock; + +#define SOUND_BLOCK_LENGTH 0x16 +typedef struct _SnssSoundBlock +{ + unsigned char soundRegisters[0x16]; +} SnssSoundBlock; + +/**************************************************************************/ +/* SNSS file manipulation functions */ +/**************************************************************************/ + +typedef struct _SNSS_FILE +{ + int *fp; + SNSS_OPEN_MODE mode; + SnssFileHeader headerBlock; + SnssBaseBlock baseBlock; + SnssVramBlock vramBlock; + SnssSramBlock sramBlock; + SnssMapperBlock mapperBlock; + SnssControllersBlock contBlock; + SnssSoundBlock soundBlock; +} SNSS_FILE; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* general file manipulation routines */ +SNSS_RETURN_CODE SNSS_OpenFile (SNSS_FILE **snssFile, const char *filename, + SNSS_OPEN_MODE mode); +SNSS_RETURN_CODE SNSS_CloseFile (SNSS_FILE **snssFile); + +/* block traversal */ +SNSS_RETURN_CODE SNSS_GetNextBlockType (SNSS_BLOCK_TYPE *blockType, + SNSS_FILE *snssFile); +SNSS_RETURN_CODE SNSS_SkipNextBlock (SNSS_FILE *snssFile); + +/* functions to read/write SNSS blocks */ +SNSS_RETURN_CODE SNSS_ReadBlock (SNSS_FILE *snssFile, SNSS_BLOCK_TYPE blockType); +SNSS_RETURN_CODE SNSS_WriteBlock (SNSS_FILE *snssFile, SNSS_BLOCK_TYPE blockType); + +/* support functions */ +const char *SNSS_GetErrorString (SNSS_RETURN_CODE code); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _LIBSNSS_H_ */ + +/* +** $Log: libsnss.h,v $ +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.2 2000/11/09 14:07:41 matt +** minor update +** +** Revision 1.1 2000/10/24 12:19:01 matt +** changed directory structure +** +** Revision 1.9 2000/09/18 02:06:48 matt +** -pedantic is your friend +** +** Revision 1.8 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.7 2000/07/15 23:49:14 matt +** fixed some typos in the mapper-specific data +** +** Revision 1.6 2000/07/09 15:37:21 matt +** all block read/write calls now pass through a common handler +** +** Revision 1.5 2000/07/09 03:39:06 matt +** minor modifications +** +** Revision 1.4 2000/07/08 16:01:39 matt +** added bald's changes, made error checking more robust +** +** Revision 1.3 2000/07/05 22:46:52 matt +** cleaned up header +** +** Revision 1.2 2000/07/04 04:46:06 matt +** simplified handling of SNSS states +** +** Revision 1.1 2000/06/29 14:13:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/log.h =================================================================== --- apps/plugins/nofrendo/log.h (revision 0) +++ apps/plugins/nofrendo/log.h (revision 0) @@ -0,0 +1,57 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** log.h +** +** Error logging header file +** $Id: log.h,v 1.1.1.1 2001/04/27 07:03:54 neil Exp $ +*/ + +#ifndef _LOG_H_ +#define _LOG_H_ + +#include + +extern int log_init(void); +extern void log_shutdown(void); +extern int log_print(const char *string); +extern int log_printf(const char *format, ...); +extern void log_chain_logfunc(int (*logfunc)(const char *string)); +extern void log_assert(int expr, int line, const char *file, char *msg); + +#endif /* _LOG_H_ */ + +/* +** $Log: log.h,v $ +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.7 2000/11/06 02:15:07 matt +** more robust logging routines +** +** Revision 1.6 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.5 2000/07/17 01:52:27 matt +** made sure last line of all source files is a newline +** +** Revision 1.4 2000/06/09 15:12:25 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/nes_apu.c =================================================================== --- apps/plugins/nofrendo/nes_apu.c (revision 0) +++ apps/plugins/nofrendo/nes_apu.c (revision 0) @@ -0,0 +1,1195 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** nes_apu.c +** +** NES APU emulation +** $Id: nes_apu.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include +#include "nes6502.h" + + +#define APU_OVERSAMPLE +#define APU_VOLUME_DECAY(x) ((x) -= ((x) >> 7)) + +/* the following seem to be the correct (empirically determined) +** relative volumes between the sound channels +*/ +#define APU_RECTANGLE_OUTPUT(channel) (apu.rectangle[channel].output_vol) +#define APU_TRIANGLE_OUTPUT (apu.triangle.output_vol + (apu.triangle.output_vol >> 2)) +#define APU_NOISE_OUTPUT ((apu.noise.output_vol + apu.noise.output_vol + apu.noise.output_vol) >> 2) +#define APU_DMC_OUTPUT ((apu.dmc.output_vol + apu.dmc.output_vol + apu.dmc.output_vol) >> 2) + +/* active APU */ +static apu_t apu; + +/* look up table madness */ +static int32 decay_lut[16]; +static int vbl_lut[32]; +static int trilength_lut[128]; + +/* noise lookups for both modes */ +#ifndef REALTIME_NOISE +static int8 noise_long_lut[APU_NOISE_32K]; +static int8 noise_short_lut[APU_NOISE_93]; +#endif /* !REALTIME_NOISE */ + + +/* vblank length table used for rectangles, triangle, noise */ +static const uint8 vbl_length[32] = +{ + 5, 127, + 10, 1, + 19, 2, + 40, 3, + 80, 4, + 30, 5, + 7, 6, + 13, 7, + 6, 8, + 12, 9, + 24, 10, + 48, 11, + 96, 12, + 36, 13, + 8, 14, + 16, 15 +}; + +/* frequency limit of rectangle channels */ +static const int freq_limit[8] = +{ + 0x3FF, 0x555, 0x666, 0x71C, 0x787, 0x7C1, 0x7E0, 0x7F0 +}; + +/* noise frequency lookup table */ +static const int noise_freq[16] = +{ + 4, 8, 16, 32, 64, 96, 128, 160, + 202, 254, 380, 508, 762, 1016, 2034, 4068 +}; + +/* DMC transfer freqs */ +const int dmc_clocks[16] = +{ + 428, 380, 340, 320, 286, 254, 226, 214, + 190, 160, 142, 128, 106, 85, 72, 54 +}; + +/* ratios of pos/neg pulse for rectangle waves */ +static const int duty_flip[4] = { 2, 4, 8, 12 }; + + +void apu_setcontext(apu_t *src_apu) +{ + apu = *src_apu; +} + +void apu_getcontext(apu_t *dest_apu) +{ + *dest_apu = apu; +} + +void apu_setchan(int chan, int enabled) +{ + if (enabled) + apu.mix_enable |= (1 << chan); + else + apu.mix_enable &= ~(1 << chan); +} + +/* emulation of the 15-bit shift register the +** NES uses to generate pseudo-random series +** for the white noise channel +*/ +#ifdef REALTIME_NOISE +INLINE int8 shift_register15(uint8 xor_tap) +{ + static int sreg = 0x4000; + int bit0, tap, bit14; + + bit0 = sreg & 1; + tap = (sreg & xor_tap) ? 1 : 0; + bit14 = (bit0 ^ tap); + sreg >>= 1; + sreg |= (bit14 << 14); + return (bit0 ^ 1); +} +#else /* !REALTIME_NOISE */ +static void shift_register15(int8 *buf, int count) +{ + static int sreg = 0x4000; + int bit0, bit1, bit6, bit14; + + if (count == APU_NOISE_93) + { + while (count--) + { + bit0 = sreg & 1; + bit6 = (sreg & 0x40) >> 6; + bit14 = (bit0 ^ bit6); + sreg >>= 1; + sreg |= (bit14 << 14); + *buf++ = bit0 ^ 1; + } + } + else /* 32K noise */ + { + while (count--) + { + bit0 = sreg & 1; + bit1 = (sreg & 2) >> 1; + bit14 = (bit0 ^ bit1); + sreg >>= 1; + sreg |= (bit14 << 14); + *buf++ = bit0 ^ 1; + } + } +} +#endif /* !REALTIME_NOISE */ + +/* RECTANGLE WAVE +** ============== +** reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle +** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on +** reg2: 8 bits of freq +** reg3: 0-2=high freq, 7-4=vbl length counter +*/ +#ifdef APU_OVERSAMPLE + +#define APU_MAKE_RECTANGLE(ch) \ +static int32 apu_rectangle_##ch(void) \ +{ \ + int32 output, total; \ + int num_times; \ +\ + APU_VOLUME_DECAY(apu.rectangle[ch].output_vol); \ +\ + if (0 == apu.rectangle[ch].enabled || 0 == apu.rectangle[ch].vbl_length) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + /* vbl length counter */ \ + if (0 == apu.rectangle[ch].holdnote) \ + apu.rectangle[ch].vbl_length--; \ +\ + /* envelope decay at a rate of (env_delay + 1) / 240 secs */ \ + apu.rectangle[ch].env_phase -= 4; /* 240/60 */ \ + while (apu.rectangle[ch].env_phase < 0) \ + { \ + apu.rectangle[ch].env_phase += apu.rectangle[ch].env_delay; \ +\ + if (apu.rectangle[ch].holdnote) \ + apu.rectangle[ch].env_vol = (apu.rectangle[ch].env_vol + 1) & 0x0F; \ + else if (apu.rectangle[ch].env_vol < 0x0F) \ + apu.rectangle[ch].env_vol++; \ + } \ +\ + /* TODO: find true relation of freq_limit to register values */ \ + if (apu.rectangle[ch].freq < 8 \ + || (0 == apu.rectangle[ch].sweep_inc \ + && apu.rectangle[ch].freq > apu.rectangle[ch].freq_limit)) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + /* frequency sweeping at a rate of (sweep_delay + 1) / 120 secs */ \ + if (apu.rectangle[ch].sweep_on && apu.rectangle[ch].sweep_shifts) \ + { \ + apu.rectangle[ch].sweep_phase -= 2; /* 120/60 */ \ + while (apu.rectangle[ch].sweep_phase < 0) \ + { \ + apu.rectangle[ch].sweep_phase += apu.rectangle[ch].sweep_delay; \ +\ + if (apu.rectangle[ch].sweep_inc) /* ramp up */ \ + { \ + if (0 == ch) \ + apu.rectangle[ch].freq += ~(apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + else \ + apu.rectangle[ch].freq -= (apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + } \ + else /* ramp down */ \ + { \ + apu.rectangle[ch].freq += (apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + } \ + } \ + } \ +\ + apu.rectangle[ch].accum -= apu.cycle_rate; \ + if (apu.rectangle[ch].accum >= 0) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + if (apu.rectangle[ch].fixed_envelope) \ + output = apu.rectangle[ch].volume << 8; /* fixed volume */ \ + else \ + output = (apu.rectangle[ch].env_vol ^ 0x0F) << 8; \ +\ + num_times = total = 0; \ +\ + while (apu.rectangle[ch].accum < 0) \ + { \ + apu.rectangle[ch].accum += apu.rectangle[ch].freq + 1; \ + apu.rectangle[ch].adder = (apu.rectangle[ch].adder + 1) & 0x0F; \ +\ + if (apu.rectangle[ch].adder < apu.rectangle[ch].duty_flip) \ + total += output; \ + else \ + total -= output; \ +\ + num_times++; \ + } \ +\ + apu.rectangle[ch].output_vol = total / num_times; \ + return APU_RECTANGLE_OUTPUT(ch); \ +} + +#else /* !APU_OVERSAMPLE */ +#define APU_MAKE_RECTANGLE(ch) \ +static int32 apu_rectangle_##ch(void) \ +{ \ + int32 output; \ +\ + APU_VOLUME_DECAY(apu.rectangle[ch].output_vol); \ +\ + if (0 == apu.rectangle[ch].enabled || 0 == apu.rectangle[ch].vbl_length) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + /* vbl length counter */ \ + if (0 == apu.rectangle[ch].holdnote) \ + apu.rectangle[ch].vbl_length--; \ +\ + /* envelope decay at a rate of (env_delay + 1) / 240 secs */ \ + apu.rectangle[ch].env_phase -= 4; /* 240/60 */ \ + while (apu.rectangle[ch].env_phase < 0) \ + { \ + apu.rectangle[ch].env_phase += apu.rectangle[ch].env_delay; \ +\ + if (apu.rectangle[ch].holdnote) \ + apu.rectangle[ch].env_vol = (apu.rectangle[ch].env_vol + 1) & 0x0F; \ + else if (apu.rectangle[ch].env_vol < 0x0F) \ + apu.rectangle[ch].env_vol++; \ + } \ +\ + /* TODO: find true relation of freq_limit to register values */ \ + if (apu.rectangle[ch].freq < 8 || (0 == apu.rectangle[ch].sweep_inc && apu.rectangle[ch].freq > apu.rectangle[ch].freq_limit)) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + /* frequency sweeping at a rate of (sweep_delay + 1) / 120 secs */ \ + if (apu.rectangle[ch].sweep_on && apu.rectangle[ch].sweep_shifts) \ + { \ + apu.rectangle[ch].sweep_phase -= 2; /* 120/60 */ \ + while (apu.rectangle[ch].sweep_phase < 0) \ + { \ + apu.rectangle[ch].sweep_phase += apu.rectangle[ch].sweep_delay; \ +\ + if (apu.rectangle[ch].sweep_inc) /* ramp up */ \ + { \ + if (0 == ch) \ + apu.rectangle[ch].freq += ~(apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + else \ + apu.rectangle[ch].freq -= (apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + } \ + else /* ramp down */ \ + { \ + apu.rectangle[ch].freq += (apu.rectangle[ch].freq >> apu.rectangle[ch].sweep_shifts); \ + } \ + } \ + } \ +\ + apu.rectangle[ch].accum -= apu.cycle_rate; \ + if (apu.rectangle[ch].accum >= 0) \ + return APU_RECTANGLE_OUTPUT(ch); \ +\ + while (apu.rectangle[ch].accum < 0) \ + { \ + apu.rectangle[ch].accum += (apu.rectangle[ch].freq + 1); \ + apu.rectangle[ch].adder = (apu.rectangle[ch].adder + 1) & 0x0F; \ + } \ +\ + if (apu.rectangle[ch].fixed_envelope) \ + output = apu.rectangle[ch].volume << 8; /* fixed volume */ \ + else \ + output = (apu.rectangle[ch].env_vol ^ 0x0F) << 8; \ +\ + if (0 == apu.rectangle[ch].adder) \ + apu.rectangle[ch].output_vol = output; \ + else if (apu.rectangle[ch].adder == apu.rectangle[ch].duty_flip) \ + apu.rectangle[ch].output_vol = -output; \ +\ + return APU_RECTANGLE_OUTPUT(ch); \ +} + +#endif /* !APU_OVERSAMPLE */ + +/* generate the functions */ +APU_MAKE_RECTANGLE(0) +APU_MAKE_RECTANGLE(1) + + +/* TRIANGLE WAVE +** ============= +** reg0: 7=holdnote, 6-0=linear length counter +** reg2: low 8 bits of frequency +** reg3: 7-3=length counter, 2-0=high 3 bits of frequency +*/ +static int32 apu_triangle(void) +{ + APU_VOLUME_DECAY(apu.triangle.output_vol); + + if (0 == apu.triangle.enabled || 0 == apu.triangle.vbl_length) + return APU_TRIANGLE_OUTPUT; + + if (apu.triangle.counter_started) + { + if (apu.triangle.linear_length > 0) + apu.triangle.linear_length--; + if (apu.triangle.vbl_length && 0 == apu.triangle.holdnote) + apu.triangle.vbl_length--; + } + else if (0 == apu.triangle.holdnote && apu.triangle.write_latency) + { + if (--apu.triangle.write_latency == 0) + apu.triangle.counter_started = 1; + } + + if (0 == apu.triangle.linear_length || apu.triangle.freq < 4) /* inaudible */ + return APU_TRIANGLE_OUTPUT; + + apu.triangle.accum -= apu.cycle_rate; \ + while (apu.triangle.accum < 0) + { + apu.triangle.accum += apu.triangle.freq; + apu.triangle.adder = (apu.triangle.adder + 1) & 0x1F; + + if (apu.triangle.adder & 0x10) + apu.triangle.output_vol -= (2 << 8); + else + apu.triangle.output_vol += (2 << 8); + } + + return APU_TRIANGLE_OUTPUT; +} + + +/* WHITE NOISE CHANNEL +** =================== +** reg0: 0-3=volume, 4=envelope, 5=hold +** reg2: 7=small(93 byte) sample,3-0=freq lookup +** reg3: 7-4=vbl length counter +*/ +/* TODO: AAAAAAAAAAAAAAAAAAAAAAAA! #ifdef MADNESS! */ +static int32 apu_noise(void) +{ + int32 outvol; + +#if defined(APU_OVERSAMPLE) && defined(REALTIME_NOISE) +#else /* !(APU_OVERSAMPLE && REALTIME_NOISE) */ + int32 noise_bit; +#endif /* !(APU_OVERSAMPLE && REALTIME_NOISE) */ +#ifdef APU_OVERSAMPLE + int num_times; + int32 total; +#endif /* APU_OVERSAMPLE */ + + APU_VOLUME_DECAY(apu.noise.output_vol); + + if (0 == apu.noise.enabled || 0 == apu.noise.vbl_length) + return APU_NOISE_OUTPUT; + + /* vbl length counter */ + if (0 == apu.noise.holdnote) + apu.noise.vbl_length--; + + /* envelope decay at a rate of (env_delay + 1) / 240 secs */ + apu.noise.env_phase -= 4; /* 240/60 */ + while (apu.noise.env_phase < 0) + { + apu.noise.env_phase += apu.noise.env_delay; + + if (apu.noise.holdnote) + apu.noise.env_vol = (apu.noise.env_vol + 1) & 0x0F; + else if (apu.noise.env_vol < 0x0F) + apu.noise.env_vol++; + } + + apu.noise.accum -= apu.cycle_rate; + if (apu.noise.accum >= 0) + return APU_NOISE_OUTPUT; + +#ifdef APU_OVERSAMPLE + if (apu.noise.fixed_envelope) + outvol = apu.noise.volume << 8; /* fixed volume */ + else + outvol = (apu.noise.env_vol ^ 0x0F) << 8; + + num_times = total = 0; +#endif /* APU_OVERSAMPLE */ + + while (apu.noise.accum < 0) + { + apu.noise.accum += apu.noise.freq; + +#ifdef REALTIME_NOISE + +#ifdef APU_OVERSAMPLE + if (shift_register15(apu.noise.xor_tap)) + total += outvol; + else + total -= outvol; + + num_times++; +#else /* !APU_OVERSAMPLE */ + noise_bit = shift_register15(apu.noise.xor_tap); +#endif /* !APU_OVERSAMPLE */ + +#else /* !REALTIME_NOISE */ + apu.noise.cur_pos++; + + if (apu.noise.short_sample) + { + if (APU_NOISE_93 == apu.noise.cur_pos) + apu.noise.cur_pos = 0; + } + else + { + if (APU_NOISE_32K == apu.noise.cur_pos) + apu.noise.cur_pos = 0; + } + +#ifdef APU_OVERSAMPLE + if (apu.noise.short_sample) + noise_bit = noise_short_lut[apu.noise.cur_pos]; + else + noise_bit = noise_long_lut[apu.noise.cur_pos]; + + if (noise_bit) + total += outvol; + else + total -= outvol; + + num_times++; +#endif /* APU_OVERSAMPLE */ +#endif /* !REALTIME_NOISE */ + } + +#ifdef APU_OVERSAMPLE + apu.noise.output_vol = total / num_times; +#else /* !APU_OVERSAMPLE */ + if (apu.noise.fixed_envelope) + outvol = apu.noise.volume << 8; /* fixed volume */ + else + outvol = (apu.noise.env_vol ^ 0x0F) << 8; + +#ifndef REALTIME_NOISE + if (apu.noise.short_sample) + noise_bit = noise_short_lut[apu.noise.cur_pos]; + else + noise_bit = noise_long_lut[apu.noise.cur_pos]; +#endif /* !REALTIME_NOISE */ + + if (noise_bit) + apu.noise.output_vol = outvol; + else + apu.noise.output_vol = -outvol; +#endif /* !APU_OVERSAMPLE */ + + return APU_NOISE_OUTPUT; +} + + +INLINE void apu_dmcreload(void) +{ + apu.dmc.address = apu.dmc.cached_addr; + apu.dmc.dma_length = apu.dmc.cached_dmalength; + apu.dmc.irq_occurred = 0; +} + +/* DELTA MODULATION CHANNEL +** ========================= +** reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table +** reg1: output dc level, 6 bits unsigned +** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64) +** reg3: length, (value * 16) + 1 +*/ +static int32 apu_dmc(void) +{ + int delta_bit; + + APU_VOLUME_DECAY(apu.dmc.output_vol); + + /* only process when channel is alive */ + if (apu.dmc.dma_length) + { + apu.dmc.accum -= apu.cycle_rate; + + while (apu.dmc.accum < 0) + { + apu.dmc.accum += apu.dmc.freq; + + delta_bit = (apu.dmc.dma_length & 7) ^ 7; + + if (7 == delta_bit) + { + apu.dmc.cur_byte = nes6502_getbyte(apu.dmc.address); + + /* steal a cycle from CPU*/ + nes6502_burn(1); + + /* prevent wraparound */ + if (0xFFFF == apu.dmc.address) + apu.dmc.address = 0x8000; + else + apu.dmc.address++; + } + + if (--apu.dmc.dma_length == 0) + { + /* if loop bit set, we're cool to retrigger sample */ + if (apu.dmc.looping) + { + apu_dmcreload(); + } + else + { + /* check to see if we should generate an irq */ + if (apu.dmc.irq_gen) + { + apu.dmc.irq_occurred = 1; + if (apu.irq_callback) + apu.irq_callback(); + } + + /* bodge for timestamp queue */ + apu.dmc.enabled = 0; + break; + } + } + + /* positive delta */ + if (apu.dmc.cur_byte & (1 << delta_bit)) + { + if (apu.dmc.regs[1] < 0x7D) + { + apu.dmc.regs[1] += 2; + apu.dmc.output_vol += (2 << 8); + } + } + /* negative delta */ + else + { + if (apu.dmc.regs[1] > 1) + { + apu.dmc.regs[1] -= 2; + apu.dmc.output_vol -= (2 << 8); + } + } + } + } + + return APU_DMC_OUTPUT; +} + + +void apu_write(uint32 address, uint8 value) +{ + int chan; + + switch (address) + { + /* rectangles */ + case APU_WRA0: + case APU_WRB0: + chan = (address & 4) >> 2; + apu.rectangle[chan].regs[0] = value; + apu.rectangle[chan].volume = value & 0x0F; + apu.rectangle[chan].env_delay = decay_lut[value & 0x0F]; + apu.rectangle[chan].holdnote = (value & 0x20) ? 1 : 0; + apu.rectangle[chan].fixed_envelope = (value & 0x10) ? 1 : 0; + apu.rectangle[chan].duty_flip = duty_flip[value >> 6]; + break; + + case APU_WRA1: + case APU_WRB1: + chan = (address & 4) >> 2; + apu.rectangle[chan].regs[1] = value; + apu.rectangle[chan].sweep_on = (value & 0x80) ? 1 : 0; + apu.rectangle[chan].sweep_shifts = value & 7; + apu.rectangle[chan].sweep_delay = decay_lut[(value >> 4) & 7]; + apu.rectangle[chan].sweep_inc = (value & 0x08) ? 1 : 0; + apu.rectangle[chan].freq_limit = freq_limit[value & 7]; + break; + + case APU_WRA2: + case APU_WRB2: + chan = (address & 4) >> 2; + apu.rectangle[chan].regs[2] = value; + apu.rectangle[chan].freq = (apu.rectangle[chan].freq & ~0xFF) | value; + break; + + case APU_WRA3: + case APU_WRB3: + chan = (address & 4) >> 2; + apu.rectangle[chan].regs[3] = value; + apu.rectangle[chan].vbl_length = vbl_lut[value >> 3]; + apu.rectangle[chan].env_vol = 0; + apu.rectangle[chan].freq = ((value & 7) << 8) | (apu.rectangle[chan].freq & 0xFF); + apu.rectangle[chan].adder = 0; + break; + + /* triangle */ + case APU_WRC0: + apu.triangle.regs[0] = value; + apu.triangle.holdnote = (value & 0x80) ? 1 : 0; + + if (0 == apu.triangle.counter_started && apu.triangle.vbl_length) + apu.triangle.linear_length = trilength_lut[value & 0x7F]; + + break; + + case APU_WRC2: + apu.triangle.regs[1] = value; + apu.triangle.freq = (((apu.triangle.regs[2] & 7) << 8) + value) + 1; + break; + + case APU_WRC3: + + apu.triangle.regs[2] = value; + + /* this is somewhat of a hack. there appears to be some latency on + ** the Real Thing between when trireg0 is written to and when the + ** linear length counter actually begins its countdown. we want to + ** prevent the case where the program writes to the freq regs first, + ** then to reg 0, and the counter accidentally starts running because + ** of the sound queue's timestamp processing. + ** + ** set latency to a couple hundred cycles -- should be plenty of time + ** for the 6502 code to do a couple of table dereferences and load up + ** the other triregs + */ + apu.triangle.write_latency = (int) (228 / apu.cycle_rate); + apu.triangle.freq = (((value & 7) << 8) + apu.triangle.regs[1]) + 1; + apu.triangle.vbl_length = vbl_lut[value >> 3]; + apu.triangle.counter_started = 0; + apu.triangle.linear_length = trilength_lut[apu.triangle.regs[0] & 0x7F]; + break; + + /* noise */ + case APU_WRD0: + apu.noise.regs[0] = value; + apu.noise.env_delay = decay_lut[value & 0x0F]; + apu.noise.holdnote = (value & 0x20) ? 1 : 0; + apu.noise.fixed_envelope = (value & 0x10) ? 1 : 0; + apu.noise.volume = value & 0x0F; + break; + + case APU_WRD2: + apu.noise.regs[1] = value; + apu.noise.freq = noise_freq[value & 0x0F]; + +#ifdef REALTIME_NOISE + apu.noise.xor_tap = (value & 0x80) ? 0x40: 0x02; +#else /* !REALTIME_NOISE */ + /* detect transition from long->short sample */ + if ((value & 0x80) && 0 == apu.noise.short_sample) + { + /* recalculate short noise buffer */ + shift_register15(noise_short_lut, APU_NOISE_93); + apu.noise.cur_pos = 0; + } + apu.noise.short_sample = (value & 0x80) ? 1 : 0; +#endif /* !REALTIME_NOISE */ + break; + + case APU_WRD3: + apu.noise.regs[2] = value; + apu.noise.vbl_length = vbl_lut[value >> 3]; + apu.noise.env_vol = 0; /* reset envelope */ + break; + + /* DMC */ + case APU_WRE0: + apu.dmc.regs[0] = value; + apu.dmc.freq = dmc_clocks[value & 0x0F]; + apu.dmc.looping = (value & 0x40) ? 1 : 0; + + if (value & 0x80) + { + apu.dmc.irq_gen = 1; + } + else + { + apu.dmc.irq_gen = 0; + apu.dmc.irq_occurred = 0; + } + break; + + case APU_WRE1: /* 7-bit DAC */ + /* add the _delta_ between written value and + ** current output level of the volume reg + */ + value &= 0x7F; /* bit 7 ignored */ + apu.dmc.output_vol += ((value - apu.dmc.regs[1]) << 8); + apu.dmc.regs[1] = value; + break; + + case APU_WRE2: + apu.dmc.regs[2] = value; + apu.dmc.cached_addr = 0xC000 + (uint16) (value << 6); + break; + + case APU_WRE3: + apu.dmc.regs[3] = value; + apu.dmc.cached_dmalength = ((value << 4) + 1) << 3; + break; + + case APU_SMASK: + /* bodge for timestamp queue */ + apu.dmc.enabled = (value & 0x10) ? 1 : 0; + apu.enable_reg = value; + + for (chan = 0; chan < 2; chan++) + { + if (value & (1 << chan)) + { + apu.rectangle[chan].enabled = 1; + } + else + { + apu.rectangle[chan].enabled = 0; + apu.rectangle[chan].vbl_length = 0; + } + } + + if (value & 0x04) + { + apu.triangle.enabled = 1; + } + else + { + apu.triangle.enabled = 0; + apu.triangle.vbl_length = 0; + apu.triangle.linear_length = 0; + apu.triangle.counter_started = 0; + apu.triangle.write_latency = 0; + } + + if (value & 0x08) + { + apu.noise.enabled = 1; + } + else + { + apu.noise.enabled = 0; + apu.noise.vbl_length = 0; + } + + if (value & 0x10) + { + if (0 == apu.dmc.dma_length) + apu_dmcreload(); + } + else + { + apu.dmc.dma_length = 0; + } + + apu.dmc.irq_occurred = 0; + break; + + /* unused, but they get hit in some mem-clear loops */ + case 0x4009: + case 0x400D: + break; + + default: + break; + } +} + +/* Read from $4000-$4017 */ +uint8 apu_read(uint32 address) +{ + uint8 value; + + switch (address) + { + case APU_SMASK: + value = 0; + /* Return 1 in 0-5 bit pos if a channel is playing */ + if (apu.rectangle[0].enabled && apu.rectangle[0].vbl_length) + value |= 0x01; + if (apu.rectangle[1].enabled && apu.rectangle[1].vbl_length) + value |= 0x02; + if (apu.triangle.enabled && apu.triangle.vbl_length) + value |= 0x04; + if (apu.noise.enabled && apu.noise.vbl_length) + value |= 0x08; + + /* bodge for timestamp queue */ + if (apu.dmc.enabled) + value |= 0x10; + + if (apu.dmc.irq_occurred) + value |= 0x80; + + if (apu.irqclear_callback) + value |= apu.irqclear_callback(); + + break; + + default: + value = (address >> 8); /* heavy capacitance on data bus */ + break; + } + + return value; +} + +#define CLIP_OUTPUT16(out) \ +{ \ + /*out <<= 1;*/ \ + if (out > 0x7FFF) \ + out = 0x7FFF; \ + else if (out < -0x8000) \ + out = -0x8000; \ +} + +void apu_process(void *buffer, int num_samples) +{ + static int32 prev_sample = 0; + + int16 *buf16; + uint8 *buf8; + + if (NULL != buffer) + { + /* bleh */ + apu.buffer = buffer; + + buf16 = (int16 *) buffer; + buf8 = (uint8 *) buffer; + + while (num_samples--) + { + int32 next_sample, accum = 0; + + if (apu.mix_enable & 0x01) + accum += apu_rectangle_0(); + if (apu.mix_enable & 0x02) + accum += apu_rectangle_1(); + if (apu.mix_enable & 0x04) + accum += apu_triangle(); + if (apu.mix_enable & 0x08) + accum += apu_noise(); + if (apu.mix_enable & 0x10) + accum += apu_dmc(); + if (apu.ext && (apu.mix_enable & 0x20)) + accum += apu.ext->process(); + + /* do any filtering */ + if (APU_FILTER_NONE != apu.filter_type) + { + next_sample = accum; + + if (APU_FILTER_LOWPASS == apu.filter_type) + { + accum += prev_sample; + accum >>= 1; + } + else + accum = (accum + accum + accum + prev_sample) >> 2; + + prev_sample = next_sample; + } + + /* do clipping */ + CLIP_OUTPUT16(accum); + + /* signed 16-bit output, unsigned 8-bit */ + if (16 == apu.sample_bits) + *buf16++ = (int16) accum; + else + *buf8++ = (accum >> 8) ^ 0x80; + } + } +} + +/* set the filter type */ +void apu_setfilter(int filter_type) +{ + apu.filter_type = filter_type; +} + +void apu_reset(void) +{ + uint32 address; + + /* initialize all channel members */ + for (address = 0x4000; address <= 0x4013; address++) + apu_write(address, 0); + + apu_write(0x4015, 0); + + if (apu.ext && NULL != apu.ext->reset) + apu.ext->reset(); +} + +void apu_build_luts(int num_samples) +{ + int i; + + /* lut used for enveloping and frequency sweeps */ + for (i = 0; i < 16; i++) + decay_lut[i] = num_samples * (i + 1); + + /* used for note length, based on vblanks and size of audio buffer */ + for (i = 0; i < 32; i++) + vbl_lut[i] = vbl_length[i] * num_samples; + + /* triangle wave channel's linear length table */ + for (i = 0; i < 128; i++) + trilength_lut[i] = (int) (0.25 * i * num_samples); + +#ifndef REALTIME_NOISE + /* generate noise samples */ + shift_register15(noise_long_lut, APU_NOISE_32K); + shift_register15(noise_short_lut, APU_NOISE_93); +#endif /* !REALTIME_NOISE */ +} + +void apu_setparams(double base_freq, int sample_rate, int refresh_rate, int sample_bits) +{ + apu.sample_rate = sample_rate; + apu.refresh_rate = refresh_rate; + apu.sample_bits = sample_bits; + apu.num_samples = sample_rate / refresh_rate; + if (0 == base_freq) + apu.base_freq = APU_BASEFREQ; + else + apu.base_freq = base_freq; + apu.cycle_rate = (float) (apu.base_freq / sample_rate); + + /* build various lookup tables for apu */ + apu_build_luts(apu.num_samples); + + apu_reset(); +} + +/* Initializes emulated sound hardware, creates waveforms/voices */ +apu_t *apu_create(double base_freq, int sample_rate, int refresh_rate, int sample_bits) +{ + apu_t *temp_apu; + int channel; + + temp_apu = malloc(sizeof(apu_t)); + if (NULL == temp_apu) + return NULL; + + memset(temp_apu, 0, sizeof(apu_t)); + + /* set the update routine */ + temp_apu->process = apu_process; + temp_apu->ext = NULL; + + /* clear the callbacks */ + temp_apu->irq_callback = NULL; + temp_apu->irqclear_callback = NULL; + + apu_setcontext(temp_apu); + + apu_setparams(base_freq, sample_rate, refresh_rate, sample_bits); + + for (channel = 0; channel < 6; channel++) + apu_setchan(channel, 1); + + apu_setfilter(APU_FILTER_WEIGHTED); + + apu_getcontext(temp_apu); + + return temp_apu; +} + +void apu_destroy(apu_t **src_apu) +{ + if (*src_apu) + { + if ((*src_apu)->ext && NULL != (*src_apu)->ext->shutdown) + (*src_apu)->ext->shutdown(); + free(*src_apu); + *src_apu = NULL; + } +} + +void apu_setext(apu_t *src_apu, apuext_t *ext) +{ + ASSERT(src_apu); + + src_apu->ext = ext; + + /* initialize it */ + if (src_apu->ext && NULL != src_apu->ext->init) + src_apu->ext->init(); +} + +/* +** $Log: nes_apu.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.6 2000/12/08 02:36:14 matt +** bye bye apu queue (for now) +** +** Revision 1.5 2000/11/27 19:33:53 matt +** no special treatment for nsf +** +** Revision 1.4 2000/11/25 20:29:17 matt +** weighted filter is now default +** +** Revision 1.3 2000/11/21 13:28:19 matt +** take care to zero allocated mem +** +** Revision 1.2 2000/10/28 15:20:59 matt +** irq callbacks in nes_apu +** +** Revision 1.1 2000/10/24 12:19:59 matt +** changed directory structure +** +** Revision 1.44 2000/10/23 17:53:06 matt +** set ptr to NULL after freeing +** +** Revision 1.43 2000/10/17 11:56:42 matt +** selectable apu base frequency +** +** Revision 1.42 2000/10/13 12:16:01 matt +** macro-ized the stuff that should be removed +** +** Revision 1.41 2000/10/10 13:58:18 matt +** stroustrup squeezing his way in the door +** +** Revision 1.40 2000/10/03 11:56:20 matt +** better support for optional sound ext routines +** +** Revision 1.39 2000/09/27 12:26:03 matt +** changed sound accumulators back to floats +** +** Revision 1.38 2000/09/18 02:12:55 matt +** more optimizations +** +** Revision 1.37 2000/09/15 13:38:40 matt +** changes for optimized apu core +** +** Revision 1.36 2000/09/15 04:58:07 matt +** simplifying and optimizing APU core +** +** Revision 1.35 2000/09/07 21:57:14 matt +** api change +** +** Revision 1.34 2000/08/16 05:01:01 matt +** small buglet fixed +** +** Revision 1.33 2000/08/15 12:38:04 matt +** removed debug output +** +** Revision 1.32 2000/08/15 12:36:51 matt +** calling apu_process with buffer=NULL causes silent emulation of APU +** +** Revision 1.31 2000/08/11 02:27:21 matt +** general cleanups, plus apu_setparams routine +** +** Revision 1.30 2000/07/31 04:32:52 matt +** fragsize problem fixed, perhaps +** +** Revision 1.29 2000/07/30 04:32:59 matt +** no more apu_getcyclerate hack +** +** Revision 1.28 2000/07/28 03:15:46 matt +** accuracy changes for rectangle frequency sweeps +** +** Revision 1.27 2000/07/27 02:49:50 matt +** eccentricity in sweeping hardware now emulated correctly +** +** Revision 1.26 2000/07/25 02:25:14 matt +** safer apu_destroy +** +** Revision 1.25 2000/07/23 15:10:54 matt +** hacks for win32 +** +** Revision 1.24 2000/07/17 01:52:31 matt +** made sure last line of all source files is a newline +** +** Revision 1.23 2000/07/10 19:24:55 matt +** irqs are not supported in NSF playing mode +** +** Revision 1.22 2000/07/10 13:54:32 matt +** using generic nes_irq() now +** +** Revision 1.21 2000/07/10 05:29:34 matt +** moved joypad/oam dma from apu to ppu +** +** Revision 1.20 2000/07/09 03:49:31 matt +** apu irqs now draw an irq line (bleh) +** +** Revision 1.19 2000/07/04 04:53:26 matt +** minor changes, sound amplification +** +** Revision 1.18 2000/07/03 02:18:53 matt +** much better external module exporting +** +** Revision 1.17 2000/06/26 11:01:55 matt +** made triangle a tad quieter +** +** Revision 1.16 2000/06/26 05:10:33 matt +** fixed cycle rate generation accuracy +** +** Revision 1.15 2000/06/26 05:00:37 matt +** cleanups +** +** Revision 1.14 2000/06/23 11:06:24 matt +** more faithful mixing of channels +** +** Revision 1.13 2000/06/23 03:29:27 matt +** cleaned up external sound inteface +** +** Revision 1.12 2000/06/20 00:08:39 matt +** bugfix to rectangle wave +** +** Revision 1.11 2000/06/13 13:48:58 matt +** fixed triangle write latency for fixed point apu cycle rate +** +** Revision 1.10 2000/06/12 01:14:36 matt +** minor change to clipping extents +** +** Revision 1.9 2000/06/09 20:00:56 matt +** fixed noise hiccup in NSF player mode +** +** Revision 1.8 2000/06/09 16:49:02 matt +** removed all floating point from sound generation +** +** Revision 1.7 2000/06/09 15:12:28 matt +** initial revision +** +*/ Index: apps/plugins/nofrendo/intro.c =================================================================== --- apps/plugins/nofrendo/intro.c (revision 0) +++ apps/plugins/nofrendo/intro.c (revision 0) @@ -0,0 +1,411 @@ +/* +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** intro.c +** +** Nofrendo intro -- 6502 code +** $Id: intro.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +*/ + +#include +#include +#include +#include + +#define CODE_SIZE 0x4000 +#define VROM_SIZE 0x2000 + +/* 6502 code for the intro */ +static uint8 intro_code[301] = +{ + 0x78, 0xD8, 0xA2, 0x00, 0x8E, 0x00, 0x20, 0x8E, 0x01, 0x20, 0xAD, 0x02, 0x20, 0xAD, 0x02, 0x20, + 0x10, 0xFB, 0xAD, 0x02, 0x20, 0x10, 0xFB, 0x8E, 0x03, 0x20, 0xCA, 0x9A, 0xA9, 0x3F, 0x8D, 0x06, + 0x20, 0xA9, 0x00, 0x8D, 0x06, 0x20, 0xA2, 0x20, 0xA9, 0x0F, 0x8D, 0x07, 0x20, 0xCA, 0xD0, 0xFA, + 0xA9, 0x20, 0x8D, 0x06, 0x20, 0xA9, 0x00, 0x8D, 0x06, 0x20, 0xAA, 0xA0, 0x10, 0x8D, 0x07, 0x20, + 0xE8, 0xD0, 0xFA, 0x88, 0xD0, 0xF7, 0xA9, 0xF8, 0xA2, 0x00, 0x9D, 0x00, 0x02, 0xE8, 0xD0, 0xFA, + 0xA9, 0x02, 0x8D, 0x14, 0x40, 0xA9, 0x21, 0x8D, 0x06, 0x20, 0xA9, 0x89, 0x8D, 0x06, 0x20, 0xA0, + 0x10, 0xA2, 0xF0, 0x8C, 0x07, 0x20, 0xC8, 0xCA, 0xD0, 0xF9, 0xA9, 0x00, 0x8D, 0x05, 0x20, 0x8D, + 0x05, 0x20, 0xA9, 0x1E, 0x8D, 0x01, 0x20, 0xA9, 0x80, 0x8D, 0x00, 0x20, 0x20, 0x8B, 0x80, 0x20, + 0xFE, 0x80, 0x20, 0xF3, 0x80, 0x20, 0xC0, 0x80, 0x4C, 0x88, 0x80, 0xA2, 0x00, 0xA0, 0x06, 0xAD, + 0x02, 0x20, 0x10, 0xFB, 0x88, 0xD0, 0xF8, 0xA9, 0x00, 0x8D, 0x00, 0x20, 0x8D, 0x01, 0x20, 0xA9, + 0x3F, 0x8D, 0x06, 0x20, 0xA9, 0x01, 0x8D, 0x06, 0x20, 0xBD, 0x28, 0x81, 0x8D, 0x07, 0x20, 0xA9, + 0x1E, 0x8D, 0x01, 0x20, 0xA9, 0x80, 0x8D, 0x00, 0x20, 0xE8, 0x8A, 0xC9, 0x05, 0xD0, 0xCE, 0x60, + 0xA2, 0x05, 0xCA, 0xA0, 0x06, 0xAD, 0x02, 0x20, 0x10, 0xFB, 0x88, 0xD0, 0xF8, 0xA9, 0x00, 0x8D, + 0x00, 0x20, 0x8D, 0x01, 0x20, 0xA9, 0x3F, 0x8D, 0x06, 0x20, 0xA9, 0x01, 0x8D, 0x06, 0x20, 0xBD, + 0x28, 0x81, 0x8D, 0x07, 0x20, 0xA9, 0x1E, 0x8D, 0x01, 0x20, 0xA9, 0x80, 0x8D, 0x00, 0x20, 0x8A, + 0xD0, 0xD0, 0x60, 0xA2, 0x60, 0xAD, 0x02, 0x20, 0x10, 0xFB, 0xCA, 0xD0, 0xF8, 0x60, 0xA9, 0x0F, + 0x8D, 0x15, 0x40, 0xA9, 0x8D, 0x8D, 0x00, 0x40, 0xA9, 0x7F, 0x8D, 0x01, 0x40, 0xA9, 0x70, 0x8D, + 0x02, 0x40, 0xA9, 0x08, 0x8D, 0x03, 0x40, 0xA0, 0x05, 0xAD, 0x02, 0x20, 0x10, 0xFB, 0x88, 0xD0, + 0xF8, 0xA9, 0x54, 0x8D, 0x02, 0x40, 0x60, 0x40, 0x0F, 0x2D, 0x10, 0x3D, 0x20, +} ; + +/* interrupt vectors (FFFAh - FFFFh) */ +static uint8 intro_vec[6] = +{ + 0x27, 0x81, 0x00, 0x80, 0x27, 0x81 +}; + +/* graphics */ +static uint8 intro_vrom[4096] = +{ + 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, + 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, + 0x7F, 0x80, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x01, 0x01, 0x01, 0x81, 0xC1, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x7F, 0xFF, 0xF3, 0xF1, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x80, 0xC0, 0x80, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xC1, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE1, 0x71, 0x31, 0x39, 0x1D, 0x0D, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF1, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF3, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC7, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x7E, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x3C, 0x19, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x79, 0xF0, 0xF0, 0xF0, 0xFF, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE1, 0xF1, 0xF9, 0xF9, 0xF9, 0x01, 0xF9, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xF8, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xF8, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x78, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x78, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF1, 0x79, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x79, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0xBE, 0x80, 0x80, 0xBD, 0xA1, 0xBD, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x03, 0x00, 0x00, 0xE7, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0x00, 0x00, 0xDE, 0x10, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF3, 0x3F, 0x00, 0x00, 0xF3, 0x88, 0xF0, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xE7, 0x88, 0x8F, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xF8, 0x00, 0x00, 0x2F, 0xA8, 0xA8, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x7C, 0x00, 0x00, 0x3F, 0xA4, 0xA4, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3D, 0xA1, 0xBD, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x1F, 0x00, 0x00, 0xE7, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE1, 0x81, 0x00, 0x00, 0xC3, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0x00, 0x00, 0xD1, 0x11, 0x8E, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x7C, 0x00, 0x00, 0x3D, 0x40, 0x38, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x1F, 0x00, 0x00, 0xF7, 0x44, 0x47, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x7C, 0x00, 0x00, 0xBF, 0x24, 0xA4, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0x02, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF1, 0xC1, 0x01, 0x01, 0x19, 0x25, 0x25, 0x25, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9D, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA8, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9D, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x99, 0x01, 0xFE, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint8 *intro_getrom(void) +{ + uint8 *rom; + + rom = malloc(CODE_SIZE); + if (NULL != rom) + { + /* good measure */ + memset(rom, 0, CODE_SIZE); + + /* copy in the code */ + memcpy(rom, intro_code, sizeof(intro_code)); + + /* copy in the interrupt vectors */ + memcpy(rom + (CODE_SIZE - sizeof(intro_vec)), intro_vec, sizeof(intro_vec)); + } + + return rom; +} + +static uint8 *intro_getvrom(void) +{ + uint8 *vrom; + + vrom = malloc(VROM_SIZE); + if (NULL != vrom) + { + memcpy(vrom, intro_vrom, sizeof(intro_vrom)); + } + + return vrom; +} + +void intro_get_header(rominfo_t *rominfo) +{ + ASSERT(rominfo); + + rominfo->rom_banks = CODE_SIZE / 0x4000; + rominfo->vrom_banks = VROM_SIZE / 0x2000; + rominfo->mirror = MIRROR_VERT; + rominfo->flags = 0; + rominfo->mapper_number = 0; + + rominfo->sram_banks = 0; + rominfo->vram_banks = 0; + rominfo->sram = NULL; + rominfo->vram = NULL; + + strncpy(rominfo->filename, "Nofrendo intro", PATH_MAX); +} + +int intro_get_rom(rominfo_t *rominfo) +{ + ASSERT(rominfo); + + rominfo->rom = intro_getrom(); + rominfo->vrom = intro_getvrom(); + if (NULL == rominfo->rom || NULL == rominfo->vrom) + return -1; + + return 0; +} + +/* +** $Log: intro.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.5 2000/10/17 03:22:37 matt +** cleaning up rom module +** +** Revision 1.4 2000/10/10 13:58:13 matt +** stroustrup squeezing his way in the door +** +** Revision 1.3 2000/10/10 13:03:54 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.2 2000/07/31 04:28:46 matt +** one million cleanups +** +** Revision 1.1 2000/07/30 04:29:11 matt +** initial revision +** +*/