mirror of
https://github.com/mist-devel/mist-firmware.git
synced 2026-04-25 03:55:33 +00:00
snes.c: detect SNES ROM type
Need a small core change, too
This commit is contained in:
2
Makefile
2
Makefile
@@ -11,7 +11,7 @@ TODAY = `date +"%m/%d/%y"`
|
||||
|
||||
PRJ = firmware
|
||||
SRC = hw/AT91SAM/Cstartup_SAM7.c hw/AT91SAM/hardware.c hw/AT91SAM/spi.c hw/AT91SAM/mmc.c hw/AT91SAM/at91sam_usb.c hw/AT91SAM/usbdev.c
|
||||
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c arc_file.c font.c utils.c
|
||||
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c snes.c arc_file.c font.c utils.c
|
||||
SRC += usb/usb.c usb/max3421e.c usb/usb-max3421e.c usb/usbdebug.c usb/hub.c usb/hid.c usb/hidparser.c usb/xboxusb.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/storage.c usb/joymapping.c usb/joystick.c
|
||||
SRC += fat_compat.c
|
||||
SRC += FatFs/diskio.c FatFs/ff.c FatFs/ffunicode.c
|
||||
|
||||
@@ -12,7 +12,7 @@ TODAY = `date +"%m/%d/%y"`
|
||||
PRJ = firmware
|
||||
SRC = hw/ATSAMV71/cstartup.c hw/ATSAMV71/hardware.c hw/ATSAMV71/spi.c hw/ATSAMV71/qspi.c hw/ATSAMV71/mmc.c hw/ATSAMV71/usbdev.c hw/ATSAMV71/eth.c hw/ATSAMV71/irq/nvic.c
|
||||
SRC += hw/ATSAMV71/network/intmath.c hw/ATSAMV71/network/gmac.c hw/ATSAMV71/network/gmacd.c hw/ATSAMV71/network/phy.c hw/ATSAMV71/network/ethd.c
|
||||
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c psx.c arc_file.c font.c utils.c
|
||||
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c menu-minimig.c menu-8bit.c osd.c state.c syscalls.c user_io.c settings.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c neocd.c psx.c snes.c arc_file.c font.c utils.c
|
||||
SRC += it6613/HDMI_TX.c it6613/it6613_drv.c it6613/it6613_sys.c it6613/EDID.c it6613/hdmitx_mist.c
|
||||
SRC += usb/usbdebug.c usb/hub.c usb/xboxusb.c usb/hid.c usb/hidparser.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/joymapping.c usb/joystick.c usb/storage.c
|
||||
SRC += usb/usb.c usb/max3421e.c usb/usb-max3421e.c
|
||||
|
||||
7
debug.h
7
debug.h
@@ -161,6 +161,13 @@
|
||||
#define psx_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// SNES debug output
|
||||
#define snes_debugf(a, ...) iprintf("\033[1;34mSNES : " a "\033[0m\n",## __VA_ARGS__)
|
||||
#else
|
||||
#define snes_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// HDMI debug output
|
||||
#define hdmi_debugf(a, ...) iprintf("\033[1;34mHDMI : " a "\033[0m",## __VA_ARGS__)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "data_io.h"
|
||||
#include "fat_compat.h"
|
||||
#include "cue_parser.h"
|
||||
#include "snes.h"
|
||||
|
||||
extern char s[FF_LFN_BUF + 1];
|
||||
|
||||
@@ -39,6 +40,7 @@ extern char fs_pFileExt[13];
|
||||
/////// 8-bit menu ///////
|
||||
//////////////////////////
|
||||
static unsigned char selected_drive_slot;
|
||||
static unsigned char isSnesROM;
|
||||
|
||||
|
||||
static void substrcpy(char *d, char *s, char idx) {
|
||||
@@ -116,9 +118,11 @@ static unsigned long long getStatusMask(char *opt) {
|
||||
|
||||
static char RomFileSelected(uint8_t idx, const char *SelectedName) {
|
||||
FIL file;
|
||||
char snes_romtype;
|
||||
// this assumes that further file entries only exist if the first one also exists
|
||||
if (f_open(&file, SelectedName, FA_READ) == FR_OK) {
|
||||
data_io_file_tx(&file, user_io_ext_idx(SelectedName, fs_pFileExt)<<6 | selected_drive_slot, GetExtension(SelectedName));
|
||||
if (isSnesROM) snes_romtype = snes_getromtype(&file);
|
||||
data_io_file_tx(&file, (isSnesROM ? snes_romtype : user_io_ext_idx(SelectedName, fs_pFileExt))<<6 | selected_drive_slot, GetExtension(SelectedName));
|
||||
f_close(&file);
|
||||
}
|
||||
// close menu afterwards
|
||||
@@ -192,6 +196,7 @@ static char GetMenuItem_8bit(uint8_t idx, char action, menu_item_t *item) {
|
||||
strncpy(ext, p, 13);
|
||||
while(strlen(ext) < 3) strcat(ext, " ");
|
||||
selected_drive_slot = 1;
|
||||
isSnesROM = 0;
|
||||
SelectFileNG(ext, SCAN_DIR | SCAN_LFN, RomFileSelected, 1);
|
||||
} else if (action == MENU_ACT_GET) {
|
||||
//menumask = 1;
|
||||
@@ -244,6 +249,8 @@ static char GetMenuItem_8bit(uint8_t idx, char action, menu_item_t *item) {
|
||||
iscue = 1;
|
||||
}
|
||||
if (p[1]>='0' && p[1]<='9') selected_drive_slot = p[1]-'0';
|
||||
isSnesROM = 0;
|
||||
if (p[1] && p[1] != ',' && p[2] && p[2] != ',' && !strncmp(&p[2], "SNES", 4)) isSnesROM = 1; // F1SNES
|
||||
substrcpy(ext, p, 1);
|
||||
while(strlen(ext) < 3) strcat(ext, " ");
|
||||
SelectFileNG(ext, SCAN_DIR | SCAN_LFN, (p[0] == 'F')?RomFileSelected:iscue?CueFileSelected:ImageFileSelected, 1);
|
||||
|
||||
166
snes.c
Normal file
166
snes.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
This file is part of MiST-firmware
|
||||
|
||||
MiST-firmware is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MiST-firmware 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "snes.h"
|
||||
#include "fat_compat.h"
|
||||
#include "debug.h"
|
||||
|
||||
enum HeaderField {
|
||||
CartName = 0x00,
|
||||
Mapper = 0x15,
|
||||
RomType = 0x16,
|
||||
RomSize = 0x17,
|
||||
RamSize = 0x18,
|
||||
CartRegion = 0x19,
|
||||
Company = 0x1a,
|
||||
Version = 0x1b,
|
||||
Complement = 0x1c, //inverse checksum
|
||||
Checksum = 0x1e,
|
||||
ResetVector = 0x3c,
|
||||
};
|
||||
|
||||
// From Main_MiSTer/support/snes/snes.cpp
|
||||
static uint32_t score_header(FIL *file, uint32_t offset, uint32_t addr)
|
||||
{
|
||||
int score = 0;
|
||||
UINT br;
|
||||
uint8_t *data = sector_buffer;
|
||||
|
||||
snes_debugf("Header address: %08x offset: %d", addr, offset);
|
||||
|
||||
if ((f_lseek(file, offset + addr) != FR_OK) ||
|
||||
(f_tell(file) != (offset + addr)) ||
|
||||
(f_read(file, data, 64, &br) != FR_OK)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t resetvector = data[ResetVector] | (data[ResetVector + 1] << 8);
|
||||
uint16_t checksum = data[Checksum] | (data[Checksum + 1] << 8);
|
||||
uint16_t complement = data[Complement] | (data[Complement + 1] << 8);
|
||||
|
||||
snes_debugf("Reset vector: %04x, checksum: %04x, complement: %04x", resetvector, checksum, complement);
|
||||
|
||||
//$00:[0000-7fff] contains uninitialized RAM and MMIO.
|
||||
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
|
||||
if (resetvector < 0x8000) return 0;
|
||||
|
||||
uint8_t resetop = 0;
|
||||
if (f_lseek(file, ((addr & ~0x7fff) | (resetvector & 0x7fff)) + offset ) != FR_OK) return 0;
|
||||
if (f_read(file, &resetop, 1, &br) != FR_OK) return 0;
|
||||
//uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
|
||||
uint8_t mapper = data[Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
|
||||
|
||||
//some images duplicate the header in multiple locations, and others have completely
|
||||
//invalid header information that cannot be relied upon.
|
||||
//below code will analyze the first opcode executed at the specified reset vector to
|
||||
//determine the probability that this is the correct header.
|
||||
|
||||
//most likely opcodes
|
||||
if (resetop == 0x78 //sei
|
||||
|| resetop == 0x18 //clc (clc; xce)
|
||||
|| resetop == 0x38 //sec (sec; xce)
|
||||
|| resetop == 0x9c //stz $nnnn (stz $4200)
|
||||
|| resetop == 0x4c //jmp $nnnn
|
||||
|| resetop == 0x5c //jml $nnnnnn
|
||||
) score += 8;
|
||||
|
||||
//plausible opcodes
|
||||
if (resetop == 0xc2 //rep #$nn
|
||||
|| resetop == 0xe2 //sep #$nn
|
||||
|| resetop == 0xad //lda $nnnn
|
||||
|| resetop == 0xae //ldx $nnnn
|
||||
|| resetop == 0xac //ldy $nnnn
|
||||
|| resetop == 0xaf //lda $nnnnnn
|
||||
|| resetop == 0xa9 //lda #$nn
|
||||
|| resetop == 0xa2 //ldx #$nn
|
||||
|| resetop == 0xa0 //ldy #$nn
|
||||
|| resetop == 0x20 //jsr $nnnn
|
||||
|| resetop == 0x22 //jsl $nnnnnn
|
||||
) score += 4;
|
||||
|
||||
//implausible opcodes
|
||||
if (resetop == 0x40 //rti
|
||||
|| resetop == 0x60 //rts
|
||||
|| resetop == 0x6b //rtl
|
||||
|| resetop == 0xcd //cmp $nnnn
|
||||
|| resetop == 0xec //cpx $nnnn
|
||||
|| resetop == 0xcc //cpy $nnnn
|
||||
) score -= 4;
|
||||
|
||||
//least likely opcodes
|
||||
if (resetop == 0x00 //brk #$nn
|
||||
|| resetop == 0x02 //cop #$nn
|
||||
|| resetop == 0xdb //stp
|
||||
|| resetop == 0x42 //wdm
|
||||
|| resetop == 0xff //sbc $nnnnnn,x
|
||||
) score -= 8;
|
||||
|
||||
//at times, both the header and reset vector's first opcode will match ...
|
||||
//fallback and rely on info validity in these cases to determine more likely header.
|
||||
|
||||
//a valid checksum is the biggest indicator of a valid header.
|
||||
if ((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
|
||||
|
||||
|
||||
if (addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
|
||||
if (addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
|
||||
if (addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1
|
||||
if (addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
|
||||
|
||||
if (data[Company] == 0x33) score += 2; //0x33 indicates extended header
|
||||
if (data[RomType] < 0x08) score++;
|
||||
if (data[RomSize] < 0x10) score++;
|
||||
if (data[RamSize] < 0x08) score++;
|
||||
if (data[CartRegion] < 14) score++;
|
||||
|
||||
snes_debugf("Resetop: %02x mapper: %02x score: %d",
|
||||
resetop, mapper, score);
|
||||
|
||||
if (score < 0) score = 0;
|
||||
return score;
|
||||
}
|
||||
|
||||
char snes_getromtype(FIL *file)
|
||||
{
|
||||
uint32_t score_lo, score_hi, score_ex;
|
||||
UINT br;
|
||||
FSIZE_t size = f_size(file);
|
||||
FSIZE_t offset = size & 0x1ff;
|
||||
|
||||
score_lo = score_header(file, offset, (FSIZE_t) 0x007fc0);
|
||||
score_hi = score_header(file, offset, (FSIZE_t) 0x00ffc0);
|
||||
score_ex = score_header(file, offset, (FSIZE_t) 0x40ffc0);
|
||||
f_rewind(file);
|
||||
|
||||
if (score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
|
||||
if (score_lo >= score_hi && score_lo >= score_ex) {
|
||||
iprintf("Detected LoROM\n");
|
||||
return 0; // probably LoROM
|
||||
}
|
||||
if (score_hi >= score_ex) {
|
||||
iprintf("Detected HiROM\n");
|
||||
return 1; // probably HiROM
|
||||
}
|
||||
if (score_ex) {
|
||||
iprintf("Detected ExHiROM\n");
|
||||
return 2; // probably ExHiROM
|
||||
}
|
||||
iprintf("No clue about ROM type\n");
|
||||
return 0; // no idea, fall back to LoROM
|
||||
}
|
||||
25
snes.h
Normal file
25
snes.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
This file is part of MiST-firmware
|
||||
|
||||
MiST-firmware is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MiST-firmware 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SNES_H
|
||||
#define SNES_H
|
||||
|
||||
#include "FatFs/ff.h"
|
||||
|
||||
char snes_getromtype(FIL *file);
|
||||
|
||||
#endif // SNES_H
|
||||
Reference in New Issue
Block a user