From ff5fcf6d337bc14db4e44e4b47042d4a4e328711 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Fri, 29 Jan 2016 22:17:59 +1100 Subject: [PATCH 01/10] Basic implementation of the Transferpak, is now partially working. Have to re-implement the RTC and ensure the mbc emulation of all current carts is accurate. Settings implementation needs to be done as well. This code is based on work from NRAGE and Bobby Smiles work on Mupen64plus's implementation. --- .../Project64-core/N64System/Mips/GBCart.cpp | 810 ++++++++++++++++++ Source/Project64-core/N64System/Mips/GBCart.h | 46 + .../Project64-core/N64System/Mips/PifRam.cpp | 9 +- .../N64System/Mips/Transferpak.h | 37 + .../N64System/Mips/Trasferpak.cpp | 119 +++ Source/Project64-core/N64System/N64Class.cpp | 3 + Source/Project64-core/Project64-core.vcxproj | 4 + .../Project64-core.vcxproj.filters | 12 + 8 files changed, 1036 insertions(+), 4 deletions(-) create mode 100644 Source/Project64-core/N64System/Mips/GBCart.cpp create mode 100644 Source/Project64-core/N64System/Mips/GBCart.h create mode 100644 Source/Project64-core/N64System/Mips/Transferpak.h create mode 100644 Source/Project64-core/N64System/Mips/Trasferpak.cpp diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp new file mode 100644 index 000000000..025d5eedb --- /dev/null +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -0,0 +1,810 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include "stdafx.h" +#include "GBCart.h" + +#include + +//-------------------------------------------------------------------------------------- +bool read_from_file(const char *filename, void *data, size_t size) +{ + FILE *f = fopen(filename, "rb"); + if (f == NULL) + { + return false; + } + + if (fread(data, 1, size, f) != size) + { + fclose(f); + return false; + } + + fclose(f); + return true; +} + +bool load_file(const char* filename, void** buffer, size_t* size) +{ + FILE* fd; + size_t l_size; + void* l_buffer; + int err; + bool ret; + + /* open file */ + ret = false; + fd = fopen(filename, "rb"); + if (fd == NULL) + { + return false; + } + + /* obtain file size */ + ret = false; + err = fseek(fd, 0, SEEK_END); + if (err != 0) + { + goto close_file; + } + + err = ftell(fd); + if (err == -1) + { + goto close_file; + } + l_size = (size_t)err; + + err = fseek(fd, 0, SEEK_SET); + if (err != 0) + { + goto close_file; + } + + /* allocate buffer */ + l_buffer = malloc(l_size); + if (l_buffer == NULL) + { + goto close_file; + } + + /* copy file content to buffer */ + ret = false; + err = fread(l_buffer, 1, l_size, fd); + if (err != l_size) + { + free(l_buffer); + goto close_file; + } + + /* commit buffer,size */ + ret = true; + *buffer = l_buffer; + *size = l_size; + + /* close file */ +close_file: + fclose(fd); + return ret; +} +//-------------------------------------------------------------------------------------- + +static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + uint16_t offset; + + if ((address >= 0x0000) && (address <= 0x7FFF)) + { + //Read GB Cart + if (address >= gb_cart->rom_size) + { + //If address is larger then our rome size, bail out + return; + } + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) + { + //Read from RAM + if (gb_cart->ram == NULL) + { + //No RAM to write to + return; + } + + offset = address - 0xA000; + if (offset >= gb_cart->ram_size) + { + //Offset is larger then our ram size + return; + } + + memcpy(&gb_cart->ram[offset], data, 0x20); + memcpy(data, &gb_cart->ram[offset], 0x20); + } +} + +static void write_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + uint16_t offset; + if ((address >= 0xA000) && (address <= 0xBFFF)) + { + //Write to RAM + if (gb_cart->ram == NULL) + { + //No RAM to write to + return; + } + + offset = address - 0xa000; + if (offset >= gb_cart->ram_size) + { + //Offset is larger then our ram size + return; + } + + memcpy(&gb_cart->ram[offset], data, 0x20); + } + +} + +static void read_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + size_t offset; + + if ((address >= 0x0000) && (address <= 0x3FFF)) //No nbanked memory + { + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0x4000) && (address <= 0x7FFF)) //Read from ROM + { + offset = (address - 0x4000) + (gb_cart->rom_bank * 0x4000); + if (offset < gb_cart->rom_size) + { + memcpy(data, &gb_cart->rom[offset], 0x20); + } + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) //Read from RAM + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + } +} + +static void write_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + size_t offset; + + if ((address >= 0x0000) && (address <= 0x1FFF)) // RAM enable + { + //Enable/disable RAM + gb_cart->ram_enabled = (data[0] & 0x0F) == 0x0A; + } + else if ((address >= 0x2000) && (address <= 0x3FFF)) // ROM bank select + { + gb_cart->rom_bank &= 0x60; // keep MSB + gb_cart->rom_bank |= data[0] & 0x1F; + + // emulate quirk: 0x00 -> 0x01, 0x20 -> 0x21, 0x40->0x41, 0x60 -> 0x61 + if ((gb_cart->rom_bank & 0x1F) == 0) + { + gb_cart->rom_bank |= 0x01; + } + } + else if ((address >= 0x4000) && (address <= 0x5FFF)) // RAM bank select + { + if (gb_cart->ram_bank_mode) + { + gb_cart->ram_bank = data[0] & 0x03; + } + else + { + gb_cart->rom_bank &= 0x1F; + gb_cart->rom_bank |= ((data[0] & 0x03) << 5); // set bits 5 and 6 of ROM bank + } + } + else if ((address >= 0x6000) && (address <= 0x7FFF)) // MBC1 mode select + { + // this is overly complicated, but it keeps us from having to do bitwise math later + // Basically we shuffle the 2 "magic bits" between rom_bank and ram_bank as necessary. + if (gb_cart->ram_bank_mode != (data[0] & 0x01)) + { + // we should only alter the ROM and RAM bank numbers if we have changed modes + gb_cart->ram_bank_mode = data[0] & 0x01; + if (gb_cart->ram_bank_mode) + { + gb_cart->ram_bank = gb_cart->rom_bank >> 5; // set the ram bank to the "magic bits" + gb_cart->rom_bank &= 0x1F; // zero out bits 5 and 6 to keep consistency + } + else + { + gb_cart->rom_bank &= 0x1F; + gb_cart->rom_bank |= (gb_cart->ram_bank << 5); + gb_cart->ram_bank = 0x00; // we can only reach RAM page 0 + } + } + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + } +} + +static void read_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + size_t offset; + + if ((address < 0x4000)) //Rom Bank 0 + { + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0x4000) && (address < 0x8000)) //Switchable Rom Bank + { + offset = (address - 0x4000) + (gb_cart->rom_bank * 0x4000); + if (offset < gb_cart->rom_size) + { + memcpy(data, &gb_cart->rom[offset], 0x20); + } + } + else if ((address >= 0xA000) && (address <= 0xC000)) //Upper Bounds of memory map + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + } +} + +static void write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + size_t offset; + + if ((address >= 0x0000) && (address <= 0x1FFF)) // We shouldn't be able to read/write to RAM unless this is toggled on + { + gb_cart->ram_enabled = (data[0] & 0x0F) == 0x0A; + } + else if ((address >= 0x2000) && (address <= 0x3FFF)) // ROM bank select + { + gb_cart->rom_bank = data[0] & 0x0F; + if (gb_cart->rom_bank == 0) + { + gb_cart->rom_bank = 1; + } + } + else if ((address >= 0x4000) && (address <= 0x5FFF)) // RAM bank select + { + if (gb_cart->ram != NULL) + { + gb_cart->ram_bank = data[0] & 0x07; + } + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + } +} + + +static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + size_t offset; + + if ((address < 0x4000)) //Rom Bank 0 + { + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0x4000) && (address < 0x8000)) //Switchable Rom Bank + { + offset = (address - 0x4000) + (gb_cart->rom_bank * 0x4000); + if (offset < gb_cart->rom_size) + { + memcpy(data, &gb_cart->rom[offset], 0x20); + } + else + { + memset(data, 0x00, 0x20); + } + } + else if ((address >= 0xA000) && (address <= 0xC000)) //Upper Bounds of memory map + { + if (gb_cart->ram != NULL) + { + if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x08 && gb_cart->ram_bank <= 0x0c)) + { + /* XXX: implement RTC read */ + memset(data, 0, 0x20); + } + else + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + } + } +} + +static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + uint8_t bank; + size_t offset; + + if ((address >= 0x0000) && (address <= 0x1FFF)) // We shouldn't be able to read/write to RAM unless this is toggled on + { + //Enable / Disable RAM -- NOT WORKING -- FIXME + gb_cart->ram_enabled = (data[0] & 0x0F) == 0x0A; + } + else if ((address >= 0x2000) && (address <= 0x3FFF)) // ROM bank select + { + bank = data[0] & 0x7f; + gb_cart->rom_bank = (bank == 0) ? 1 : bank; + } + else if ((address >= 0x4000) && (address <= 0x5FFF)) // RAM/Clock bank select + { + if (gb_cart->ram != NULL) + { + bank = data[0]; + if (gb_cart->has_rtc && (bank >= 0x8 && bank <= 0xc)) + { + //Set the bank for the timer + gb_cart->ram_bank = bank; + } + else + { + gb_cart->ram_bank = bank & 0x03; + } + } + } + else if ((address >= 0x6000) && (address <= 0x7FFF)) // Latch timer data + { + //Implement RTC timer / latch + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM + { + if (gb_cart->ram != NULL) + { + if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x8 && gb_cart->ram_bank <= 0xC)) + { + /* XXX: implement RTC write */ + } + else + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + } + } +} + +static void read_gb_cart_mbc4(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void write_gb_cart_mbc4(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + size_t offset; + + if ((address < 0x4000)) //Rom Bank 0 + { + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0x4000) && (address < 0x8000)) //Switchable ROM BANK + { + offset = (address - 0x4000) + (gb_cart->rom_bank * 0x4000); + if (offset < gb_cart->rom_size) + { + memcpy(data, &gb_cart->rom[offset], 0x20); + } + } + else if ((address >= 0xA000) && (address <= 0xC000)) //Upper bounds of memory map + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + } +} + +static void write_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + size_t offset; + + if ((address >= 0x0000) && (address <= 0x1FFF)) // We shouldn't be able to read/write to RAM unless this is toggled on + { + //Enable / Disable RAM -- NOT WORKING -- CHECK ME + gb_cart->ram_enabled = (data[0] & 0x0F) == 0x0A; + } + else if ((address >= 0x2000) && (address <= 0x2FFF)) // ROM bank select, low bits + { + gb_cart->rom_bank &= 0xff00; + gb_cart->rom_bank |= data[0]; + } + else if ((address >= 0x3000) && (address <= 0x3FFF)) // ROM bank select, high bit + { + gb_cart->rom_bank &= 0x00ff; + gb_cart->rom_bank |= (data[0] & 0x01) << 8; + } + else if ((address >= 0x4000) && (address <= 0x5FFF)) // RAM bank select + { + if (gb_cart->ram != NULL) + { + gb_cart->ram_bank = data[0] & 0x0f; + } + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM + { + if (gb_cart->ram != NULL) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + } + +} + +static void read_gb_cart_mmm01(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void write_gb_cart_mmm01(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void read_gb_cart_pocket_cam(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + size_t offset; + + if ((address < 0x4000)) //Rom Bank 0 + { + memcpy(data, &gb_cart->rom[address], 0x20); + } + else if ((address >= 0x4000) && (address < 0x8000)) //Switchable ROM BANK + { + offset = (address - 0x4000) + (gb_cart->rom_bank * 0x4000); + if (offset < gb_cart->rom_size) + { + memcpy(data, &gb_cart->rom[offset], 0x20); + } + } + else if ((address >= 0xA000) && (address <= 0xC000)) //Upper bounds of memory map + { + //Check to see if where currently in register mode + if (gb_cart->ram != NULL) + { + if (gb_cart->ram_bank & 0x10) + { + //Where in register mode, based off NRAGE we just fill the memory with Zeroes. + //Seems to be incorrect behaviour but need to find more doccumentation + memset(data, 0x00, 0x20); + } + else + { + //Read RAM normally + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + } + } +} + +static void write_gb_cart_pocket_cam(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + size_t offset; + + if ((address >= 0x0000) && (address <= 0x1FFF)) // We shouldn't be able to read/write to RAM unless this is toggled on + { + //Enable / Disable RAM + gb_cart->ram_enabled = (data[0] & 0x0F) == 0x0A; + } + else if ((address >= 0x2000) && (address <= 0x2FFF)) // ROM bank select, low bits + { + gb_cart->rom_bank &= 0xFF00; + gb_cart->rom_bank |= data[0]; + } + else if ((address >= 0x4000) && (address <= 0x4FFF)) // Camera Register & RAM bank select + { + if (gb_cart->ram != NULL) + { + if (data[0] & 0x10) + { + //REGISTER MODE + gb_cart->ram_bank = data[0]; + } + else + { + //RAM MODE + gb_cart->ram_bank = data[0] & 0x0F; + } + } + } + else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM + { + if (gb_cart->ram != NULL) + { + if (gb_cart->ram_bank & 0x10) + { + //REGISTER MODE (DO NOTHING) + } + else + { + //RAM MODE + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + } + } +} + +static void read_gb_cart_bandai_tama5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void write_gb_cart_bandai_tama5(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void read_gb_cart_huc1(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void write_gb_cart_huc1(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void read_gb_cart_huc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +static void write_gb_cart_huc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + g_Notify->BreakPoint(__FILE__, __LINE__); +} + +enum gbcart_extra_devices +{ + GED_NONE = 0x00, + GED_RAM = 0x01, + GED_BATTERY = 0x02, + GED_RTC = 0x04, + GED_RUMBLE = 0x08 +}; + +struct parsed_cart_type +{ + void(*read_gb_cart)(struct gb_cart*, uint16_t, uint8_t*); + void(*write_gb_cart)(struct gb_cart*, uint16_t, const uint8_t*); + unsigned int extra_devices; +}; + +static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) +{ +#define MBC(x) read_gb_cart_ ## x, write_gb_cart_ ## x + static const struct parsed_cart_type GB_CART_TYPES[] = + { + { MBC(normal), GED_NONE }, + { MBC(mbc1), GED_NONE }, + { MBC(mbc1), GED_RAM }, + { MBC(mbc1), GED_RAM | GED_BATTERY }, + { MBC(mbc2), GED_NONE }, + { MBC(mbc2), GED_BATTERY }, + { MBC(normal), GED_RAM }, + { MBC(normal), GED_RAM | GED_BATTERY }, + { MBC(mmm01), GED_NONE }, + { MBC(mmm01), GED_RAM }, + { MBC(mmm01), GED_RAM | GED_BATTERY }, + { MBC(mbc3), GED_BATTERY | GED_RTC }, + { MBC(mbc3), GED_RAM | GED_BATTERY | GED_RTC }, + { MBC(mbc3), GED_NONE }, + { MBC(mbc3), GED_RAM }, + { MBC(mbc3), GED_RAM | GED_BATTERY }, + { MBC(mbc4), GED_NONE }, + { MBC(mbc4), GED_RAM }, + { MBC(mbc4), GED_RAM | GED_BATTERY }, + { MBC(mbc5), GED_NONE }, + { MBC(mbc5), GED_RAM }, + { MBC(mbc5), GED_RAM | GED_BATTERY }, + { MBC(mbc5), GED_RUMBLE }, + { MBC(mbc5), GED_RAM | GED_RUMBLE }, + { MBC(mbc5), GED_RAM | GED_BATTERY | GED_RUMBLE }, + { MBC(pocket_cam), GED_NONE }, + { MBC(bandai_tama5), GED_NONE }, + { MBC(huc3), GED_NONE }, + { MBC(huc1), GED_RAM | GED_BATTERY } + }; +#undef MBC + + + switch (cart_type) + { + case 0x00: return &GB_CART_TYPES[0]; + case 0x01: return &GB_CART_TYPES[1]; + case 0x02: return &GB_CART_TYPES[2]; + case 0x03: return &GB_CART_TYPES[3]; + case 0x05: return &GB_CART_TYPES[4]; + case 0x06: return &GB_CART_TYPES[5]; + case 0x08: return &GB_CART_TYPES[6]; + case 0x09: return &GB_CART_TYPES[7]; + case 0x0b: return &GB_CART_TYPES[8]; + case 0x0c: return &GB_CART_TYPES[9]; + case 0x0d: return &GB_CART_TYPES[10]; + case 0x0f: return &GB_CART_TYPES[11]; + case 0x10: return &GB_CART_TYPES[12]; + case 0x11: return &GB_CART_TYPES[13]; + case 0x12: return &GB_CART_TYPES[14]; + case 0x13: return &GB_CART_TYPES[15]; + case 0x15: return &GB_CART_TYPES[16]; + case 0x16: return &GB_CART_TYPES[17]; + case 0x17: return &GB_CART_TYPES[18]; + case 0x19: return &GB_CART_TYPES[19]; + case 0x1a: return &GB_CART_TYPES[20]; + case 0x1b: return &GB_CART_TYPES[21]; + case 0x1c: return &GB_CART_TYPES[22]; + case 0x1d: return &GB_CART_TYPES[23]; + case 0x1e: return &GB_CART_TYPES[24]; + case 0xfc: return &GB_CART_TYPES[25]; + case 0xfd: return &GB_CART_TYPES[26]; + case 0xfe: return &GB_CART_TYPES[27]; + case 0xff: return &GB_CART_TYPES[28]; + default: return NULL; + } +} + + +int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) +{ + int err; + const struct parsed_cart_type* type; + uint8_t* rom = NULL; + size_t rom_size = 0; + uint8_t* ram = NULL; + size_t ram_size = 0; + + /* load GB cart ROM */ + err = load_file(gb_file, (void**)&rom, &rom_size); + if (err == 0) + { + return err; + } + + if (rom_size < 0x8000) + { + err = 0; + goto free_rom; + } + + /* get and parse cart type */ + uint8_t cart_type = rom[0x147]; + type = parse_cart_type(cart_type); + if (type == NULL) + { + err = 0; + goto free_rom; + } + + /* load ram (if present) */ + if (type->extra_devices & GED_RAM) + { + ram_size = 0; + switch (rom[0x149]) + { + case 0x01: ram_size = 1 * 0x800; break; + case 0x02: ram_size = 4 * 0x800; break; + case 0x03: ram_size = 16 * 0x800; break; + case 0x04: ram_size = 64 * 0x800; break; + case 0x05: ram_size = 32 * 0x800; break; + } + + if (ram_size != 0) + { + ram = (uint8_t*)malloc(ram_size); + if (ram == NULL) + { + err = 0; + goto free_rom; + } + + read_from_file("C:/Users/death/Desktop/pkmgb.sav", ram, ram_size); + } + } + + /* update gb_cart */ + gb_cart->ram = ram; + gb_cart->rom = rom; + gb_cart->rom_size = rom_size; + gb_cart->ram_size = ram_size; + gb_cart->rom_bank = 1; + gb_cart->ram_bank = 0; + gb_cart->has_rtc = (type->extra_devices & GED_RTC) ? 1 : 0; + gb_cart->read_gb_cart = type->read_gb_cart; + gb_cart->write_gb_cart = type->write_gb_cart; + return 1; + +free_rom: + free(rom); + return err; +} + +void GBCart::release_gb_cart(struct gb_cart* gb_cart) +{ + if (gb_cart->rom != NULL) + free(gb_cart->rom); + + if (gb_cart->ram != NULL) + free(gb_cart->ram); + + memset(gb_cart, 0, sizeof(*gb_cart)); +} + + +void GBCart::read_gb_cart(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) +{ + gb_cart->read_gb_cart(gb_cart, address, data); +} + +void GBCart::write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data) +{ + gb_cart->write_gb_cart(gb_cart, address, data); +} diff --git a/Source/Project64-core/N64System/Mips/GBCart.h b/Source/Project64-core/N64System/Mips/GBCart.h new file mode 100644 index 000000000..7d712fa15 --- /dev/null +++ b/Source/Project64-core/N64System/Mips/GBCart.h @@ -0,0 +1,46 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#pragma once + +#include +#include + +struct gb_cart +{ + uint8_t* rom; + uint8_t* ram; + + size_t rom_size; + size_t ram_size; + + unsigned int rom_bank; + unsigned int ram_bank; + + bool has_rtc; + bool ram_bank_mode; + bool ram_enabled; + + void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); + void(*write_gb_cart)(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data); +}; + +class GBCart +{ +public: + static int init_gb_cart(struct gb_cart* gb_cart, const char* gb_file); + static void release_gb_cart(struct gb_cart* gb_cart); + + static void read_gb_cart(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); + static void write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data); +}; + + + diff --git a/Source/Project64-core/N64System/Mips/PifRam.cpp b/Source/Project64-core/N64System/Mips/PifRam.cpp index 4257f0935..a44b07752 100644 --- a/Source/Project64-core/N64System/Mips/PifRam.cpp +++ b/Source/Project64-core/N64System/Mips/PifRam.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -526,7 +527,7 @@ void CPifRam::ProcessControllerCommand(int32_t Control, uint8_t * Command) { case PLUGIN_RUMBLE_PAK: Rumblepak::ReadFrom(address, data); break; case PLUGIN_MEMPAK: Mempak::ReadFrom(Control, address, data); break; - case PLUGIN_TANSFER_PAK: /* TODO */; break; + case PLUGIN_TANSFER_PAK: Transferpak::ReadFrom(address, data); break; case PLUGIN_RAW: if (g_Plugins->Control()->ControllerCommand) { g_Plugins->Control()->ControllerCommand(Control, Command); } break; default: memset(&Command[5], 0, 0x20); @@ -534,7 +535,7 @@ void CPifRam::ProcessControllerCommand(int32_t Control, uint8_t * Command) if (Controllers[Control].Plugin != PLUGIN_RAW) { - Command[0x25] = Mempak::CalculateCrc(&Command[5]); + Command[0x25] = Mempak::CalculateCrc(data); } } else @@ -567,13 +568,13 @@ void CPifRam::ProcessControllerCommand(int32_t Control, uint8_t * Command) { case PLUGIN_MEMPAK: Mempak::WriteTo(Control, address, data); break; case PLUGIN_RUMBLE_PAK: Rumblepak::WriteTo(Control, address, data); break; - case PLUGIN_TANSFER_PAK: /* TODO */; break; + case PLUGIN_TANSFER_PAK: Transferpak::WriteTo(address, data); break; case PLUGIN_RAW: if (g_Plugins->Control()->ControllerCommand) { g_Plugins->Control()->ControllerCommand(Control, Command); } break; } if (Controllers[Control].Plugin != PLUGIN_RAW) { - Command[0x25] = Mempak::CalculateCrc(&Command[5]); + Command[0x25] = Mempak::CalculateCrc(data); } } else diff --git a/Source/Project64-core/N64System/Mips/Transferpak.h b/Source/Project64-core/N64System/Mips/Transferpak.h new file mode 100644 index 000000000..de5980764 --- /dev/null +++ b/Source/Project64-core/N64System/Mips/Transferpak.h @@ -0,0 +1,37 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#pragma once +#include "GBCart.h" +enum cart_access_mode +{ + CART_NOT_INSERTED = 0x40, + CART_ACCESS_MODE_0 = 0x80, + CART_ACCESS_MODE_1 = 0x89 +}; + +struct transferpak +{ + unsigned int enabled; + unsigned int bank; + unsigned int access_mode; + unsigned int access_mode_changed; + struct gb_cart gb_cart; +}; + +class Transferpak +{ +public: + + static void Release(); + static void Init(); + static void ReadFrom(uint16_t address, uint8_t * command); + static void WriteTo(uint16_t address, uint8_t * command); +}; diff --git a/Source/Project64-core/N64System/Mips/Trasferpak.cpp b/Source/Project64-core/N64System/Mips/Trasferpak.cpp new file mode 100644 index 000000000..3126249bd --- /dev/null +++ b/Source/Project64-core/N64System/Mips/Trasferpak.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include "stdafx.h" +#include "GBCart.h" +#include "Transferpak.h" + +static transferpak tpak; + +uint16_t gb_cart_address(unsigned int bank, uint16_t address) +{ + return (address & 0x3FFF) | ((bank & 0x3) * 0x4000); +} + +void Transferpak::Init() +{ + memset(&tpak, 0, sizeof(tpak)); + tpak.access_mode = (GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pkmgb.gb") == 0) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; + + tpak.access_mode_changed = 0x44; +} + +void Transferpak::Release() +{ + GBCart::release_gb_cart(&tpak.gb_cart); +} + +void Transferpak::ReadFrom(uint16_t address, uint8_t * data) +{ + if ((address >= 0x8000) && (address <= 0x8FFF)) + { + //Get whether the GB cart is enabled or disabled + uint8_t value = (tpak.enabled) ? 0x84 : 0x00; + + memset(data, value, 0x20); + } + else if ((address >= 0xB000) && (address <= 0xBFFF)) + { + // Get the GB Cart access mode + if (tpak.enabled) + { + memset(data, tpak.access_mode, 0x20); + if (tpak.access_mode != CART_NOT_INSERTED) + { + data[0] |= tpak.access_mode_changed; + } + + tpak.access_mode_changed = 0; + } + } + else if (address >= 0xC000) + { + // Read the GB Cart + if (tpak.enabled) + { + GBCart::read_gb_cart(&tpak.gb_cart, gb_cart_address(tpak.bank, address), data); + } + } + +} + +void Transferpak::WriteTo(uint16_t address, uint8_t * data) +{ + if ((address >= 0x8000) && (address <= 0x8FFF)) + { + //Set whether the gb cart is enabled or disabled. + switch (*data) + { + case 0xFE: + tpak.enabled = false; + break; + case 0x84: + tpak.enabled = true; + break; + default: + //Do nothing + break; + } + } + else if ((address >= 0xA000) && (address <= 0xAFFF)) + { + //Set the bank for the GB Cart + if (tpak.enabled) + { + tpak.bank = *data; + } + } + else if ((address >= 0xB000) && (address <= 0xBFFF)) + { + // Get the GB Cart access mode + if (tpak.enabled) + { + tpak.access_mode_changed = 0x04; + + tpak.access_mode = ((*data & 1) == 0) ? CART_ACCESS_MODE_0 : CART_ACCESS_MODE_1; + + if ((*data & 0xFE) != 0) + { + //Unkown tpak write + } + } + } + else if (address >= 0xC000) + { + // Write the GB Cart + if (tpak.enabled) + { + GBCart::write_gb_cart(&tpak.gb_cart, gb_cart_address(tpak.bank, address), data); + //Write the GB CART + } + } +} \ No newline at end of file diff --git a/Source/Project64-core/N64System/N64Class.cpp b/Source/Project64-core/N64System/N64Class.cpp index 9b49a8fb2..15068ded6 100644 --- a/Source/Project64-core/N64System/N64Class.cpp +++ b/Source/Project64-core/N64System/N64Class.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -66,11 +67,13 @@ m_CheatsSlectionChanged(false) g_Settings->SaveDword(GameRunning_ScreenHertz, gameHertz); m_Cheats.LoadCheats(!g_Settings->LoadDword(Setting_RememberCheats), Plugins); Mempak::Load(); + Transferpak::Init(); } CN64System::~CN64System() { SetActiveSystem(false); + Transferpak::Release(); if (m_SyncCPU) { m_SyncCPU->CpuStopped(); diff --git a/Source/Project64-core/Project64-core.vcxproj b/Source/Project64-core/Project64-core.vcxproj index 3c5e643be..187e7a50a 100644 --- a/Source/Project64-core/Project64-core.vcxproj +++ b/Source/Project64-core/Project64-core.vcxproj @@ -50,6 +50,7 @@ + @@ -60,6 +61,7 @@ + @@ -135,6 +137,7 @@ + @@ -147,6 +150,7 @@ + diff --git a/Source/Project64-core/Project64-core.vcxproj.filters b/Source/Project64-core/Project64-core.vcxproj.filters index 207c34c9a..e74a13a60 100644 --- a/Source/Project64-core/Project64-core.vcxproj.filters +++ b/Source/Project64-core/Project64-core.vcxproj.filters @@ -300,6 +300,12 @@ Source Files\N64 System + + Source Files\N64 System\Mips + + + Source Files\N64 System\Mips + @@ -584,5 +590,11 @@ Header Files\N64 System + + Header Files\N64 System\Mips + + + Header Files\N64 System\Mips + \ No newline at end of file From 74d38258704e5768f71b755d6a7b2e089900452e Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Sun, 31 Jan 2016 01:52:26 +1100 Subject: [PATCH 02/10] Basic implementation of the RTC for the Transferpak. Unable to properly test this due to Project64 not being able to emulate the co-processor - http://www.emutalk.net/threads/54598-Pok%C3%A9mon-Stadium-%28Pocket-Monster-Stadium%29-requires-RSP-emulation @project64 @LuigiBlood @LegendOfDragoon --- .../Project64-core/N64System/Mips/GBCart.cpp | 154 +++++++++++++++--- Source/Project64-core/N64System/Mips/GBCart.h | 28 ++++ .../N64System/Mips/Trasferpak.cpp | 5 +- Source/nragev20/GBCart.cpp | 11 -- 4 files changed, 158 insertions(+), 40 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index 025d5eedb..ca9a42c42 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -11,6 +11,7 @@ #include "stdafx.h" #include "GBCart.h" +#include #include //-------------------------------------------------------------------------------------- @@ -332,10 +333,6 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t { memcpy(data, &gb_cart->rom[offset], 0x20); } - else - { - memset(data, 0x00, 0x20); - } } else if ((address >= 0xA000) && (address <= 0xC000)) //Upper Bounds of memory map { @@ -343,8 +340,24 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t { if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x08 && gb_cart->ram_bank <= 0x0c)) { - /* XXX: implement RTC read */ - memset(data, 0, 0x20); + switch (gb_cart->ram_bank) + { + case 0x08: + data[0] = gb_cart->rtc_latch_second; + break; + case 0x09: + data[0] = gb_cart->rtc_latch_minute; + break; + case 0x0A: + data[0] = gb_cart->rtc_latch_hour; + break; + case 0x0B: + data[0] = gb_cart->rtc_latch_day; + break; + case 0x0C: + data[0] = (gb_cart->rtc_latch_day_carry << 7) | (gb_cart->rtc_latch_day >> 8); + break; + } } else { @@ -370,7 +383,7 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const } else if ((address >= 0x2000) && (address <= 0x3FFF)) // ROM bank select { - bank = data[0] & 0x7f; + bank = data[0] & 0x7F; gb_cart->rom_bank = (bank == 0) ? 1 : bank; } else if ((address >= 0x4000) && (address <= 0x5FFF)) // RAM/Clock bank select @@ -392,6 +405,16 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const else if ((address >= 0x6000) && (address <= 0x7FFF)) // Latch timer data { //Implement RTC timer / latch + if (gb_cart->rtc_latch == 0 && data[0] == 1) + { + correctRTC(gb_cart); + gb_cart->rtc_latch_second = gb_cart->rtc_second; + gb_cart->rtc_latch_minute = gb_cart->rtc_minute; + gb_cart->rtc_latch_hour = gb_cart->rtc_hour; + gb_cart->rtc_latch_day = gb_cart->rtc_day; + gb_cart->rtc_latch_day_carry = gb_cart->rtc_day_carry; + } + gb_cart->rtc_latch = data[0]; } else if ((address >= 0xA000) && (address <= 0xBFFF)) // Write to RAM { @@ -399,7 +422,34 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const { if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x8 && gb_cart->ram_bank <= 0xC)) { - /* XXX: implement RTC write */ + bank = data[0]; + + /* RTC write */ + switch (gb_cart->ram_bank) + { + case 0x08: + if (bank >= 60) + bank = 0; + gb_cart->rtc_second = bank; + break; + case 0x09: + if (bank >= 60) + bank = 0; + gb_cart->rtc_minute = bank; + break; + case 0x0A: + if (bank >= 24) + bank = 0; + gb_cart->rtc_hour = bank; + break; + case 0x0B: + gb_cart->rtc_day = (gb_cart->rtc_day & 0x0100) | bank; + break; + case 0x0C: + gb_cart->rtc_day = ((bank & 1) << 8) | (gb_cart->rtc_day & 0xFF); + gb_cart->rtc_day_carry = bank & 0x80; + break; + } } else { @@ -425,8 +475,6 @@ static void write_gb_cart_mbc4(struct gb_cart* gb_cart, uint16_t address, const static void read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) { - size_t offset; - if ((address < 0x4000)) //Rom Bank 0 { memcpy(data, &gb_cart->rom[address], 0x20); @@ -687,10 +735,10 @@ static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) case 0x06: return &GB_CART_TYPES[5]; case 0x08: return &GB_CART_TYPES[6]; case 0x09: return &GB_CART_TYPES[7]; - case 0x0b: return &GB_CART_TYPES[8]; - case 0x0c: return &GB_CART_TYPES[9]; - case 0x0d: return &GB_CART_TYPES[10]; - case 0x0f: return &GB_CART_TYPES[11]; + case 0x0B: return &GB_CART_TYPES[8]; + case 0x0C: return &GB_CART_TYPES[9]; + case 0x0D: return &GB_CART_TYPES[10]; + case 0x0F: return &GB_CART_TYPES[11]; case 0x10: return &GB_CART_TYPES[12]; case 0x11: return &GB_CART_TYPES[13]; case 0x12: return &GB_CART_TYPES[14]; @@ -699,19 +747,52 @@ static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) case 0x16: return &GB_CART_TYPES[17]; case 0x17: return &GB_CART_TYPES[18]; case 0x19: return &GB_CART_TYPES[19]; - case 0x1a: return &GB_CART_TYPES[20]; - case 0x1b: return &GB_CART_TYPES[21]; - case 0x1c: return &GB_CART_TYPES[22]; - case 0x1d: return &GB_CART_TYPES[23]; - case 0x1e: return &GB_CART_TYPES[24]; - case 0xfc: return &GB_CART_TYPES[25]; - case 0xfd: return &GB_CART_TYPES[26]; - case 0xfe: return &GB_CART_TYPES[27]; - case 0xff: return &GB_CART_TYPES[28]; + case 0x1A: return &GB_CART_TYPES[20]; + case 0x1B: return &GB_CART_TYPES[21]; + case 0x1C: return &GB_CART_TYPES[22]; + case 0x1D: return &GB_CART_TYPES[23]; + case 0x1E: return &GB_CART_TYPES[24]; + case 0xFC: return &GB_CART_TYPES[25]; + case 0xFD: return &GB_CART_TYPES[26]; + case 0xFE: return &GB_CART_TYPES[27]; + case 0xFF: return &GB_CART_TYPES[28]; default: return NULL; } } +void correctRTC(struct gb_cart* gb_cart) +{ + time_t now, dif; + int days; + + now = time(NULL); + dif = now - gb_cart->rtc_last_time; + + gb_cart->rtc_second += (BYTE)(dif % 60); + dif /= 60; + gb_cart->rtc_minute += (BYTE)(dif % 60); + dif /= 60; + gb_cart->rtc_hour += (BYTE)(dif % 24); + dif /= 24; + + days = (int)(gb_cart->rtc_day + ((gb_cart->rtc_day_carry & 1) << 8) + dif); + gb_cart->rtc_day = (days & 0xFF); + + if (days > 255) + { + if (days > 511) + { + days &= 511; + gb_cart->rtc_day_carry |= 0x80; + } + if (days > 255) + { + gb_cart->rtc_day_carry = (gb_cart->rtc_day_carry & 0xFE) | (days > 255 ? 1 : 0); + } + } + + gb_cart->rtc_last_time = now; +} int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) { @@ -750,8 +831,8 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) ram_size = 0; switch (rom[0x149]) { - case 0x01: ram_size = 1 * 0x800; break; - case 0x02: ram_size = 4 * 0x800; break; + case 0x01: ram_size = 1 * 0x800; break; + case 0x02: ram_size = 4 * 0x800; break; case 0x03: ram_size = 16 * 0x800; break; case 0x04: ram_size = 64 * 0x800; break; case 0x05: ram_size = 32 * 0x800; break; @@ -766,8 +847,29 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) goto free_rom; } - read_from_file("C:/Users/death/Desktop/pkmgb.sav", ram, ram_size); + read_from_file("C:/Users/death/Desktop/pokemonsilver.sav", ram, ram_size + ((type->extra_devices & GED_RTC ) ? 0x30 : 0x00)); } + + //If we have RTC we need to load in the data, we assume the save will use the VBA-M format + if (type->extra_devices & GED_RTC) + { + gbCartRTC rtc; + memcpy(&rtc, &ram[ram_size], 0x30); + + gb_cart->rtc_second = rtc.second; + gb_cart->rtc_minute = rtc.minute; + gb_cart->rtc_hour = rtc.hour; + gb_cart->rtc_day = rtc.day; + gb_cart->rtc_day_carry = rtc.day_carry; + gb_cart->rtc_latch_second = rtc.latch_second; + gb_cart->rtc_latch_minute = rtc.latch_minute; + gb_cart->rtc_latch_hour = rtc.latch_hour; + gb_cart->rtc_latch_day = rtc.latch_day; + gb_cart->rtc_latch_day_carry = rtc.latch_day_carry; + gb_cart->rtc_last_time = rtc.mapperLastTime; + + correctRTC(gb_cart); + } } /* update gb_cart */ diff --git a/Source/Project64-core/N64System/Mips/GBCart.h b/Source/Project64-core/N64System/Mips/GBCart.h index 7d712fa15..371b4e4b2 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.h +++ b/Source/Project64-core/N64System/Mips/GBCart.h @@ -28,10 +28,38 @@ struct gb_cart bool ram_bank_mode; bool ram_enabled; + uint32_t rtc_latch; + + uint32_t rtc_second; + uint32_t rtc_minute; + uint32_t rtc_hour; + uint32_t rtc_day; + uint32_t rtc_day_carry; + uint32_t rtc_latch_second; + uint32_t rtc_latch_minute; + uint32_t rtc_latch_hour; + uint32_t rtc_latch_day; + uint32_t rtc_latch_day_carry; + time_t rtc_last_time; + void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); void(*write_gb_cart)(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data); }; +struct gbCartRTC { + uint32_t second; + uint32_t minute; + uint32_t hour; + uint32_t day; + uint32_t day_carry; + uint32_t latch_second; + uint32_t latch_minute; + uint32_t latch_hour; + uint32_t latch_day; + uint32_t latch_day_carry; + time_t mapperLastTime; +}; + class GBCart { public: diff --git a/Source/Project64-core/N64System/Mips/Trasferpak.cpp b/Source/Project64-core/N64System/Mips/Trasferpak.cpp index 3126249bd..861729493 100644 --- a/Source/Project64-core/N64System/Mips/Trasferpak.cpp +++ b/Source/Project64-core/N64System/Mips/Trasferpak.cpp @@ -22,7 +22,7 @@ uint16_t gb_cart_address(unsigned int bank, uint16_t address) void Transferpak::Init() { memset(&tpak, 0, sizeof(tpak)); - tpak.access_mode = (GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pkmgb.gb") == 0) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; + tpak.access_mode = (GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pokemonsilver.gbc") == 0) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; tpak.access_mode_changed = 0x44; } @@ -109,11 +109,10 @@ void Transferpak::WriteTo(uint16_t address, uint8_t * data) } else if (address >= 0xC000) { - // Write the GB Cart + // Write to the GB Cart if (tpak.enabled) { GBCart::write_gb_cart(&tpak.gb_cart, gb_cart_address(tpak.bank, address), data); - //Write the GB CART } } } \ No newline at end of file diff --git a/Source/nragev20/GBCart.cpp b/Source/nragev20/GBCart.cpp index b16daafc4..84f1e0176 100644 --- a/Source/nragev20/GBCart.cpp +++ b/Source/nragev20/GBCart.cpp @@ -77,17 +77,6 @@ void UpdateRTC(LPGBCART Cart) Cart->timerLastUpdate = now; - DebugWriteA("Update RTC: "); - DebugWriteByteA(Cart->TimerData[0]); - DebugWriteA(":"); - DebugWriteByteA(Cart->TimerData[1]); - DebugWriteA(":"); - DebugWriteByteA(Cart->TimerData[2]); - DebugWriteA(":"); - DebugWriteByteA(Cart->TimerData[3]); - DebugWriteA(":"); - DebugWriteByteA(Cart->TimerData[4]); - DebugWriteA("\n"); } // returns true if the ROM was loaded OK From 258a5a0eb84c440ca55fc432cf4d1dd86ab61f6a Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Mon, 1 Feb 2016 19:58:37 +1100 Subject: [PATCH 03/10] Transferpak: Add support for RAM saving, and RTC saving (Visual Boy Advance format) Remove UpdateRTC() till I can get a better idea if the RTC code works properly. --- .../Project64-core/N64System/Mips/GBCart.cpp | 146 ++++++++---------- Source/Project64-core/N64System/Mips/GBCart.h | 3 +- .../N64System/Mips/Trasferpak.cpp | 3 +- 3 files changed, 71 insertions(+), 81 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index ca9a42c42..dc63da08f 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -38,11 +38,8 @@ bool load_file(const char* filename, void** buffer, size_t* size) FILE* fd; size_t l_size; void* l_buffer; - int err; - bool ret; /* open file */ - ret = false; fd = fopen(filename, "rb"); if (fd == NULL) { @@ -50,51 +47,48 @@ bool load_file(const char* filename, void** buffer, size_t* size) } /* obtain file size */ - ret = false; - err = fseek(fd, 0, SEEK_END); - if (err != 0) + if (fseek(fd, 0, SEEK_END) != 0) { - goto close_file; + fclose(fd); + return false; } - err = ftell(fd); - if (err == -1) + l_size = (size_t)ftell(fd); + if (l_size == -1) { - goto close_file; + fclose(fd); + return false; } - l_size = (size_t)err; - err = fseek(fd, 0, SEEK_SET); - if (err != 0) + if (fseek(fd, 0, SEEK_SET) != 0) { - goto close_file; + fclose(fd); + return false; } /* allocate buffer */ l_buffer = malloc(l_size); if (l_buffer == NULL) { - goto close_file; + fclose(fd); + return false; } /* copy file content to buffer */ - ret = false; - err = fread(l_buffer, 1, l_size, fd); - if (err != l_size) + if (fread(l_buffer, 1, l_size, fd) != l_size) { free(l_buffer); - goto close_file; + fclose(fd); + return false; } /* commit buffer,size */ - ret = true; *buffer = l_buffer; *size = l_size; /* close file */ -close_file: fclose(fd); - return ret; + return true; } //-------------------------------------------------------------------------------------- @@ -407,7 +401,6 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const //Implement RTC timer / latch if (gb_cart->rtc_latch == 0 && data[0] == 1) { - correctRTC(gb_cart); gb_cart->rtc_latch_second = gb_cart->rtc_second; gb_cart->rtc_latch_minute = gb_cart->rtc_minute; gb_cart->rtc_latch_hour = gb_cart->rtc_hour; @@ -475,6 +468,8 @@ static void write_gb_cart_mbc4(struct gb_cart* gb_cart, uint16_t address, const static void read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) { + size_t offset; + if ((address < 0x4000)) //Rom Bank 0 { memcpy(data, &gb_cart->rom[address], 0x20); @@ -760,43 +755,8 @@ static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) } } -void correctRTC(struct gb_cart* gb_cart) +bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) { - time_t now, dif; - int days; - - now = time(NULL); - dif = now - gb_cart->rtc_last_time; - - gb_cart->rtc_second += (BYTE)(dif % 60); - dif /= 60; - gb_cart->rtc_minute += (BYTE)(dif % 60); - dif /= 60; - gb_cart->rtc_hour += (BYTE)(dif % 24); - dif /= 24; - - days = (int)(gb_cart->rtc_day + ((gb_cart->rtc_day_carry & 1) << 8) + dif); - gb_cart->rtc_day = (days & 0xFF); - - if (days > 255) - { - if (days > 511) - { - days &= 511; - gb_cart->rtc_day_carry |= 0x80; - } - if (days > 255) - { - gb_cart->rtc_day_carry = (gb_cart->rtc_day_carry & 0xFE) | (days > 255 ? 1 : 0); - } - } - - gb_cart->rtc_last_time = now; -} - -int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) -{ - int err; const struct parsed_cart_type* type; uint8_t* rom = NULL; size_t rom_size = 0; @@ -804,16 +764,15 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) size_t ram_size = 0; /* load GB cart ROM */ - err = load_file(gb_file, (void**)&rom, &rom_size); - if (err == 0) + if (!load_file(gb_file, (void**)&rom, &rom_size)) { - return err; + return false; } if (rom_size < 0x8000) { - err = 0; - goto free_rom; + free(rom); + return false; } /* get and parse cart type */ @@ -821,8 +780,8 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) type = parse_cart_type(cart_type); if (type == NULL) { - err = 0; - goto free_rom; + free(rom); + return false; } /* load ram (if present) */ @@ -840,21 +799,26 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) if (ram_size != 0) { - ram = (uint8_t*)malloc(ram_size); + if (type->extra_devices & GED_RTC) + { + ram_size += 0x30; + } + + ram = (uint8_t*)malloc(ram_size ); if (ram == NULL) { - err = 0; - goto free_rom; + free(rom); + return false; } - read_from_file("C:/Users/death/Desktop/pokemonsilver.sav", ram, ram_size + ((type->extra_devices & GED_RTC ) ? 0x30 : 0x00)); + read_from_file("C:/Users/death/Desktop/pokemonsilver.sav", ram, ram_size ); } //If we have RTC we need to load in the data, we assume the save will use the VBA-M format if (type->extra_devices & GED_RTC) { gbCartRTC rtc; - memcpy(&rtc, &ram[ram_size], 0x30); + memcpy(&rtc, &ram[ram_size-0x30], 0x30); gb_cart->rtc_second = rtc.second; gb_cart->rtc_minute = rtc.minute; @@ -867,8 +831,6 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) gb_cart->rtc_latch_day = rtc.latch_day; gb_cart->rtc_latch_day_carry = rtc.latch_day_carry; gb_cart->rtc_last_time = rtc.mapperLastTime; - - correctRTC(gb_cart); } } @@ -882,11 +844,37 @@ int GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) gb_cart->has_rtc = (type->extra_devices & GED_RTC) ? 1 : 0; gb_cart->read_gb_cart = type->read_gb_cart; gb_cart->write_gb_cart = type->write_gb_cart; - return 1; + return true; +} -free_rom: - free(rom); - return err; +void GBCart::save_gb_cart(struct gb_cart* gb_cart) +{ + FILE *fRAM = fopen("C:/Users/death/Desktop/pokemonsilver.sav", "wb"); + + if (gb_cart->has_rtc) + { + fwrite(gb_cart->ram, 1, gb_cart->ram_size-0x30, fRAM); + + gbCartRTC rtc; + rtc.second = gb_cart->rtc_second; + rtc.minute = gb_cart->rtc_minute; + rtc.hour = gb_cart->rtc_hour; + rtc.day = gb_cart->rtc_day; + rtc.day_carry = gb_cart->rtc_day_carry; + rtc.latch_second = gb_cart->rtc_latch_second; + rtc.latch_minute = gb_cart->rtc_latch_minute; + rtc.latch_hour = gb_cart->rtc_latch_hour; + rtc.latch_day = gb_cart->rtc_latch_day; + rtc.latch_day_carry = gb_cart->rtc_latch_day_carry; + rtc.mapperLastTime = gb_cart->rtc_last_time; + fwrite(&rtc, 1, 0x30, fRAM); + } + else + { + fwrite(gb_cart->ram, 1, gb_cart->ram_size, fRAM); + } + + fclose(fRAM); } void GBCart::release_gb_cart(struct gb_cart* gb_cart) @@ -894,8 +882,8 @@ void GBCart::release_gb_cart(struct gb_cart* gb_cart) if (gb_cart->rom != NULL) free(gb_cart->rom); - if (gb_cart->ram != NULL) - free(gb_cart->ram); + if (gb_cart->ram != NULL) + free(gb_cart->ram); memset(gb_cart, 0, sizeof(*gb_cart)); } diff --git a/Source/Project64-core/N64System/Mips/GBCart.h b/Source/Project64-core/N64System/Mips/GBCart.h index 371b4e4b2..f74e8a11c 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.h +++ b/Source/Project64-core/N64System/Mips/GBCart.h @@ -63,8 +63,9 @@ struct gbCartRTC { class GBCart { public: - static int init_gb_cart(struct gb_cart* gb_cart, const char* gb_file); + static bool init_gb_cart(struct gb_cart* gb_cart, const char* gb_file); static void release_gb_cart(struct gb_cart* gb_cart); + static void save_gb_cart(struct gb_cart* gb_cart); static void read_gb_cart(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); static void write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data); diff --git a/Source/Project64-core/N64System/Mips/Trasferpak.cpp b/Source/Project64-core/N64System/Mips/Trasferpak.cpp index 861729493..a0c28c1a0 100644 --- a/Source/Project64-core/N64System/Mips/Trasferpak.cpp +++ b/Source/Project64-core/N64System/Mips/Trasferpak.cpp @@ -22,7 +22,7 @@ uint16_t gb_cart_address(unsigned int bank, uint16_t address) void Transferpak::Init() { memset(&tpak, 0, sizeof(tpak)); - tpak.access_mode = (GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pokemonsilver.gbc") == 0) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; + tpak.access_mode = (!GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pokemonsilver.gbc")) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; tpak.access_mode_changed = 0x44; } @@ -113,6 +113,7 @@ void Transferpak::WriteTo(uint16_t address, uint8_t * data) if (tpak.enabled) { GBCart::write_gb_cart(&tpak.gb_cart, gb_cart_address(tpak.bank, address), data); + GBCart::save_gb_cart(&tpak.gb_cart); } } } \ No newline at end of file From 1ddeb52f7f8b788c17dbfb59590ffb2da3d9a496 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Mon, 1 Feb 2016 23:41:46 +1100 Subject: [PATCH 04/10] Allow transferpaks to be set through the RDB. Still need to implement the actual settings in the GUI --- Source/Project64-core/N64System/Mips/GBCart.cpp | 6 +++--- Source/Project64-core/N64System/Mips/Trasferpak.cpp | 3 ++- Source/Project64-core/Settings/Settings.h | 2 ++ Source/Project64-core/Settings/SettingsClass.cpp | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index dc63da08f..7a54d66df 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -811,7 +811,7 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) return false; } - read_from_file("C:/Users/death/Desktop/pokemonsilver.sav", ram, ram_size ); + read_from_file(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), ram, ram_size ); } //If we have RTC we need to load in the data, we assume the save will use the VBA-M format @@ -849,8 +849,8 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) void GBCart::save_gb_cart(struct gb_cart* gb_cart) { - FILE *fRAM = fopen("C:/Users/death/Desktop/pokemonsilver.sav", "wb"); - + FILE *fRAM = fopen(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), "wb"); + if (gb_cart->has_rtc) { fwrite(gb_cart->ram, 1, gb_cart->ram_size-0x30, fRAM); diff --git a/Source/Project64-core/N64System/Mips/Trasferpak.cpp b/Source/Project64-core/N64System/Mips/Trasferpak.cpp index a0c28c1a0..29c90f3ff 100644 --- a/Source/Project64-core/N64System/Mips/Trasferpak.cpp +++ b/Source/Project64-core/N64System/Mips/Trasferpak.cpp @@ -21,8 +21,9 @@ uint16_t gb_cart_address(unsigned int bank, uint16_t address) void Transferpak::Init() { + memset(&tpak, 0, sizeof(tpak)); - tpak.access_mode = (!GBCart::init_gb_cart(&tpak.gb_cart, "C:/Users/death/Desktop/pokemonsilver.gbc")) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; + tpak.access_mode = (!GBCart::init_gb_cart(&tpak.gb_cart, g_Settings->LoadStringVal(Game_Transferpak_ROM).c_str())) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; tpak.access_mode_changed = 0x44; } diff --git a/Source/Project64-core/Settings/Settings.h b/Source/Project64-core/Settings/Settings.h index 43eb12bd4..eadbf603e 100644 --- a/Source/Project64-core/Settings/Settings.h +++ b/Source/Project64-core/Settings/Settings.h @@ -157,6 +157,8 @@ enum SettingID Game_AudioResetOnLoad, Game_AllowROMWrites, Game_CRC_Recalc, + Game_Transferpak_ROM, + Game_Transferpak_Sav, // General Game running info GameRunning_LoadingInProgress, diff --git a/Source/Project64-core/Settings/SettingsClass.cpp b/Source/Project64-core/Settings/SettingsClass.cpp index f34a1f68a..84bce4369 100644 --- a/Source/Project64-core/Settings/SettingsClass.cpp +++ b/Source/Project64-core/Settings/SettingsClass.cpp @@ -224,6 +224,8 @@ void CSettings::AddHowToHandleSetting(const char * BaseDirectory) AddHandler(Game_AudioResetOnLoad, new CSettingTypeGame("AudioResetOnLoad", Rdb_AudioResetOnLoad)); AddHandler(Game_AllowROMWrites, new CSettingTypeGame("AllowROMWrites", Rdb_AllowROMWrites)); AddHandler(Game_CRC_Recalc, new CSettingTypeGame("CRC-Recalc", Rdb_CRC_Recalc)); + AddHandler(Game_Transferpak_ROM, new CSettingTypeGame("Tpak-ROM-dir", Default_None)); + AddHandler(Game_Transferpak_Sav, new CSettingTypeGame("Tpak-Sav-dir", Default_None)); //User Interface AddHandler(UserInterface_BasicMode, new CSettingTypeApplication("", "Basic Mode", (uint32_t)true)); From aab625734d39a40a0f0ad13837b9bb47f820d7cc Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Tue, 2 Feb 2016 15:09:47 +1100 Subject: [PATCH 05/10] Fix up spelling mistake in Tansferpak.cpp naming, --- .../N64System/Mips/{Trasferpak.cpp => Transferpak.cpp} | 0 Source/Project64-core/Project64-core.vcxproj | 2 +- Source/Project64-core/Project64-core.vcxproj.filters | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename Source/Project64-core/N64System/Mips/{Trasferpak.cpp => Transferpak.cpp} (100%) diff --git a/Source/Project64-core/N64System/Mips/Trasferpak.cpp b/Source/Project64-core/N64System/Mips/Transferpak.cpp similarity index 100% rename from Source/Project64-core/N64System/Mips/Trasferpak.cpp rename to Source/Project64-core/N64System/Mips/Transferpak.cpp diff --git a/Source/Project64-core/Project64-core.vcxproj b/Source/Project64-core/Project64-core.vcxproj index 187e7a50a..d1aa124d9 100644 --- a/Source/Project64-core/Project64-core.vcxproj +++ b/Source/Project64-core/Project64-core.vcxproj @@ -61,7 +61,7 @@ - + diff --git a/Source/Project64-core/Project64-core.vcxproj.filters b/Source/Project64-core/Project64-core.vcxproj.filters index e74a13a60..3542ebd90 100644 --- a/Source/Project64-core/Project64-core.vcxproj.filters +++ b/Source/Project64-core/Project64-core.vcxproj.filters @@ -303,7 +303,7 @@ Source Files\N64 System\Mips - + Source Files\N64 System\Mips From 696d419e5b2feaf559f4918b9b3c3401983b2662 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Tue, 2 Feb 2016 19:44:18 +1100 Subject: [PATCH 06/10] Improve behaviour of MBC3 if statements. --- .../Project64-core/N64System/Mips/GBCart.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index 7a54d66df..6cc377fa5 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -332,7 +332,15 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t { if (gb_cart->ram != NULL) { - if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x08 && gb_cart->ram_bank <= 0x0c)) + if (gb_cart->ram_bank >= 0x00 && gb_cart->ram_bank <= 0x03) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(data, &gb_cart->ram[offset], 0x20); + } + } + else if (gb_cart->has_rtc) { switch (gb_cart->ram_bank) { @@ -353,14 +361,6 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t break; } } - else - { - offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); - if (offset < gb_cart->ram_size) - { - memcpy(data, &gb_cart->ram[offset], 0x20); - } - } } } } @@ -413,7 +413,15 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const { if (gb_cart->ram != NULL) { - if (gb_cart->has_rtc && (gb_cart->ram_bank >= 0x8 && gb_cart->ram_bank <= 0xC)) + if (gb_cart->ram_bank >= 0x00 && gb_cart->ram_bank <= 0x03) + { + offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); + if (offset < gb_cart->ram_size) + { + memcpy(&gb_cart->ram[offset], data, 0x20); + } + } + else if (gb_cart->has_rtc) { bank = data[0]; @@ -444,14 +452,6 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const break; } } - else - { - offset = (address - 0xA000) + (gb_cart->ram_bank * 0x2000); - if (offset < gb_cart->ram_size) - { - memcpy(&gb_cart->ram[offset], data, 0x20); - } - } } } } From 26d4bea1f1d5d543df0fe0cfda6b89a51560f867 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Wed, 3 Feb 2016 13:34:52 +1100 Subject: [PATCH 07/10] Switch to using an auto_ptr for our buffers, and switch fopen/fwrites. to make use of the CFile class. --- .../Project64-core/N64System/Mips/GBCart.cpp | 144 +++++------------- 1 file changed, 38 insertions(+), 106 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index 6cc377fa5..be23afcab 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -11,87 +11,6 @@ #include "stdafx.h" #include "GBCart.h" -#include -#include - -//-------------------------------------------------------------------------------------- -bool read_from_file(const char *filename, void *data, size_t size) -{ - FILE *f = fopen(filename, "rb"); - if (f == NULL) - { - return false; - } - - if (fread(data, 1, size, f) != size) - { - fclose(f); - return false; - } - - fclose(f); - return true; -} - -bool load_file(const char* filename, void** buffer, size_t* size) -{ - FILE* fd; - size_t l_size; - void* l_buffer; - - /* open file */ - fd = fopen(filename, "rb"); - if (fd == NULL) - { - return false; - } - - /* obtain file size */ - if (fseek(fd, 0, SEEK_END) != 0) - { - fclose(fd); - return false; - } - - l_size = (size_t)ftell(fd); - if (l_size == -1) - { - fclose(fd); - return false; - } - - if (fseek(fd, 0, SEEK_SET) != 0) - { - fclose(fd); - return false; - } - - /* allocate buffer */ - l_buffer = malloc(l_size); - if (l_buffer == NULL) - { - fclose(fd); - return false; - } - - /* copy file content to buffer */ - if (fread(l_buffer, 1, l_size, fd) != l_size) - { - free(l_buffer); - fclose(fd); - return false; - } - - /* commit buffer,size */ - *buffer = l_buffer; - *size = l_size; - - /* close file */ - fclose(fd); - return true; -} -//-------------------------------------------------------------------------------------- - static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) { uint16_t offset; @@ -758,29 +677,35 @@ static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) { const struct parsed_cart_type* type; - uint8_t* rom = NULL; - size_t rom_size = 0; - uint8_t* ram = NULL; - size_t ram_size = 0; + std::auto_ptr rom; + size_t rom_size = 0; + std::auto_ptr ram; + size_t ram_size = 0; + CFile tempFile; - /* load GB cart ROM */ - if (!load_file(gb_file, (void**)&rom, &rom_size)) - { - return false; - } + /* load GB cart ROM */ + if (!tempFile.Open(gb_file, CFileBase::modeRead)) + { + g_Notify->DisplayError("Failed to open Transferpak ROM"); + return false; + } + + rom_size = tempFile.GetLength(); + rom.reset(new uint8_t[rom_size]); + + tempFile.Read(rom.get(), rom_size); + tempFile.Close(); if (rom_size < 0x8000) { - free(rom); return false; } /* get and parse cart type */ - uint8_t cart_type = rom[0x147]; + uint8_t cart_type = rom.get()[0x147]; type = parse_cart_type(cart_type); if (type == NULL) { - free(rom); return false; } @@ -788,7 +713,7 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) if (type->extra_devices & GED_RAM) { ram_size = 0; - switch (rom[0x149]) + switch (rom.get()[0x149]) { case 0x01: ram_size = 1 * 0x800; break; case 0x02: ram_size = 4 * 0x800; break; @@ -804,21 +729,27 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) ram_size += 0x30; } - ram = (uint8_t*)malloc(ram_size ); - if (ram == NULL) + ram.reset(new uint8_t[ram_size]); + if (ram.get() == NULL) { - free(rom); return false; } - read_from_file(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), ram, ram_size ); + if (!tempFile.Open(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), CFileBase::modeRead)) + { + g_Notify->DisplayError("Failed to open Transferpak SAV File"); + return false; + } + + tempFile.Read(ram.get(), ram_size); + tempFile.Close(); } //If we have RTC we need to load in the data, we assume the save will use the VBA-M format if (type->extra_devices & GED_RTC) { gbCartRTC rtc; - memcpy(&rtc, &ram[ram_size-0x30], 0x30); + memcpy(&rtc, &ram.get()[ram_size-0x30], 0x30); gb_cart->rtc_second = rtc.second; gb_cart->rtc_minute = rtc.minute; @@ -835,8 +766,8 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) } /* update gb_cart */ - gb_cart->ram = ram; - gb_cart->rom = rom; + gb_cart->ram = ram.release(); + gb_cart->rom = rom.release(); gb_cart->rom_size = rom_size; gb_cart->ram_size = ram_size; gb_cart->rom_bank = 1; @@ -849,11 +780,12 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) void GBCart::save_gb_cart(struct gb_cart* gb_cart) { - FILE *fRAM = fopen(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), "wb"); + CFile ramFile; + ramFile.Open(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), CFileBase::modeWrite | CFileBase::modeCreate); if (gb_cart->has_rtc) { - fwrite(gb_cart->ram, 1, gb_cart->ram_size-0x30, fRAM); + ramFile.Write(gb_cart->ram, gb_cart->ram_size - 0x30); gbCartRTC rtc; rtc.second = gb_cart->rtc_second; @@ -867,14 +799,14 @@ void GBCart::save_gb_cart(struct gb_cart* gb_cart) rtc.latch_day = gb_cart->rtc_latch_day; rtc.latch_day_carry = gb_cart->rtc_latch_day_carry; rtc.mapperLastTime = gb_cart->rtc_last_time; - fwrite(&rtc, 1, 0x30, fRAM); + ramFile.Write(&rtc, 0x30); } else { - fwrite(gb_cart->ram, 1, gb_cart->ram_size, fRAM); + ramFile.Write(gb_cart->ram, gb_cart->ram_size); } - fclose(fRAM); + ramFile.Close(); } void GBCart::release_gb_cart(struct gb_cart* gb_cart) From dd7cf4af10ec3fe622efa28237ce651cf2191c63 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Wed, 3 Feb 2016 13:42:06 +1100 Subject: [PATCH 08/10] Missed two frees, when swapping out for deletes --- Source/Project64-core/N64System/Mips/GBCart.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index be23afcab..a4ca79399 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -812,10 +812,10 @@ void GBCart::save_gb_cart(struct gb_cart* gb_cart) void GBCart::release_gb_cart(struct gb_cart* gb_cart) { if (gb_cart->rom != NULL) - free(gb_cart->rom); + delete gb_cart->rom; if (gb_cart->ram != NULL) - free(gb_cart->ram); + delete gb_cart->ram; memset(gb_cart, 0, sizeof(*gb_cart)); } From e6b1fd3aecb5371df9178f383739ed6f8097ec2b Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Thu, 4 Feb 2016 00:33:03 +1100 Subject: [PATCH 09/10] Fix up reading and writing of the RTC data to the save file. Correct the RTC emulation behaviour, made it more like NRAGES, various emulators i was basing mine off seemed to not correctly update the RTC. --- .../Project64-core/N64System/Mips/GBCart.cpp | 176 +++++++++--------- Source/Project64-core/N64System/Mips/GBCart.h | 26 +-- 2 files changed, 89 insertions(+), 113 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index a4ca79399..46a895f16 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -11,6 +11,8 @@ #include "stdafx.h" #include "GBCart.h" +#include + static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) { uint16_t offset; @@ -230,6 +232,44 @@ static void write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const } } +void memoryUpdateMBC3Clock(struct gb_cart* gb_cart) +{ + time_t now = time(NULL); + time_t diff = now - gb_cart->rtc_last_time; + if (diff > 0) { + // update the clock according to the last update time + gb_cart->rtc_data[0] += (int)(diff % 60); + if (gb_cart->rtc_data[0] > 59) { + gb_cart->rtc_data[0] -= 60; + gb_cart->rtc_data[1]++; + } + diff /= 60; + + gb_cart->rtc_data[1] += (int)(diff % 60); + if (gb_cart->rtc_data[1] > 59) { + gb_cart->rtc_data[1] -= 60; + gb_cart->rtc_data[2]++; + } + diff /= 60; + + gb_cart->rtc_data[2] += (int)(diff % 24); + if (gb_cart->rtc_data[2] > 23) { + gb_cart->rtc_data[2] -= 24; + gb_cart->rtc_data[3]++; + } + diff /= 24; + + gb_cart->rtc_data[3] += (int)(diff & 0xffffffff); + if (gb_cart->rtc_data[3] > 255) { + if (gb_cart->rtc_data[3] > 511) { + gb_cart->rtc_data[3] %= 512; + gb_cart->rtc_data[3] |= 0x80; + } + gb_cart->rtc_data[4] = (gb_cart->rtc_data[4] & 0xFE) | (gb_cart->rtc_data[3]>255 ? 1 : 0); + } + } + gb_cart->rtc_last_time = now; +} static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) { @@ -261,23 +301,20 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t } else if (gb_cart->has_rtc) { - switch (gb_cart->ram_bank) + if (gb_cart->rtc_latch) { - case 0x08: - data[0] = gb_cart->rtc_latch_second; - break; - case 0x09: - data[0] = gb_cart->rtc_latch_minute; - break; - case 0x0A: - data[0] = gb_cart->rtc_latch_hour; - break; - case 0x0B: - data[0] = gb_cart->rtc_latch_day; - break; - case 0x0C: - data[0] = (gb_cart->rtc_latch_day_carry << 7) | (gb_cart->rtc_latch_day >> 8); - break; + for (int i = 0; i < 32; i++) + { + data[i] = gb_cart->rtc_latch_data[gb_cart->ram_bank - 0x08]; + } + } + else + { + memoryUpdateMBC3Clock(gb_cart); + for (int i = 0; i < 32; i++) + { + data[i] = gb_cart->rtc_data[gb_cart->ram_bank - 0x08]; + } } } } @@ -320,11 +357,12 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const //Implement RTC timer / latch if (gb_cart->rtc_latch == 0 && data[0] == 1) { - gb_cart->rtc_latch_second = gb_cart->rtc_second; - gb_cart->rtc_latch_minute = gb_cart->rtc_minute; - gb_cart->rtc_latch_hour = gb_cart->rtc_hour; - gb_cart->rtc_latch_day = gb_cart->rtc_day; - gb_cart->rtc_latch_day_carry = gb_cart->rtc_day_carry; + //Update time + memoryUpdateMBC3Clock(gb_cart); + for (int i = 0; i < 4; i++) + { + gb_cart->rtc_latch_data[i] = gb_cart->rtc_data[i]; + } } gb_cart->rtc_latch = data[0]; } @@ -342,34 +380,8 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const } else if (gb_cart->has_rtc) { - bank = data[0]; - /* RTC write */ - switch (gb_cart->ram_bank) - { - case 0x08: - if (bank >= 60) - bank = 0; - gb_cart->rtc_second = bank; - break; - case 0x09: - if (bank >= 60) - bank = 0; - gb_cart->rtc_minute = bank; - break; - case 0x0A: - if (bank >= 24) - bank = 0; - gb_cart->rtc_hour = bank; - break; - case 0x0B: - gb_cart->rtc_day = (gb_cart->rtc_day & 0x0100) | bank; - break; - case 0x0C: - gb_cart->rtc_day = ((bank & 1) << 8) | (gb_cart->rtc_day & 0xFF); - gb_cart->rtc_day_carry = bank & 0x80; - break; - } + gb_cart->rtc_data[gb_cart->ram_bank - 0x08] = data[0]; } } } @@ -724,11 +736,6 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) if (ram_size != 0) { - if (type->extra_devices & GED_RTC) - { - ram_size += 0x30; - } - ram.reset(new uint8_t[ram_size]); if (ram.get() == NULL) { @@ -742,32 +749,30 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file) } tempFile.Read(ram.get(), ram_size); - tempFile.Close(); } //If we have RTC we need to load in the data, we assume the save will use the VBA-M format if (type->extra_devices & GED_RTC) { - gbCartRTC rtc; - memcpy(&rtc, &ram.get()[ram_size-0x30], 0x30); - - gb_cart->rtc_second = rtc.second; - gb_cart->rtc_minute = rtc.minute; - gb_cart->rtc_hour = rtc.hour; - gb_cart->rtc_day = rtc.day; - gb_cart->rtc_day_carry = rtc.day_carry; - gb_cart->rtc_latch_second = rtc.latch_second; - gb_cart->rtc_latch_minute = rtc.latch_minute; - gb_cart->rtc_latch_hour = rtc.latch_hour; - gb_cart->rtc_latch_day = rtc.latch_day; - gb_cart->rtc_latch_day_carry = rtc.latch_day_carry; - gb_cart->rtc_last_time = rtc.mapperLastTime; + tempFile.Read(&gb_cart->rtc_data[0], 4); + tempFile.Read(&gb_cart->rtc_data[1], 4); + tempFile.Read(&gb_cart->rtc_data[2], 4); + tempFile.Read(&gb_cart->rtc_data[3], 4); + tempFile.Read(&gb_cart->rtc_data[4], 4); + tempFile.Read(&gb_cart->rtc_latch_data[0], 4); + tempFile.Read(&gb_cart->rtc_latch_data[1], 4); + tempFile.Read(&gb_cart->rtc_latch_data[2], 4); + tempFile.Read(&gb_cart->rtc_latch_data[3], 4); + tempFile.Read(&gb_cart->rtc_latch_data[4], 4); + tempFile.Read(&gb_cart->rtc_last_time, 8); + memoryUpdateMBC3Clock(gb_cart); } + tempFile.Close(); } /* update gb_cart */ - gb_cart->ram = ram.release(); gb_cart->rom = rom.release(); + gb_cart->ram = ram.release(); gb_cart->rom_size = rom_size; gb_cart->ram_size = ram_size; gb_cart->rom_bank = 1; @@ -782,28 +787,21 @@ void GBCart::save_gb_cart(struct gb_cart* gb_cart) { CFile ramFile; ramFile.Open(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), CFileBase::modeWrite | CFileBase::modeCreate); - + ramFile.Write(gb_cart->ram, gb_cart->ram_size); + if (gb_cart->has_rtc) { - ramFile.Write(gb_cart->ram, gb_cart->ram_size - 0x30); - - gbCartRTC rtc; - rtc.second = gb_cart->rtc_second; - rtc.minute = gb_cart->rtc_minute; - rtc.hour = gb_cart->rtc_hour; - rtc.day = gb_cart->rtc_day; - rtc.day_carry = gb_cart->rtc_day_carry; - rtc.latch_second = gb_cart->rtc_latch_second; - rtc.latch_minute = gb_cart->rtc_latch_minute; - rtc.latch_hour = gb_cart->rtc_latch_hour; - rtc.latch_day = gb_cart->rtc_latch_day; - rtc.latch_day_carry = gb_cart->rtc_latch_day_carry; - rtc.mapperLastTime = gb_cart->rtc_last_time; - ramFile.Write(&rtc, 0x30); - } - else - { - ramFile.Write(gb_cart->ram, gb_cart->ram_size); + ramFile.Write(&gb_cart->rtc_data[0], 4); + ramFile.Write(&gb_cart->rtc_data[1], 4); + ramFile.Write(&gb_cart->rtc_data[2], 4); + ramFile.Write(&gb_cart->rtc_data[3], 4); + ramFile.Write(&gb_cart->rtc_data[4], 4); + ramFile.Write(&gb_cart->rtc_latch_data[0], 4); + ramFile.Write(&gb_cart->rtc_latch_data[1], 4); + ramFile.Write(&gb_cart->rtc_latch_data[2], 4); + ramFile.Write(&gb_cart->rtc_latch_data[3], 4); + ramFile.Write(&gb_cart->rtc_latch_data[4], 4); + ramFile.Write(&gb_cart->rtc_last_time, 8); } ramFile.Close(); diff --git a/Source/Project64-core/N64System/Mips/GBCart.h b/Source/Project64-core/N64System/Mips/GBCart.h index f74e8a11c..8eb9c506c 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.h +++ b/Source/Project64-core/N64System/Mips/GBCart.h @@ -30,36 +30,14 @@ struct gb_cart uint32_t rtc_latch; - uint32_t rtc_second; - uint32_t rtc_minute; - uint32_t rtc_hour; - uint32_t rtc_day; - uint32_t rtc_day_carry; - uint32_t rtc_latch_second; - uint32_t rtc_latch_minute; - uint32_t rtc_latch_hour; - uint32_t rtc_latch_day; - uint32_t rtc_latch_day_carry; + int32_t rtc_data[5]; + int32_t rtc_latch_data[5]; time_t rtc_last_time; void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); void(*write_gb_cart)(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data); }; -struct gbCartRTC { - uint32_t second; - uint32_t minute; - uint32_t hour; - uint32_t day; - uint32_t day_carry; - uint32_t latch_second; - uint32_t latch_minute; - uint32_t latch_hour; - uint32_t latch_day; - uint32_t latch_day_carry; - time_t mapperLastTime; -}; - class GBCart { public: From 494ad71352d0e2146938ce7d6bebe5fa04b30831 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Thu, 4 Feb 2016 12:57:09 +1100 Subject: [PATCH 10/10] Change declaration, we should only need int. --- Source/Project64-core/N64System/Mips/GBCart.cpp | 3 ++- Source/Project64-core/N64System/Mips/GBCart.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/GBCart.cpp b/Source/Project64-core/N64System/Mips/GBCart.cpp index 46a895f16..49afdab14 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.cpp +++ b/Source/Project64-core/N64System/Mips/GBCart.cpp @@ -259,7 +259,8 @@ void memoryUpdateMBC3Clock(struct gb_cart* gb_cart) } diff /= 24; - gb_cart->rtc_data[3] += (int)(diff & 0xffffffff); + + gb_cart->rtc_data[3] += (int)(diff & 0xFFFFFFFF); if (gb_cart->rtc_data[3] > 255) { if (gb_cart->rtc_data[3] > 511) { gb_cart->rtc_data[3] %= 512; diff --git a/Source/Project64-core/N64System/Mips/GBCart.h b/Source/Project64-core/N64System/Mips/GBCart.h index 8eb9c506c..564e08258 100644 --- a/Source/Project64-core/N64System/Mips/GBCart.h +++ b/Source/Project64-core/N64System/Mips/GBCart.h @@ -30,8 +30,8 @@ struct gb_cart uint32_t rtc_latch; - int32_t rtc_data[5]; - int32_t rtc_latch_data[5]; + int rtc_data[5]; + int rtc_latch_data[5]; time_t rtc_last_time; void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data);