MCUME/MCUME_teensy41/teensynofrendo/nes_rom_light.c

412 wiersze
10 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_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 <stdio.h>
#include <string.h>
#include "noftypes.h"
#include "nes_rom.h"
#include "nes_mmc.h"
#include "nes_ppu.h"
#include "nes.h"
#include "log.h"
#include "osd.h"
extern char *osd_getromdata();
/* 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"
//ToDo: packed - JD
typedef struct inesheader_s
{
uint8 ines_magic[4] ;
uint8 rom_banks ;
uint8 vrom_banks ;
uint8 rom_type ;
uint8 mapper_hinybble ;
uint8 reserved[8] ;
} 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
static int rom_loadrom(unsigned char **rom, rominfo_t *rominfo)
{
ASSERT(rom);
ASSERT(rominfo);
/* Allocate ROM space, and load it up! */
rominfo->rom=*rom;
*rom+=ROM_BANK_LENGTH*rominfo->rom_banks;
/* If there's VROM, allocate and stuff it in */
if (rominfo->vrom_banks)
{
rominfo->vrom=*rom;
*rom+=VROM_BANK_LENGTH*rominfo->vrom_banks;
}
else
{
rominfo->vram = emu_Malloc(VRAM_LENGTH);
if (NULL == rominfo->vram)
{
return -1;
}
memset(rominfo->vram, 0, VRAM_LENGTH);
}
return 0;
}
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 = emu_FileOpen(rominfo->filename);
if (!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 = emu_FileOpen(rominfo->filename);
}
return fp;
}
/* Add ROM name to a list with dirty headers */
static int rom_adddirty(char *filename)
{
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 (0 == fp)
return -1;
emu_FileRead(&head, 1*sizeof(head));
emu_FileClose();
if (0 == memcmp(head.ines_magic, ROM_INES_MAGIC, 4))
/* not an iNES file */
return 0;
return -1;
}
static int rom_getheader(unsigned char **rom, rominfo_t *rominfo)
{
#define RESERVED_LENGTH 8
inesheader_t head;
uint8 reserved[RESERVED_LENGTH];
bool header_dirty;
ASSERT(rom);
ASSERT(*rom);
ASSERT(rominfo);
/* Read in the header */
// _fread(&head, 1, sizeof(head), fp);
log_printf("Head: %p (%x %x %x %x)\n", *rom, (*rom)[0], (*rom)[1], (*rom)[2], (*rom)[3]);
memcpy(&head, *rom, sizeof(head));
*rom+=sizeof(head);
if (memcmp(head.ines_magic, ROM_INES_MAGIC, 4))
{
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 = false;
rominfo->mapper_number |= (head.mapper_hinybble & 0xF0);
}
else
{
header_dirty = true;
/* @!?#@! 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)
{
unsigned char *rom=(unsigned char*)osd_getromdata();
rominfo_t *rominfo;
rominfo = emu_Malloc(sizeof(rominfo_t));
if (NULL == rominfo)
return NULL;
memset(rominfo, 0, sizeof(rominfo_t));
/* Get the header and stick it into rominfo struct */
if (rom_getheader(&rom, rominfo))
goto _fail;
/* Make sure we really support the mapper */
if (false == mmc_peek(rominfo->mapper_number))
{
goto _fail;
}
if (rom_loadrom(&rom, rominfo))
goto _fail;
return rominfo;
_fail:
rom_free(&rominfo);
return NULL;
}
/* Free a ROM */
void rom_free(rominfo_t **rominfo)
{
if (NULL == *rominfo)
{
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");
}
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);
}
/*
** $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
**
*/