NES: Fixed FDS BIOS loading to match the README and give a proper error

This commit is contained in:
Alex Duchesne 2021-08-29 15:08:22 -04:00
parent 73cb29e2c9
commit 21940f2d56
7 changed files with 99 additions and 74 deletions

View File

@ -34,7 +34,7 @@
#define FDS_CLOCK (NES_CPU_CLOCK_NTSC / 2)
#define SEEK_TIME 100 // 150
#define CLEAR_IRQ() irq.seek_counter = irq.transfer_done = irq.timer_fired = 0; nes6502_irq_clear();
#define TIMER_RELOAD() irq.timer_counter = (fds->regs[1] << 8) | fds->regs[0];
#define TIMER_RELOAD() irq.timer_counter = (fds.regs[1] << 8) | fds.regs[0];
#define REG2_IRQ_REPEAT (1 << 0)
#define REG2_IRQ_ENABLED (1 << 1)
@ -80,18 +80,18 @@ struct
bool transfer_done;
} irq;
static fds_t *fds;
static fds_t fds;
static void fds_cpu_timer(int cycles)
{
if (irq.timer_counter > 0 && (fds->regs[2] & REG2_IRQ_ENABLED))
if (irq.timer_counter > 0 && (fds.regs[2] & REG2_IRQ_ENABLED))
{
irq.timer_counter -= cycles;
if (irq.timer_counter <= 0)
{
if (!(fds->regs[2] & REG2_IRQ_REPEAT))
fds->regs[2] &= ~REG2_IRQ_ENABLED;
if (!(fds.regs[2] & REG2_IRQ_REPEAT))
fds.regs[2] &= ~REG2_IRQ_ENABLED;
TIMER_RELOAD();
nes6502_irq();
@ -105,7 +105,7 @@ static void fds_cpu_timer(int cycles)
irq.seek_counter -= cycles;
if (irq.seek_counter <= 0)
{
if (fds->regs[5] & REG5_USE_INTERRUPT)
if (fds.regs[5] & REG5_USE_INTERRUPT)
{
nes6502_irq();
}
@ -133,13 +133,13 @@ static uint8 fds_read(uint32 address)
return ret;
case 0x4031: // Read data register
if (fds->regs[5] & 0x04)
if (fds.regs[5] & 0x04)
{
CLEAR_IRQ();
irq.seek_counter = SEEK_TIME;
if (fds->block_pos < fds->block_size)
return fds->block_ptr[fds->block_pos++];
if (fds.block_pos < fds.block_size)
return fds.block_ptr[fds.block_pos++];
else
return 0;
}
@ -147,7 +147,7 @@ static uint8 fds_read(uint32 address)
case 0x4032: // Disk drive status register
// wprotect|/ready|/inserted
if (!(fds->regs[5] & 1) || (fds->regs[5] & 2))
if (!(fds.regs[5] & 1) || (fds.regs[5] & 2))
return 0b110;
return 0b100;
@ -191,42 +191,42 @@ static void fds_write(uint32 address, uint8 value)
// Transfer Reset
if (value & 0x02)
{
fds->block_type = BLOCK_INIT;
fds->block_ptr = &fds->disk[0][0];
fds->block_filesize = 0;
fds->block_size = 0;
fds->block_pos = 0;
fds.block_type = BLOCK_INIT;
fds.block_ptr = &fds.disk[0][0];
fds.block_filesize = 0;
fds.block_size = 0;
fds.block_pos = 0;
}
// New transfer
if (value & 0x40 && ~(fds->regs[5]) & 0x40)
if (value & 0x40 && ~(fds.regs[5]) & 0x40)
{
fds->block_ptr = fds->block_ptr + fds->block_pos;
fds->block_pos = 0;
fds.block_ptr = fds.block_ptr + fds.block_pos;
fds.block_pos = 0;
switch (fds->block_type + 1)
switch (fds.block_type + 1)
{
case BLOCK_VOLUME:
fds->block_type = BLOCK_VOLUME;
fds->block_size = 0x38;
fds.block_type = BLOCK_VOLUME;
fds.block_size = 0x38;
break;
case BLOCK_FILECOUNT:
fds->block_type = BLOCK_FILECOUNT;
fds->block_size = 0x02;
fds.block_type = BLOCK_FILECOUNT;
fds.block_size = 0x02;
break;
case BLOCK_FILEHEADER:
case BLOCK_NEXT:
fds->block_type = BLOCK_FILEHEADER;
fds->block_size = 0x10;
fds->block_filesize = (fds->block_ptr[13]) | (fds->block_ptr[14]) << 8;
fds.block_type = BLOCK_FILEHEADER;
fds.block_size = 0x10;
fds.block_filesize = (fds.block_ptr[13]) | (fds.block_ptr[14]) << 8;
break;
case BLOCK_FILEDATA:
fds->block_type = BLOCK_FILEDATA;
fds->block_size = 0x01 + fds->block_filesize;
fds.block_type = BLOCK_FILEDATA;
fds.block_size = 0x01 + fds.block_filesize;
break;
}
MESSAGE_INFO("Block type %d with size %d bytes\n", fds->block_type, fds->block_size);
MESSAGE_INFO("Block type %d with size %d bytes\n", fds.block_type, fds.block_size);
}
// Turn on motor
@ -236,7 +236,7 @@ static void fds_write(uint32 address, uint8 value)
}
// Update mirroring
if ((value & REG5_MIRRORING) != (fds->regs[5] & REG5_MIRRORING) || fds->regs[5] == 0)
if ((value & REG5_MIRRORING) != (fds.regs[5] & REG5_MIRRORING) || fds.regs[5] == 0)
{
ppu_setmirroring((value & REG5_MIRRORING) ? PPU_MIRROR_HORI : PPU_MIRROR_VERT);
}
@ -244,7 +244,7 @@ static void fds_write(uint32 address, uint8 value)
break;
}
fds->regs[address & 7] = value;
fds.regs[address & 7] = value;
}
static uint8 fds_sound_read(uint32 address)
@ -281,40 +281,28 @@ static void fds_setstate(void *state)
void fds_init(rom_t *cart)
{
if (!fds)
{
fds = calloc(1, sizeof(fds_t));
// I'm not sure yet where we should load the bios
// so it shall be hardcoded here while I work on
// the actual hardware emulation...
FILE *fp = fopen("/sd/roms/fds/disksys.rom", "rb");
fread(cart->prg_rom, 0x2000, 1, fp);
fclose(fp);
}
uint8 *disk_ptr = cart->data_ptr;
if (memcmp(disk_ptr, FDS_HEAD_MAGIC, 4) == 0)
{
fds->sides = ((fdsheader_t *)disk_ptr)->sides;
fds.sides = ((fdsheader_t *)disk_ptr)->sides;
disk_ptr += 16;
MESSAGE_INFO("FDS header present. Sides = %d\n", fds->sides);
MESSAGE_INFO("FDS header present. Sides = %d\n", fds.sides);
}
else
{
fds->sides = cart->data_len / 65500;
MESSAGE_INFO("FDS header absent. Sides = %d\n", fds->sides);
fds.sides = cart->data_len / 65500;
MESSAGE_INFO("FDS header absent. Sides = %d\n", fds.sides);
}
for (int i = 0; i < 8; i++)
{
if (i < fds->sides || cart->data_len > i * 65500)
fds->disk[i] = disk_ptr + (i * 65500);
if (i < fds.sides || cart->data_len > i * 65500)
fds.disk[i] = disk_ptr + (i * 65500);
else
fds->disk[i] = NULL;
fds.disk[i] = NULL;
}
fds->block_ptr = &fds->disk[0][0];
fds.block_ptr = &fds.disk[0][0];
mmc_bankprg(32, 0x6000, 0, PRG_RAM); // PRG-RAM 0x6000-0xDFFF
mmc_bankprg(8, 0xE000, 0, PRG_ROM); // BIOS 0xE000-0xFFFF

View File

@ -135,17 +135,25 @@ void nes_setcompathacks(void)
}
/* insert a cart into the NES */
rom_t *nes_insertcart(const char *filename)
int nes_insertcart(const char *filename, const char *biosfile)
{
int status = 0;
/* rom file */
nes.cart = rom_loadfile(filename);
if (NULL == nes.cart)
{
status = -1;
goto _fail;
}
/* mapper */
nes.mapper = mmc_init(nes.cart);
if (NULL == nes.mapper)
{
status = -2;
goto _fail;
}
/* if we're using VRAM, let the PPU know */
nes.ppu->vram_present = (nes.cart->chr_rom == NULL);
@ -184,21 +192,42 @@ rom_t *nes_insertcart(const char *filename)
nes.overscan = 8;
}
/* Load BIOS file if required (currently only for Famicom Disk System) */
if (nes.cart->flags & ROM_FLAG_FDS_DISK)
{
if (biosfile == NULL)
{
// TO DO: Try biosfile = dirname(filename) / disksys.rom
status = -3;
goto _fail;
}
FILE *fp = fopen(biosfile, "rb");
if (!fp || !fread(nes.cart->prg_rom, ROM_PRG_BANK_SIZE, nes.cart->prg_rom_banks, fp))
{
MESSAGE_ERROR("NES: BIOS file load failed from '%s'.\n", biosfile);
status = -3;
fclose(fp);
goto _fail;
}
fclose(fp);
MESSAGE_INFO("NES: BIOS file loaded from '%s'.\n", biosfile);
}
nes_setcompathacks();
nes_reset(true);
return nes.cart;
return status;
_fail:
nes_shutdown();
return NULL;
return status;
}
/* insert a disk into the FDS */
rom_t *nes_insertdisk(const char *filename)
int nes_insertdisk(const char *filename, const char *biosfile)
{
return NULL;
return nes_insertcart(filename, biosfile);
}
/* Reset NES hardware */

View File

@ -123,8 +123,8 @@ typedef struct
nes_t *nes_getptr(void);
nes_t *nes_init(nes_type_t system, int sample_rate, bool stereo);
void nes_shutdown(void);
rom_t *nes_insertcart(const char *filename);
rom_t *nes_insertdisk(const char *filename);
int nes_insertcart(const char *filename, const char *biosfile);
int nes_insertdisk(const char *filename, const char *biosfile);
void nes_settimer(nes_timer_t *func, long period);
void nes_emulate(bool draw);
void nes_reset(bool hard_reset);

View File

@ -107,6 +107,8 @@ rom_t *rom_loadmem(uint8 *data, size_t size)
rom.flags = header->rom_type;
rom.mapper_number = header->rom_type >> 4;
MESSAGE_INFO("ROM: CRC32: %08X\n", rom.checksum);
if (header->reserved2 == 0)
{
// https://wiki.nesdev.com/w/index.php/INES
@ -186,7 +188,6 @@ rom_t *rom_loadmem(uint8 *data, size_t size)
rom.chr_rom = rom.prg_rom + (rom.prg_rom_banks * ROM_PRG_BANK_SIZE);
}
MESSAGE_INFO("ROM: CRC32: %08X\n", rom.checksum);
MESSAGE_INFO("ROM: Mapper: %d, PRG:%dK, CHR:%dK, Flags: %c%c%c%c\n",
rom.mapper_number,
rom.prg_rom_banks * 8, rom.chr_rom_banks * 8,
@ -202,25 +203,26 @@ rom_t *rom_loadmem(uint8 *data, size_t size)
{
MESSAGE_INFO("ROM: Found FDS file of size %d.\n", size);
rom.flags = ROM_FLAG_FDS_DISK|ROM_FLAG_BATTERY;
rom.prg_ram_banks = 4;
rom.chr_ram_banks = 1;
rom.prg_rom_banks = 1;
rom.prg_ram = malloc(0x8000 + 0x2000);
rom.chr_ram = malloc(0x2000);
rom.prg_rom = rom.prg_ram + 0x8000;
if (!rom.prg_ram || !rom.chr_ram)
{
MESSAGE_ERROR("ROM: Memory allocation failed!\n");
return NULL;
}
rom.checksum = crc32_le(0, rom.data_ptr, rom.data_len);
rom.mapper_number = 20;
MESSAGE_INFO("ROM: CRC32: %08X\n", rom.checksum);
rom.prg_ram = malloc((rom.prg_ram_banks + rom.prg_rom_banks) * ROM_PRG_BANK_SIZE);
rom.chr_ram = malloc(rom.chr_ram_banks * ROM_CHR_BANK_SIZE);
// We do it this way because only rom.prg_ram is freed in rom_free
rom.prg_rom = rom.prg_ram + (rom.prg_ram_banks * ROM_PRG_BANK_SIZE);
if (!rom.prg_ram || !rom.chr_ram || !rom.prg_rom)
{
MESSAGE_ERROR("ROM: Memory allocation failed!\n");
return NULL;
}
strncpy(rom.filename, "filename.fds", PATH_MAX);
return &rom;
}

View File

@ -32,6 +32,7 @@
#define ROM_FLAG_BATTERY 0x02
#define ROM_FLAG_VERTICAL 0x01
#define ROM_FLAG_FREE_DATA 0x100
#define ROM_FLAG_FDS_DISK 0x200
#define ROM_PRG_BANK_SIZE 0x2000
#define ROM_CHR_BANK_SIZE 0x2000

View File

@ -107,7 +107,7 @@ int nofrendo_run(const char *filename, const char *savefile)
{
nes_t *nes = nes_getptr();
if (!nes_insertcart(filename))
if (nes_insertcart(filename, NULL) < 0)
{
MESSAGE_ERROR("Failed to insert NES cart.\n");
return -2;

View File

@ -257,10 +257,15 @@ void app_main(void)
RG_PANIC("Init failed.");
}
if (!nes_insertcart(app->romPath))
{
int ret = nes_insertcart(app->romPath, "/sd/bios/fds_bios.bin");
if (ret == -1)
RG_PANIC("ROM load failed.");
else if (ret == -2)
RG_PANIC("Unsupported mapper.");
else if (ret == -3)
RG_PANIC("BIOS file required.");
else if (ret < 0)
RG_PANIC("Unsupported ROM.");
}
app->refreshRate = nes->refresh_rate;
nes->blit_func = osd_blitscreen;