kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
354 wiersze
8.6 KiB
C
Executable File
354 wiersze
8.6 KiB
C
Executable File
/*
|
|
** 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 <string.h>
|
|
#include "noftypes.h"
|
|
#include "nes6502.h"
|
|
#include "nes_mmc.h"
|
|
#include "nes_ppu.h"
|
|
#include "libsnss.h"
|
|
#include "log.h"
|
|
#include "mmclist.h"
|
|
#include "nes_rom.h"
|
|
|
|
#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 */
|
|
bool mmc_peek(int map_num)
|
|
{
|
|
mapintf_t **map_ptr = mappers;
|
|
|
|
while (NULL != *map_ptr)
|
|
{
|
|
if ((*map_ptr)->number == map_num)
|
|
return true;
|
|
map_ptr++;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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
|
|
**
|
|
*/
|