kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
763 wiersze
18 KiB
C
763 wiersze
18 KiB
C
/*
|
|
** 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "noftypes.h"
|
|
#include "nes6502.h"
|
|
#include "log.h"
|
|
#include "osd.h"
|
|
#include "nes.h"
|
|
#include "nes_apu.h"
|
|
#include "nes_ppu.h"
|
|
#include "nes_rom.h"
|
|
#include "nes_mmc.h"
|
|
#include "vid_drv.h"
|
|
#include "nofrendo.h"
|
|
|
|
|
|
#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 const nes6502_memread default_readhandler[] =
|
|
{
|
|
{ 0x0800, 0x1FFF, ram_read },
|
|
{ 0x2000, 0x3FFF, ppu_read },
|
|
{ 0x4000, 0x4015, apu_read },
|
|
{ 0x4016, 0x4017, ppu_readhigh },
|
|
LAST_MEMORY_HANDLER
|
|
};
|
|
|
|
static const 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)
|
|
{
|
|
nes6502_irq();
|
|
}
|
|
|
|
static uint8 nes_clearfiq(void)
|
|
{
|
|
if (nes.fiq_occurred)
|
|
{
|
|
nes.fiq_occurred = false;
|
|
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 = true;
|
|
nes6502_irq();
|
|
}
|
|
}
|
|
}
|
|
|
|
void nes_nmi(void)
|
|
{
|
|
nes6502_nmi();
|
|
}
|
|
|
|
static void nes_renderframe(bool 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);
|
|
ppu_scanline(vid_getbuffer(), 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(bool draw)
|
|
{
|
|
|
|
#ifdef NOLOOP
|
|
#else
|
|
#endif
|
|
/* blit to screen */
|
|
vid_flush();
|
|
|
|
/* grab input */
|
|
osd_getinput();
|
|
}
|
|
|
|
/* main emulation loop */
|
|
static int last_ticks, frames_to_render;
|
|
void nes_emulate(void)
|
|
{
|
|
osd_setsound(nes.apu->process);
|
|
|
|
last_ticks = nofrendo_ticks;
|
|
frames_to_render = 0;
|
|
nes.scanline_cycles = 0;
|
|
nes.fiq_cycles = (int) NES_FIQ_PERIOD;
|
|
#ifdef NOLOOP
|
|
#else
|
|
while (false == nes.poweroff)
|
|
{
|
|
if (nofrendo_ticks != last_ticks)
|
|
{
|
|
int tick_diff = nofrendo_ticks - last_ticks;
|
|
|
|
frames_to_render += tick_diff;
|
|
last_ticks = nofrendo_ticks;
|
|
}
|
|
|
|
if (true == nes.pause)
|
|
{
|
|
/* TODO: dim the screen, and pause/silence the apu */
|
|
system_video(true);
|
|
frames_to_render = 0;
|
|
}
|
|
else if (frames_to_render > 1)
|
|
{
|
|
frames_to_render--;
|
|
nes_renderframe(false);
|
|
system_video(false);
|
|
}
|
|
else if ((1 == frames_to_render && true == nes.autoframeskip)
|
|
|| false == nes.autoframeskip)
|
|
{
|
|
frames_to_render = 0;
|
|
nes_renderframe(true);
|
|
system_video(true);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//ADD ON
|
|
#ifdef NOLOOP
|
|
void nes_step(int skip)
|
|
{
|
|
if (skip) {
|
|
nes_renderframe(false);
|
|
system_video(false);
|
|
}
|
|
else {
|
|
nes_renderframe(true);
|
|
system_video(true);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
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 = true;
|
|
}
|
|
|
|
void nes_togglepause(void)
|
|
{
|
|
nes.pause ^= true;
|
|
}
|
|
|
|
/* 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 = true;
|
|
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 = true;
|
|
|
|
/* 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 = false;
|
|
machine->pause = false;
|
|
|
|
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
|
|
** bool 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
|
|
**
|
|
*/
|