commit 3c3bea257346efa5a282a6308553d7e4309e641b Author: msiewert76 Date: Mon Apr 25 19:59:27 2011 +0000 This is the code for the first version, released on 12-5-2010. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2fe57d8 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +export TARGET := $(shell basename $(CURDIR)) +export TOPDIR := $(CURDIR) + + +.PHONY: $(TARGET).arm7 $(TARGET).arm9 + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all: $(TARGET).nds + +#--------------------------------------------------------------------------------- +#$(TARGET).nds : $(TARGET).arm7 $(TARGET).arm9 +# ndstool -c $(TARGET).nds -7 $(TARGET).arm7 -9 $(TARGET).arm9 +$(TARGET).nds : $(TARGET).arm9 + ndstool -c $(TARGET).nds -9 $(TARGET).arm9 + +#--------------------------------------------------------------------------------- +#$(TARGET).arm7 : arm7/$(TARGET).elf +$(TARGET).arm9 : arm9/$(TARGET).elf + +#--------------------------------------------------------------------------------- +#arm7/$(TARGET).elf: +# $(MAKE) -C arm7 + +#--------------------------------------------------------------------------------- +arm9/$(TARGET).elf: + $(MAKE) -C arm9 + +#--------------------------------------------------------------------------------- +clean: + $(MAKE) -C arm9 clean +# $(MAKE) -C arm7 clean + rm -f $(TARGET).nds $(TARGET).arm9 +# rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9 diff --git a/arm9/Makefile b/arm9/Makefile new file mode 100644 index 0000000..cbf5cd1 --- /dev/null +++ b/arm9/Makefile @@ -0,0 +1,132 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +# DATA is a list of directories containing binary files +# all directories are relative to this makefile +#--------------------------------------------------------------------------------- +BUILD := build +SOURCES := source +INCLUDES := include +DATA := + + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -O2\ + -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s + +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lfat -lnds9 + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export ARM9BIN := $(TOPDIR)/$(TARGET).arm9 +export ARM9ELF := $(CURDIR)/$(TARGET).arm9.elf +export DEPSDIR := $(CURDIR)/$(BUILD) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf *.nds* *.bin + + +#--------------------------------------------------------------------------------- +else + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(ARM9BIN) : $(ARM9ELF) + @$(OBJCOPY) -O binary $< $@ + @echo built ... $(notdir $@) + +$(ARM9ELF) : $(OFILES) + @echo linking $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPSDIR)/*.d + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/arm9/source/auxspi.cpp b/arm9/source/auxspi.cpp new file mode 100644 index 0000000..0b3ddbb --- /dev/null +++ b/arm9/source/auxspi.cpp @@ -0,0 +1,283 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * auxspi.cpp: A thin reimplementation of the AUXSPI protocol + * (high level functions) + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "auxspi.h" +#include "auxspi_core.cpp" +#include "hardware.h" + + +// ======================================================== +// local functions +uint8 jedec_table(uint32 id) +{ + switch (id) { + // 256 kB + case 0x204012: + case 0x621600: + return 0x12; + // 512 kB + case 0x204013: + case 0x621100: + return 0x13; + // 1 MB + case 0x204014: + return 0x14; + // 8 MB (Band Brothers DX) + case 0x204017: + return 0x17; + default: + return 0; + }; +} + +uint8 type2_size() +{ + static const uint32 offset0 = (8*1024-1); // 8KB + static const uint32 offset1 = (2*8*1024-1); // 16KB + u8 buf1; // +0k data read -> write + u8 buf2; // +8k data read -> read + u8 buf3; // +0k ~data write + u8 buf4; // +8k data new comp buf2 + auxspi_read_data(offset0, &buf1, 1, 2); + auxspi_read_data(offset1, &buf2, 1, 2); + buf3=~buf1; + auxspi_write_data(offset0, &buf3, 1, 2); + auxspi_read_data (offset1, &buf4, 1, 2); + auxspi_write_data(offset0, &buf1, 1, 2); + if(buf4!=buf2) // +8k + return 0x0d; // 8KB(64kbit) + else + return 0x10; // 64KB(512kbit) +} + +// ======================================================== + +uint8 auxspi_save_type() +{ + uint32 jedec = auxspi_save_jedec_id(); // 9f + int8 sr = auxspi_save_status_register(); // 05 + + if ((sr & 0xfd) == 0xF0 && (jedec == 0x00ffffff)) return 1; + if ((sr & 0xfd) == 0x00 && (jedec == 0x00ffffff)) return 2; + if ((sr & 0xfd) == 0x00 && (jedec != 0x00ffffff)) return 3; // should also cover Pokemon HG/SS + + return 0; +} + +uint32 auxspi_save_size() +{ + return 1 << auxspi_save_size_log_2(); +} + +uint8 auxspi_save_size_log_2() +{ + uint8 type = auxspi_save_type(); + switch (type) { + case 1: + return 0x09; // 512 bytes + break; + case 2: + return type2_size(); + break; + case 3: + return jedec_table(auxspi_save_jedec_id()); + break; + default: + return 0; + } +} + +uint32 auxspi_save_jedec_id() +{ + uint32 id = 0; + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(0x9f); + id |= auxspi_read() << 16; + id |= auxspi_read() << 8; + id |= auxspi_read(); + auxspi_close(); + return id; +} + +uint8 auxspi_save_status_register() +{ + uint8 sr = 0; + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(0x05); + sr = auxspi_read(); + auxspi_close(); + return sr; +} + +void auxspi_read_data(uint32 addr, uint8* buf, uint16 cnt, uint8 type) +{ + if (type == 0) + type = auxspi_save_type(); + if (type == 0) + return; + + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(0x03 | ((type == 1) ? addr>>8<<3 : 0)); + + if (type == 3) { + auxspi_write((addr >> 16) & 0xFF); + } + + if (type >= 2) { + auxspi_write((addr >> 8) & 0xFF); + } + + auxspi_write(addr & 0xFF); + + while (cnt > 0) { + *buf++ = auxspi_read(); + cnt--; + } + + auxspi_close(); +} + +void auxspi_write_data(uint32 addr, uint8 *buf, uint16 cnt, uint8 type) +{ +/* + if (type == 0) + type = auxspi_save_type(); + if (type == 0) + return; + */ + + uint32 addr_end = addr + cnt; + int i; + int maxblocks = 32; + if(type == 1) maxblocks = 16; + if(type == 2) maxblocks = 32; + if(type == 3) maxblocks = 256; + + // we can only write a finite amount of data at once, so we need a separate loop + // for multiple passes. + while (addr < addr_end) { + auxspi_disable_infrared(); + auxspi_open(0); + // set WEL (Write Enable Latch) + auxspi_write(0x06); + auxspi_close_lite(); + + auxspi_disable_infrared(); + auxspi_open(0); + // send initial "write" command + if(type == 1) { + auxspi_write(0x02 | (addr & BIT(8)) >> (8-3)); + auxspi_write(addr & 0xFF); + } + else if(type == 2) { + auxspi_write(0x02); + auxspi_write((addr >> 8) & 0xff); + auxspi_write(addr & 0xFF); + } + else if(type == 3) { + auxspi_write(0x02); + auxspi_write((addr >> 16) & 0xff); + auxspi_write((addr >> 8) & 0xff); + auxspi_write(addr & 0xFF); + } + + for (i=0; addr < addr_end && i < maxblocks; i++, addr++) { + auxspi_write(*buf++); + } + auxspi_close_lite(); + + // wait for programming to finish + //auxspi_wait_wip(); + // wait programming to finish + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(5); + do { REG_AUXSPIDATA = 0; auxspi_wait_busy(); } while (REG_AUXSPIDATA & 0x01); // WIP (Write In Progress) ? + auxspi_wait_busy(); + auxspi_close(); + } +} + +void auxspi_disable_infrared() +{ + if (with_infrared) + auxspi_disable_infrared_core(); +} + +bool auxspi_has_infrared() +{ + return with_infrared; +} + +void auxspi_erase() +{ + uint8 type = auxspi_save_type(); + if (type == 3) { + uint8 size; + size = 1 << (auxspi_save_size_log_2() - 16); + for (int i = 0; i < size; i++) { + auxspi_disable_infrared(); + auxspi_open(0); + // set WEL (Write Enable Latch) + auxspi_write(0x06); + auxspi_close_lite(); + + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(0xd8); + auxspi_write(i); + auxspi_write(0); + auxspi_write(0); + auxspi_close_lite(); + + // wait for programming to finish + //auxspi_wait_wip(); + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(5); + do { REG_AUXSPIDATA = 0; auxspi_wait_busy(); } while (REG_AUXSPIDATA & 0x01); // WIP (Write In Progress) ? + auxspi_wait_busy(); + auxspi_close(); + } + } + + // FIXME: do something for other types as well! +} + +void auxspi_wait_wip() +{ + auxspi_disable_infrared(); + auxspi_open(0); + auxspi_write(0x05); + uint8 sr; + do { + sr = auxspi_read(); + } while (sr & 0x01); + auxspi_close(); +} diff --git a/arm9/source/auxspi.h b/arm9/source/auxspi.h new file mode 100644 index 0000000..2cd16ba --- /dev/null +++ b/arm9/source/auxspi.h @@ -0,0 +1,51 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * auxspi.h: Header for auxspi.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + This is a thin reimplementation of the AUXSPI protocol at low levels. + It is used to implement various experimental procedures to test accessing the HG/SS save chip. */ + +#ifndef SPI_BUS_H +#define SPI_BUS_H + +#include + + +extern bool with_infrared; + +uint8 auxspi_save_type(); +uint32 auxspi_save_size(); +uint8 auxspi_save_size_log_2(); +uint32 auxspi_save_jedec_id(); +uint8 auxspi_save_status_register(); +void auxspi_read_data(uint32 addr, uint8* buf, uint16 cnt, uint8 type = 0); +void auxspi_write_data(uint32 addr, uint8 *buf, uint16 cnt, uint8 type = 0); +void auxspi_disable_infrared(); +void auxspi_erase(); +void auxspi_wait_wip(); + +bool auxspi_has_infrared(); +//void auxspi_gpio_init_save(); + +#endif \ No newline at end of file diff --git a/arm9/source/auxspi_core.cpp b/arm9/source/auxspi_core.cpp new file mode 100644 index 0000000..9670f7a --- /dev/null +++ b/arm9/source/auxspi_core.cpp @@ -0,0 +1,85 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * auxspi.cpp: A thin reimplementation of the AUXSPI protocol + * (low level functions) + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +inline void auxspi_wait_busy() +{ + while (REG_AUXSPICNT & 0x80); +} + +inline void auxspi_open(uint8 device) +{ + REG_AUXSPICNT = 0xa040 | (device & 3); + auxspi_wait_busy(); +} + +inline void auxspi_close() +{ + REG_AUXSPIDATA = 0; + auxspi_wait_busy(); + REG_AUXSPICNT = 0; + auxspi_wait_busy(); +} + +inline void auxspi_close_lite() +{ + REG_AUXSPICNT = 0x40; + auxspi_wait_busy(); +} + +inline uint8 auxspi_transfer(uint8 out) +{ + REG_AUXSPIDATA = out; + auxspi_wait_busy(); + return REG_AUXSPIDATA; +} + +inline void auxspi_write(uint8 out) +{ + auxspi_transfer(out); +} + +inline uint8 auxspi_read() +{ + return auxspi_transfer(0); +} + +inline uint16 auxspi_read_16() +{ + REG_AUXSPIDATA = 0; + auxspi_wait_busy(); + return REG_AUXSPIDATA; +} + +inline void auxspi_disable_infrared_core() +{ + auxspi_open(0); + swiDelay(1000); + auxspi_open(2); + auxspi_write(0); + swiDelay(1000); +} diff --git a/arm9/source/display.cpp b/arm9/source/display.cpp new file mode 100644 index 0000000..a9331af --- /dev/null +++ b/arm9/source/display.cpp @@ -0,0 +1,293 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * display.cpp: A collection of shared functions used to print various + * status messages and feedback on the screens. + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include + +#include "display.h" +#include "auxspi.h" +#include "hardware.h" +#include "fileselect.h" + +#include "auxspi_core.cpp" + +PrintConsole upperScreen; +PrintConsole lowerScreen; + + +extern uint32 mode; + + +//=========================================================== +void displayInit() +{ + videoSetMode(MODE_0_2D); + vramSetBankA(VRAM_A_MAIN_BG); + consoleInit(&upperScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true); + + videoSetModeSub(MODE_0_2D); + vramSetBankC(VRAM_C_SUB_BG); + consoleInit(&lowerScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true); + + consoleSelect(&upperScreen); + displayMessage("DS savegame manager\nVersion 0.1 Beta\nBy Pokedoc"); + + displayPrintState("Press (A) to continue"); + while (!(keysCurrent() & KEY_A)); +} + +void displayPrintUpper() +{ + // print upper screen (background) + consoleSelect(&upperScreen); + consoleSetWindow(&upperScreen, 0, 0, 32, 24); + consoleClear(); + iprintf("Mode :\n"); + iprintf("--- SLOT 1 ---------------------"); + iprintf("Game ID :\n"); + iprintf("Game name:\n"); + iprintf("Game save:\n"); + iprintf("Special :\n"); +#if 0 + iprintf("--- SLOT 2 ---------------------"); + iprintf("Game ID :\n"); + iprintf("Game name:\n"); + iprintf("Game save:\n"); + iprintf("Special :\n"); +#endif + + // print upper screen + consoleSetWindow(&upperScreen, 10, 2, 12, 4); + consoleClear(); + + // fetch cartridge header (maybe, calling "cardReadHeader" on a FC messes with libfat!) + bool flash_card = is_flash_card(); + bool ir = auxspi_has_infrared(); + sNDSHeader nds; + if (!flash_card) + cardReadHeader((uint8*)&nds); + + char name[MAXPATHLEN]; + // 0) print the mode + consoleSetWindow(&upperScreen, 10, 0, 20, 1); + switch (mode) { + case 0: + sprintf(&name[0], "WiFi/FTP"); + break; + case 1: + sprintf(&name[0], "GBA"); + break; + case 2: + sprintf(&name[0], "3-in-1"); + break; + case 3: + sprintf(&name[0], "DSi/SD"); + break; + } + consoleClear(); + iprintf("%s", name); + + // 1) The cart id. + consoleSetWindow(&upperScreen, 10, 2, 20, 1); + sprintf(&name[0], "----"); + if (flash_card) { + sprintf(&name[0], "Flash Card"); + } else if (nds.gameCode[0]) { + memcpy(&name[0], &nds.gameCode[0], 4); + name[4] = 0x00; + } + consoleClear(); + iprintf("%s", name); + + // 2) The cart name. + consoleSetWindow(&upperScreen, 10, 3, 20, 1); + sprintf(&name[0], "----"); + if (flash_card) { + sprintf(&name[0], "Flash Card"); + } else if (nds.gameTitle[0]) { + memcpy(&name[0], &nds.gameTitle[0], 12); + name[12] = 0x00; + } + consoleClear(); + iprintf("%s", name); + + // 3) The save type + consoleSetWindow(&upperScreen, 10, 4, 20, 1); + sprintf(&name[0], "----"); + if (flash_card) { + sprintf(&name[0], "Flash Card"); + } else { + uint8 type = auxspi_save_type(); + uint32 size = auxspi_save_size(); + switch (type) { + case 1: + sprintf(&name[0], "Type 1 (%i Bytes)", size); + break; + case 2: + sprintf(&name[0], "Type 2 (%i kB)", size >> 10); + break; + case 3: + sprintf(&name[0], "Flash (%i kB)", size >> 10); + break; + default: + sprintf(&name[0], "unknown"); + break; + } + } + consoleClear(); + iprintf("%s", name); + + // 4) Special properties (infrared device...) + consoleSetWindow(&upperScreen, 10, 5, 24, 1); + consoleClear(); + memset(&name[0], 0, MAXPATHLEN); + //if (auxspi_has_infrared()) { + if (ir) { + sprintf(&name[0], "Infrared"); + } else { + sprintf(&name[0], "---"); + } + iprintf("%s", name); + +#if 0 + // hack: some tests to debug new hardware. + uint8 data[512]; + memset(&data[0], 0, 512); + char text[128]; + + int i; + uint32 id = auxspi_save_jedec_id(); + auxspi_read_data(0, &data[0], 32); + /* + auxspi_open(0); + for (int i = 0; i < 32; i++) { + data[i] = auxspi_read(); + } + auxspi_close(); + */ + sprintf(&text[0], + "Status: %x\n%x %x %x %x %x %x %x %x\n%x %x %x %x %x %x %x %x\n%x %x %x %x %x %x %x %x\n%x %x %x %x %x %x %x %x\n", + id, + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], + data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], + data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], + data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31]); + displayMessage(&text[0]); +#endif +} + +void displayPrintLower() +{ + consoleSelect(&lowerScreen); + consoleSetWindow(&lowerScreen, 0, 0, 32, 24); + consoleClear(); + iprintf("+------------------------------+"); + for (int i = 0; i < 6; i++) { + iprintf("| |"); + } + iprintf("+------------------------------+"); + iprintf("+------------------------------+"); + for (int i = 0; i < 6; i++) { + iprintf("| |"); + } + iprintf("+------------------------------+"); + iprintf("+------------------------------+"); + for (int i = 0; i < 6; i++) { + iprintf("| |"); + } + iprintf("+------------------------------+"); + + consoleSetWindow(&lowerScreen, 1, 1, 30, 6); + iprintf("\n\n BACKUP\n"); + iprintf(" Game -> .sav"); + + consoleSetWindow(&lowerScreen, 1, 9, 30, 6); + iprintf("\n\n RESTORE\n"); + iprintf(" .sav -> Game"); + + consoleSetWindow(&lowerScreen, 1, 17, 30, 6); + iprintf("\n RESET\n\n"); + iprintf(" WIPES OUT ALL SAVE DATA\n"); + iprintf(" ON YOUR GAME !"); +} + +void displayMessage(const char *msg) +{ + consoleSelect(&upperScreen); + consoleSetWindow(0, 0, 16, 32, 6); + consoleClear(); + + iprintf("%s", msg); +} + +void displayPrintState(const char *txt) +{ + swiWaitForVBlank(); + consoleSelect(&upperScreen); + consoleSetWindow(0, 0, 22, 32, 1); + consoleClear(); + iprintf("%s", txt); +} + + +void displayProgressBar(int cur, int max0) +{ + swiWaitForVBlank(); + consoleSelect(&upperScreen); + consoleSetWindow(0, 0, 23, 32, 1); + consoleClear(); + + char buffer[33]; + + int percent = float(cur)/float(max0)*100; + if (percent > 100) + percent = 100; + sprintf(&buffer[14], "%i%%", percent); + + buffer[0] = '['; + int steps = float(cur)/float(max0)*30; + if (steps > 30) + steps = 30; + for (int i = 1; i <= 30; i++) { + if ((i >= 14) && (i <= 15)) + continue; + if ((i == 16) && (percent >= 10)) + continue; + if ((i == 17) && (percent == 100)) + continue; + if (i <= steps) + buffer[i] = '#'; + else + buffer[i] = '-'; + } + buffer[31] = ']'; + buffer[32] = 0; + + iprintf("%s", buffer); +} + diff --git a/arm9/source/display.h b/arm9/source/display.h new file mode 100644 index 0000000..78bcd8c --- /dev/null +++ b/arm9/source/display.h @@ -0,0 +1,47 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * display.h: header file for display.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SAVE_DISPLAY_H +#define SAVE_DISPLAY_H + +#include + + +extern PrintConsole upperScreen; +extern PrintConsole lowerScreen; + + +void displayInit(); + +void displayPrintUpper(); +void displayPrintLower(); + +void displayMessage(const char *msg); +void displayProgressBar(int cur, int max0); +void displayPrintState(const char *txt); + + + +#endif diff --git a/arm9/source/dsCard.cpp b/arm9/source/dsCard.cpp new file mode 100644 index 0000000..3b120bb --- /dev/null +++ b/arm9/source/dsCard.cpp @@ -0,0 +1,661 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * dsCard.cpp: Functions for accessing an EZFlash 3-in-1. + * + * Copyright (C) EZFlash Group (2006) + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "dscard.h" +#include "string.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// This is set by "ReadNORFlashID", which *must* *always* be called before anything else! +uint32 ID; + +//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +//--------------------------------------------------- +//DS 卡 基本操作 +void Enable_Arm9DS() +{ + REG_EXMEMCNT &= ~0x0800; + //WAIT_CR &= ~0x0800; +} + +void Enable_Arm7DS() +{ + REG_EXMEMCNT |= 0x0800; + //WAIT_CR |= 0x0800; +} + +void OpenNorWrite() +{ + *(vuint16 *)0x9fe0000 = 0xd200; + *(vuint16 *)0x8000000 = 0x1500; + *(vuint16 *)0x8020000 = 0xd200; + *(vuint16 *)0x8040000 = 0x1500; + *(vuint16 *)0x9C40000 = 0x1500; + *(vuint16 *)0x9fc0000 = 0x1500; +} + + +void CloseNorWrite() +{ + *(vuint16 *)0x9fe0000 = 0xd200; + *(vuint16 *)0x8000000 = 0x1500; + *(vuint16 *)0x8020000 = 0xd200; + *(vuint16 *)0x8040000 = 0x1500; + *(vuint16 *)0x9C40000 = 0xd200; + *(vuint16 *)0x9fc0000 = 0x1500; +} + +void SetRompage(u16 page) +{ + *(vuint16 *)0x9fe0000 = 0xd200; + *(vuint16 *)0x8000000 = 0x1500; + *(vuint16 *)0x8020000 = 0xd200; + *(vuint16 *)0x8040000 = 0x1500; + *(vuint16 *)0x9880000 = page; + *(vuint16 *)0x9fc0000 = 0x1500; +} +void SetRampage(u16 page) +{ + *(vu16 *)0x9fe0000 = 0xd200; + *(vu16 *)0x8000000 = 0x1500; + *(vu16 *)0x8020000 = 0xd200; + *(vu16 *)0x8040000 = 0x1500; + *(vu16 *)0x9c00000 = page; + *(vu16 *)0x9fc0000 = 0x1500; +} +void SetSerialMode() +{ + + *(vu16 *)0x9fe0000 = 0xd200; + *(vu16 *)0x8000000 = 0x1500; + *(vu16 *)0x8020000 = 0xd200; + *(vu16 *)0x8040000 = 0x1500; + *(vu16 *)0x9A40000 = 0xe200; + *(vu16 *)0x9fc0000 = 0x1500; + +} +uint32 ReadNorFlashID() +{ + vuint16 id1,id2,id3,id4; + ID=0; + //check intel 512M 3in1 card + *((vuint16 *)(FlashBase+0)) = 0xFF ; + *((vuint16 *)(FlashBase+0x1000*2)) = 0xFF ; + *((vuint16 *)(FlashBase+0)) = 0x90 ; + *((vuint16 *)(FlashBase+0x1000*2)) = 0x90 ; + id1 = *((vuint16 *)(FlashBase+0)) ; + id2 = *((vuint16 *)(FlashBase+0x1000*2)) ; + id3 = *((vuint16 *)(FlashBase+1*2)) ; + id4 = *((vuint16 *)(FlashBase+0x1001*2)) ; + if(id3==0x8810) + id3=0x8816; + if(id4==0x8810) + id4=0x8816; + if( (id1==0x89)&& (id2==0x89) &&(id3==0x8816) && (id4==0x8816)) + { + ID = 0x89168916; + return 0x89168916; + } + //检测256M卡 + *((vuint16 *)(FlashBase+0x555*2)) = 0xAA ; + *((vuint16 *)(FlashBase+0x2AA*2)) = 0x55 ; + *((vuint16 *)(FlashBase+0x555*2)) = 0x90 ; + + *((vuint16 *)(FlashBase+0x1555*2)) = 0xAA ; + *((vuint16 *)(FlashBase+0x12AA*2)) = 0x55 ; + *((vuint16 *)(FlashBase+0x1555*2)) = 0x90 ; + + id1 = *((vuint16 *)(FlashBase+0x2)) ; + id2 = *((vuint16 *)(FlashBase+0x2002)) ; + if( (id1!=0x227E)|| (id2!=0x227E)) + return 0; + + id1 = *((vuint16 *)(FlashBase+0xE*2)) ; + id2 = *((vuint16 *)(FlashBase+0x100e*2)) ; + if(id1==0x2218 && id2==0x2218) //H6H6 + { + ID = 0x227E2218; + return 0x227E2218; + } + + if(id1==0x2202 && id2==0x2202) //VZ064 + { + ID = 0x227E2202; + return 0x227E2202; + } + if(id1==0x2202 && id2==0x2220) //VZ064 + { + ID = 0x227E2202; + return 0x227E2202; + } + if(id1==0x2202 && id2==0x2215) //VZ064 + { + ID = 0x227E2202; + return 0x227E2202; + } + + return 0; +} +void chip_reset() +{ + if(ID==0x89168916) + { + *((vuint16 *)(FlashBase+0)) = 0x50 ; + *((vuint16 *)(FlashBase+0x1000*2)) = 0x50 ; + *((vuint16 *)(FlashBase+0)) = 0xFF ; + *((vuint16 *)(FlashBase+0x1000*2)) = 0xFF ; + return; + } + *((vu16 *)(FlashBase)) = 0xF0 ; + *((vu16 *)(FlashBase+0x1000*2)) = 0xF0 ; + + if(ID==0x227E2202) + { + *((vu16 *)(FlashBase+0x1000000)) = 0xF0 ; + *((vu16 *)(FlashBase+0x1000000+0x1000*2)) = 0xF0 ; + } +} + +void Block_EraseIntel(u32 blockAdd) +{ + u32 loop; + vu16 v1,v2; + bool b512=false; + if(blockAdd>=0x2000000) + { + blockAdd-=0x2000000; + CloseNorWrite(); + SetRompage(768); + OpenNorWrite(); + b512=true; + } + if(blockAdd==0) + { + for(loop=0;loop<0x40000;loop+=0x10000) + { + *((vu16 *)(FlashBase+loop)) = 0x50 ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0x50 ; + *((vu16 *)(FlashBase+loop)) = 0xFF ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0xFF ; + *((vu16 *)(FlashBase+loop)) = 0x60 ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0x60; + *((vu16 *)(FlashBase+loop)) = 0xD0 ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0xD0; + *((vu16 *)(FlashBase+loop)) = 0x20 ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0x20; + *((vu16 *)(FlashBase+loop)) = 0xD0 ; + *((vu16 *)(FlashBase+loop+0x2000)) = 0xD0; + + do + { + v1 = *((vu16 *)(FlashBase+loop)); + v2 = *((vu16 *)(FlashBase+loop+0x2000)); + } + while((v1!=0x80)||(v2!=0x80)); + } + } + else + { + *((vu16 *)(FlashBase+blockAdd)) = 0xFF ; + *((vu16 *)(FlashBase+blockAdd+0x2000)) = 0xFF ; + *((vu16 *)(FlashBase+blockAdd)) = 0x60 ; + *((vu16 *)(FlashBase+blockAdd+0x2000)) = 0x60 ; + *((vu16 *)(FlashBase+blockAdd)) = 0xD0 ; + *((vu16 *)(FlashBase+blockAdd+0x2000)) = 0xD0 ; + *((vu16 *)(FlashBase+blockAdd)) = 0x20 ; + *((vu16 *)(FlashBase+blockAdd+0x2000)) = 0x20 ; + *((vu16 *)(FlashBase+blockAdd)) = 0xD0 ; + *((vu16 *)(FlashBase+blockAdd+0x2000)) = 0xD0 ; + do + { + v1 = *((vu16 *)(FlashBase+blockAdd)); + v2 = *((vu16 *)(FlashBase+blockAdd+0x2000)); + + } + while((v1!=0x80)||(v2!=0x80)); + } + if(b512) + { + CloseNorWrite(); + SetRompage(0); + OpenNorWrite(); + b512=true; + } +} + +void Block_Erase(u32 blockAdd) +{ + vu16 v1,v2; + u32 Address; + u32 loop; + u32 off=0; + if(ID==0x89168916) + { + //intel 512 card + Block_EraseIntel(blockAdd); + return ; + } + if( (blockAdd>=0x1000000) && (ID==0x227E2202)) + { + off=0x1000000; + *((vu16 *)(FlashBase+off+0x555*2)) = 0xF0 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xF0 ; + } + else + off=0; + Address=blockAdd; + *((vu16 *)(FlashBase+0x555*2)) = 0xF0 ; + *((vu16 *)(FlashBase+0x1555*2)) = 0xF0 ; + + + if( (blockAdd==0) || (blockAdd==0x1FC0000) || (blockAdd==0xFC0000) || (blockAdd==0x1000000)) + { + for(loop=0;loop<0x40000;loop+=0x8000) + { + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+loop)) = 0x30 ; + + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+loop+0x2000)) = 0x30 ; + + *((vu16 *)(FlashBase+off+0x2555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x22AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x2555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x2555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x22AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+loop+0x4000)) = 0x30 ; + + *((vu16 *)(FlashBase+off+0x3555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x32AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x3555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x3555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x32AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+loop+0x6000)) = 0x30 ; + do + { + + v1 = *((vu16 *)(FlashBase+Address+loop)) ; + v2 = *((vu16 *)(FlashBase+Address+loop)) ; + }while(v1!=v2); + do + { + + v1 = *((vu16 *)(FlashBase+Address+loop+0x2000)) ; + v2 = *((vu16 *)(FlashBase+Address+loop+0x2000)) ; + }while(v1!=v2); + do + { + + v1 = *((vu16 *)(FlashBase+Address+loop+0x4000)) ; + v2 = *((vu16 *)(FlashBase+Address+loop+0x4000)) ; + }while(v1!=v2); + do + { + + v1 = *((vu16 *)(FlashBase+Address+loop+0x6000)) ; + v2 = *((vu16 *)(FlashBase+Address+loop+0x6000)) ; + }while(v1!=v2); + } + } + else + { + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55; + *((vu16 *)(FlashBase+Address)) = 0x30 ; + + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+0x2000)) = 0x30 ; + + do + { + v1 = *((vu16 *)(FlashBase+Address)) ; + v2 = *((vu16 *)(FlashBase+Address)) ; + }while(v1!=v2); + do + { + v1 = *((vu16 *)(FlashBase+Address+0x2000)) ; + v2 = *((vu16 *)(FlashBase+Address+0x2000)) ; + }while(v1!=v2); + + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55; + *((vu16 *)(FlashBase+Address+0x20000)) = 0x30 ; + + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0x80 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+Address+0x2000+0x20000)) = 0x30 ; + + do + { + v1 = *((vu16 *)(FlashBase+Address+0x20000)) ; + v2 = *((vu16 *)(FlashBase+Address+0x20000)) ; + }while(v1!=v2); + do + { + v1 = *((vu16 *)(FlashBase+Address+0x2000+0x20000)) ; + v2 = *((vu16 *)(FlashBase+Address+0x2000+0x20000)) ; + }while(v1!=v2); + } +} +void ReadNorFlash(u8* pBuf,u32 address,u16 len) +{ + vu16 *p = (vu16 *)pBuf; + u32 loop; + bool b512=false; + if(address>=0x2000000)//256M + { + CloseNorWrite(); + SetRompage(768); + address-=0x2000000; + b512=true; + } + Enable_Arm7DS(); + OpenNorWrite(); + if(ID==0x89168916) + { + *((vuint16 *)(FlashBase+address)) = 0x50 ; + *((vuint16 *)(FlashBase+address+0x1000*2)) = 0x50 ; + *((vuint16 *)(FlashBase+address)) = 0xFF ; + *((vuint16 *)(FlashBase+address+0x1000*2)) = 0xFF ; + } + for(loop=0;loop=0x2000000) + { + address-=0x2000000; + CloseNorWrite(); + SetRompage(768); + OpenNorWrite(); + b512=true; + } + else + { + CloseNorWrite(); + SetRompage(0); + OpenNorWrite(); + } + + if(size>0x4000) + { + size2 = size >>1 ; + lop = 2; + } + else + { + size2 = size ; + lop = 1; + } + mapaddress = address; + +// _consolePrintf("WriteNorFlashINTEL begin\n"); + for(j=0;j>1))) = 0x50; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0x50; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) = 0xFF; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0xFF; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) = 0xE8; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0xE8; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) = 0x70; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0x70; + v1=v2=0; + while((v1!= 0x80) || (v2 != 0x80) ) + { + v1 = *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) ; + v2 = *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) ; + } + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) = 0x0F; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0x0F; + for(i=0;i<0x10;i++) + { + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+i*2)) = buf[(loopwrite>>2)+i]; + *((vu16 *)(FlashBase+mapaddress+0x2000+(loopwrite>>1)+i*2)) = buf[0x1000+(loopwrite>>2)+i]; + } + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) = 0xD0; + *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) = 0xD0; + v1=v2=0; +// _consolePrintf("WriteNorFlashINTEL begin 2\n"); + while((v1!= 0x80) || (v2 != 0x80) ) + { + v1 = *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1))) ; + v2 = *((vu16 *)(FlashBase+mapaddress+(loopwrite>>1)+0x2000)) ; + if( (v1==0x90) || (v2==0x90)) + { + WriteSram(0xA000000,(u8 *)buf,0x8000); +// _consolePrintf("Err \n"); + while(1); + break; + } + } +// _consolePrintf("WriteNorFlashINTEL begin 3\n"); + } + } + if(b512==true) + { + CloseNorWrite(); + SetRompage(0); + OpenNorWrite(); + } +} + +void WriteNorFlash(u32 address,u8 *buffer,u32 size) +{ + if(ID==0x89168916) + { + WriteNorFlashINTEL(address,buffer,size); + return; + } + vu16 v1,v2; + register u32 loopwrite ; + vu16* buf = (vu16*)buffer ; + u32 size2,lop; + u32 mapaddress; + u32 j; + v1=0;v2=1; + u32 off=0; + if( (address>=0x1000000) && (ID==0x227E2202)) + { + off=0x1000000; + } + else + off=0; + if(size>0x4000) + { + size2 = size >>1 ; + lop = 2; + } + else + { + size2 = size ; + lop = 1; + } + mapaddress = address; + for(j=0;j>2);loopwrite++) + { + *((vu16 *)(FlashBase+off+0x555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x2AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x555*2)) = 0xA0 ; + *((vu16 *)(FlashBase+mapaddress+loopwrite*2)) = buf[loopwrite]; + + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xAA ; + *((vu16 *)(FlashBase+off+0x12AA*2)) = 0x55 ; + *((vu16 *)(FlashBase+off+0x1555*2)) = 0xA0 ; + *((vu16 *)(FlashBase+mapaddress+0x2000+loopwrite*2)) = buf[0x1000+loopwrite]; + do + { + v1 = *((vu16 *)(FlashBase+mapaddress+loopwrite*2)) ; + v2 = *((vu16 *)(FlashBase+mapaddress+loopwrite*2)) ; + }while(v1!=v2); + do + { + v1 = *((vu16 *)(FlashBase+mapaddress+0x2000+loopwrite*2)) ; + v2 = *((vu16 *)(FlashBase+mapaddress+0x2000+loopwrite*2)) ; + }while(v1!=v2); + } + } +} +void WriteSram(uint32 address, u8* data , uint32 size ) +{ + uint32 i ; + for(i=0;i>1]=*(u8*)(address+i)+(*(u8*)(address+i+1)*0x100); + } +} + +void WritePSram(u8* address, u8* data , uint32 length ) +{ + vuint16 *pPatch=NULL; + pPatch=(vuint16*)address; + Enable_Arm7DS(); + CloseNorWrite(); + SetRompage(192); + OpenNorWrite(); + for(u32 pi=0;pi>1]= data[pi] + (data[pi+1]<<8); + + + } + CloseNorWrite(); + Enable_Arm9DS(); + +} +void ReadPSram(u8* address, u8* data , uint32 length ) +{ + vuint16 *pPatch=NULL; + pPatch=(vuint16*)address; + Enable_Arm7DS(); + CloseNorWrite(); + SetRompage(192); + OpenNorWrite(); + for(u32 pi=0;pi>1] & 0xff; + data[pi+1]=(pPatch[pi>>1] &0xff00)>>8; + + } + CloseNorWrite(); + Enable_Arm9DS(); + +} +void OpenRamWrite() +{ + *(vu16 *)0x9fe0000 = 0xd200; + *(vu16 *)0x8000000 = 0x1500; + *(vu16 *)0x8020000 = 0xd200; + *(vu16 *)0x8040000 = 0x1500; + *(vu16 *)0x9C40000 = 0xA500; + *(vu16 *)0x9fc0000 = 0x1500; +} + +void CloseRamWrite() +{ + *(vu16 *)0x9fe0000 = 0xd200; + *(vu16 *)0x8000000 = 0x1500; + *(vu16 *)0x8020000 = 0xd200; + *(vu16 *)0x8040000 = 0x1500; + *(vu16 *)0x9C40000 = 0xA200; + *(vu16 *)0x9fc0000 = 0x1500; +} +void SetShake(u16 data) +{ + *(vuint16 *)0x9fe0000 = 0xd200; + *(vuint16 *)0x8000000 = 0x1500; + *(vuint16 *)0x8020000 = 0xd200; + *(vuint16 *)0x8040000 = 0x1500; + *(vuint16 *)0x9E20000 = data; + *(vuint16 *)0x9fc0000 = 0x1500; +} +#ifdef __cplusplus +} +#endif diff --git a/arm9/source/dsCard.h b/arm9/source/dsCard.h new file mode 100644 index 0000000..6f345d1 --- /dev/null +++ b/arm9/source/dsCard.h @@ -0,0 +1,96 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * dsCard.h: header file for dsCard.cpp + * + * Copyright (C) EZFlash Group (2006) + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/************************************************************************************************************** + * 此文件为 dsCard.h 文件的第二版 + * 日期:2006年11月27日11点33分 第一版 version 1.0 + * 作者:aladdin + * CopyRight : EZFlash Group + * + **************************************************************************************************************/ + +#ifndef NDS_DSCARD_V2_INCLUDE +#define NDS_DSCARD_V2_INCLUDE + +#include "nds.h" + + #ifdef __cplusplus + extern "C" { + #endif + +#ifndef BYTE +typedef unsigned char BYTE; +#endif + +#ifndef WORD +typedef unsigned short WORD; +#endif + +#ifndef DWORD +typedef unsigned long DWORD; +#endif + +#ifndef BOOL +typedef bool BOOL ; +#endif +// export interface + + + + +//--------------------------------------------------- +//DS 卡 基本操作 + //Arm9 方面基本操作容许ARM7访问slot1 + void Enable_Arm7DS(void); + + //Arm9 方面基本操作容许ARM9访问slot1 + void Enable_Arm9DS(void); + + + //下面是访问震动卡的函数 +#define FlashBase 0x08000000 +#define _Ez5PsRAM 0x08000000 + void OpenNorWrite(); + void CloseNorWrite(); + void SetRompage(u16 page); + void SetRampage(u16 page); + void OpenRamWrite(); + void CloseRamWrite(); + void SetSerialMode(); + uint32 ReadNorFlashID(); + void chip_reset(); + void Block_Erase(u32 blockAdd); + void ReadNorFlash(u8* pBuf,u32 address,u16 len); + void WriteNorFlash(u32 address,u8 *buffer,u32 size); + void WriteSram(uint32 address, u8* data , uint32 size ); + void ReadSram(uint32 address, u8* data , uint32 size ); + void SetShake(u16 data); + void WritePSram(u8* address, u8* data , uint32 length ); + void ReadPSram(u8* address, u8* data , uint32 length ); + #ifdef __cplusplus + } + #endif +#endif diff --git a/arm9/source/fileselect.cpp b/arm9/source/fileselect.cpp new file mode 100644 index 0000000..a2c0a87 --- /dev/null +++ b/arm9/source/fileselect.cpp @@ -0,0 +1,191 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * fileselect.cpp: Functions for browsing files on the Flash Card. + * Also a happy collection of other file-related functions. + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "display.h" + +char fnames[256][256]; + +// --------------------------------------------------------------------------------- +void fileGetFileList(const char *dir, uint32 &num) +{ + DIR *pdir; + struct dirent *pent; + num = 0; + + pdir=opendir(dir); + + if (pdir) { + while ((pent=readdir(pdir)) !=NULL) { + sprintf(&fnames[num][0], "%s", pent->d_name); + num++; + if (num == 256) + break; + } + } + if (pdir) + closedir(pdir); +} + +void filePrintFileList(const char *dir, uint32 first, uint32 select, uint32 count, bool cancel = false) +{ + if (select < first) + select = first; + + consoleSelect(&lowerScreen); + consoleSetWindow(&lowerScreen, 0, 0, 32, 19); + consoleClear(); + + for (uint32 i = first; (i < first + 18) && (i < count); i++) { + struct stat statbuf; + char fullpath[512]; + sprintf(fullpath, "%s/%s", dir, fnames[i]); + stat(fullpath, &statbuf); + if (S_ISDIR(statbuf.st_mode)) { + if (i != select) + iprintf("[%.29s]\n", fnames[i]); + else + iprintf("-->[%.26s]\n", fnames[i]); + } else { + if (i != select) + iprintf("%.31s\n", fnames[i]); + else + iprintf("-->%.28s\n", fnames[i]); + } + } + + consoleSelect(&lowerScreen); + consoleSetWindow(&lowerScreen, 0, 18, 32, 6); + consoleClear(); + iprintf("================================"); + iprintf("Please select a .sav file\n"); + iprintf(" (A) Select\n"); + if (cancel) + iprintf(" (B) cancel"); +} + +// ========================***************************============================== +void fileSelect(const char *startdir, char *out_dir, char *out_fname, bool allow_cancel) +{ + bool select = false; + + uint32 num_files = 0; + uint32 sel_file = 0; + uint32 first_file = 0; + + // get list of files in current dir + fileGetFileList(startdir, num_files); + filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel); + + while (!select) { + // get_event + uint32 keys = keysCurrent(); + + // handle_event + if (keys & KEY_DOWN) { + if (sel_file < num_files-1) { + sel_file++; + filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel); + if (sel_file > first_file + 18) + first_file = sel_file - 18; + } + } else if (keys & KEY_UP) { + if (sel_file > 0) { + sel_file--; + filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel); + if (sel_file < first_file) + first_file = sel_file; + } + } else if (keys & KEY_A) { + // TODO: Okay, my first attempt at implementing a fuill file browser + // failed, so I am disabling changing directory for now. If anybody + // feels inclined to fix it, go ahead. + if (stricmp(fnames[sel_file], ".") == 0) + continue; + if (stricmp(fnames[sel_file], "..") == 0) + //return; + continue; + char fullname[512]; + sprintf(fullname, "%s/%s", startdir, fnames[sel_file]); + struct stat statbuf; + stat(fullname, &statbuf); + if (S_ISDIR(statbuf.st_mode)) { + /* + char fullpath[512]; + sprintf(fullpath, "%s/%s", startdir, fnames[sel_file]); + fileSelect(fullpath, out_dir, out_fname, allow_cancel); + for (int i = 0; i < 5; i++) + swiWaitForVBlank(); + if (strlen(out_fname)) + return; + */ + continue; + } else { + sprintf(out_dir, "%s", startdir); + sprintf(out_fname, "%s", fnames[sel_file]); + return; + } + select = true; + + } else if (keys & KEY_B) { + if (allow_cancel) { + sprintf(out_dir, "%s", startdir); + out_fname[0] = 0; + return; + } + } + + for (int i = 0; i < 5; i++) + swiWaitForVBlank(); + } +} + +// ------------------------------------------------------- +bool fileExists(const char *fname) +{ + struct stat statbuf; + if (stat(fname, &statbuf) != 0) + return false; + else + return true; +} + +uint32 fileSize(const char *fname) +{ + struct stat statbuf; + if (stat(fname, &statbuf) == 0) + return statbuf.st_size; + else + return 0; +} diff --git a/arm9/source/fileselect.h b/arm9/source/fileselect.h new file mode 100644 index 0000000..1d239aa --- /dev/null +++ b/arm9/source/fileselect.h @@ -0,0 +1,42 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * fileselect.h: header file for fileselect.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _FILE_SELECT +#define _FILE_SELECT + + +#define CONFIRMDELETE 5 +#define LOADBIN 4 +#define MAXBROWSERCYCLES 4 + +#define MAX_CUSTOM_LIST 8192 + + +void fileSelect(const char *startdir, char *out_dir, char *out_fname, bool allow_cancel = false); + +bool fileExists(const char *fname); +uint32 fileSize(const char *fname); + +#endif diff --git a/arm9/source/gba.cpp b/arm9/source/gba.cpp new file mode 100644 index 0000000..49bd497 --- /dev/null +++ b/arm9/source/gba.cpp @@ -0,0 +1,186 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * gba.cpp: Functions for working with the GBA-slot on a Nintendo DS. + * EZFlash 3-in-1 functions are found in dsCard.h/.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "gba.h" +#include "dsCard.h" + + +bool slot2Init() +{ + static bool doonce = false; + static bool init_3in1 = false; + + if (doonce) + return init_3in1; + + doonce = true; + OpenNorWrite(); + uint32 test = ReadNorFlashID(); + CloseNorWrite(); + + init_3in1 = test; + if (test) + return true; + else + return false; +} + + +// ----------------------------------------------------- +#define MAGIC_EEPR 0x52504545 +#define MAGIC_SRAM 0x4d415253 +#define MAGIC_FLAS 0x53414c46 + +#define MAGIC_H1M_ 0x5f4d3148 + +saveTypeGBA GetSlot2SaveType(cartTypeGBA type) { + if (type == CART_GBA_NONE) + return SAVE_GBA_NONE; + + // Search for any one of the magic version strings in the ROM. + uint32 *data = (uint32*)0x08000000; + + for (int i = 0; i < (0x02000000 >> 2); i++, data++) { + if (*data == MAGIC_EEPR) + return SAVE_GBA_EEPROM_8; // TODO: Try to figure out 512 bytes version... + if (*data == MAGIC_SRAM) + return SAVE_GBA_SRAM_32; + if (*data == MAGIC_FLAS) { + uint32 *data2 = data + 1; + if (*data2 == MAGIC_H1M_) + return SAVE_GBA_FLASH_128; + else + return SAVE_GBA_FLASH_64; + } + } + return SAVE_GBA_NONE; +}; + +cartTypeGBA GetSlot2Type(uint32 id) +{ + if (id == 0x53534150) + // All conventional GBA flash cards identify themselves as "PASS" + return CART_GBA_FLASH; + else { + return CART_GBA_GAME; + } +}; + +void IdentifySlot2(dataSlot2 &data) +{ +// FIXME... +#if 0 + // Identify an EZFlash 3in1 + OpenNorWrite(); + cartTypeGBA ezflash = slot2IsEZFlash3in1(data.ez_ID); + //chip_reset(); + CloseNorWrite(); + if (ezflash != CART_GBA_NONE) { + data.type = cartTypeGBA(ezflash); + return; // 3in1 has no classic save memory + } else { + // it's not a 3in1 + sGBAHeader *gba = (sGBAHeader*)0x08000000; + memcpy(&data.name[0], &gba->title[0], 12); + data.name[12] = 0; + memcpy(&data.iid, &gba->gamecode[0], 4); + data.cid[4] = 0; + data.type = GetSlot2Type(data.iid); + } + + data.save = GetSlot2SaveType(data.type); +#endif +}; + +// ----------------------------------------------------------- +bool gbaIsGame() +{ + // look for some magic bytes of the compressed Nintendo logo + uint32 *data = (uint32*)0x08000004; + + if (*data == 0x51aeff24) { + data ++; data ++; + if (*data == 0x0a82843d) + return true; + } + return false; +} + +uint8 gbaGetSaveType() +{ + // Search for any one of the magic version strings in the ROM. They are always dword-aligned. + uint32 *data = (uint32*)0x08000000; + + for (int i = 0; i < (0x02000000 >> 2); i++, data++) { + if (*data == MAGIC_EEPR) + return 1; // TODO: Try to figure out how to ID the 512 bytes version... + if (*data == MAGIC_SRAM) + return 3; + if (*data == MAGIC_FLAS) { + uint32 *data2 = data + 1; + if (*data2 == MAGIC_H1M_) + return 4; + else + return 5; + } + } + + return 0; +} + +uint32 gbaGetSaveSize(uint8 type) +{ + if (type == 255) + type = gbaGetSaveType(); + + switch (type) { + case 1: + return 512; // ??? + case 2: + return 8192; + case 3: + return 32768; + case 4: + return 65536; + case 5: + return 131072; + case 0: + default: + return 0; + } +} diff --git a/arm9/source/gba.h b/arm9/source/gba.h new file mode 100644 index 0000000..240c07c --- /dev/null +++ b/arm9/source/gba.h @@ -0,0 +1,71 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * gba.h: header file for gba.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __SLOT2_H__ +#define __SLOT2_H__ + +enum cartTypeGBA { + CART_GBA_NONE = 0, + CART_GBA_GAME, + CART_GBA_EMULATOR, + CART_GBA_3IN1_256_V1, + CART_GBA_3IN1_256_V2, + CART_GBA_3IN1_512_V3, + CART_GBA_FLASH +}; + +enum saveTypeGBA { + SAVE_GBA_NONE = 0, + SAVE_GBA_EEPROM_05 = 0x00010001, // 512 bytes + SAVE_GBA_EEPROM_8 = 0x00010002, // 8k + SAVE_GBA_SRAM_32 = 0x00020001, // 32k + SAVE_GBA_FLASH_64 = 0x00040001, // 64k + SAVE_GBA_FLASH_128 = 0x00040002 // 128k +}; + +struct dataSlot2 { + cartTypeGBA type; + saveTypeGBA save; + uint32 ez_ID; + union { + char cid[5]; + uint32 iid; + }; + char name[13]; +}; + + +cartTypeGBA GetSlot2Type(uint32 id); +saveTypeGBA GetSlot2SaveType(cartTypeGBA type); +void IdentifySlot2(dataSlot2 &data); + +bool slot2Init(); + +// -------------------- +bool gbaIsGame(); +uint8 gbaGetSaveType(); +uint32 gbaGetSaveSize(uint8 type = 255); + + +#endif // __SLOT2_H__ \ No newline at end of file diff --git a/arm9/source/hardware.cpp b/arm9/source/hardware.cpp new file mode 100644 index 0000000..ead96fe --- /dev/null +++ b/arm9/source/hardware.cpp @@ -0,0 +1,438 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * hardware.cpp: Functions used to communicate with slot-1 devices, including + * hotswap and identification of cartridges. + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "display.h" +#include "dsCard.h" +#include "gba.h" + +#include "hardware.h" + +#include "fileselect.h" + +#include "auxspi.h" + +using namespace std; + +uint32 boot; + +bool flash_card = true; // the homebrew will always start with a FC inserted +bool with_infrared = false; // ... which does not have an IR device + +u8 data[0x8000]; + +// --------------------------------------------------------------------- +bool swap_cart() +{ + sNDSHeader nds; + nds.gameTitle[0] = 0; + + while (!nds.gameTitle[0]) { + // this is an attempt to account for bad contacts, where "cardreadheader" returns nothing. + // since this problem disappeared after adding this (as usual), I don't know if it works + + displayMessage("Please take out Slot 1 flash\ncart and insert a game\n\nPress A when done."); + + bool swap = false; + while (!swap) { + if (keysCurrent() & KEY_A) { + // identify hardware + sysSetBusOwners(true, true); + cardReadHeader((u8*)&nds); + if (!nds.gameTitle[0]) + continue; + + // Look for an IR-enabled game cart first. If the save size returns something + // nonzero, we hae found an IR-enabled game and we are done. If there is no + // IR device present, "size2" is always zero. + with_infrared = true; + uint32 size2 = auxspi_save_size_log_2(); + if (size2) { + flash_card = false; + return true; + } + + // Second, test if this is a Flash Card, which has no save chip. Therefore, + // trying to identify this without IR-specific functions again returns zero. + with_infrared = false; + uint32 size1 = auxspi_save_size_log_2(); + if (!size1) { + flash_card = true; + return true; + } + + // No special hardware found, so it must be a regular game. + flash_card = false; + return true; + } + } + } + + return true; +} + +bool is_flash_card() +{ + return flash_card; +} + +// -------------------------------------------------------- +void hwFormatNor(uint32 page, uint32 count) +{ + chip_reset(); + OpenNorWrite(); + SetSerialMode(); + displayPrintState("Formating NOR memory"); + displayProgressBar(0, count); + for (int i = page; i < page+count; i++) { + Block_Erase(i << 18); + displayProgressBar(i+1, count); + } + CloseNorWrite(); +} + +// -------------------------------------------------------- +void hwBackup3in1() +{ + uint8 size = auxspi_save_size_log_2(); + int size_blocks = 1 << max(0, (int8(size) - 18)); // ... in units of 0x40000 bytes - that's 256 kB + uint8 type = auxspi_save_type(); + + hwFormatNor(0, size_blocks); + + // Dump save and write it to NOR + chip_reset(); + OpenNorWrite(); + displayPrintState("Writing save to NOR"); + if (size < 15) + size_blocks = 1; + else + size_blocks = 1 << (uint8(size) - 15); + for (int i = 0; i < size_blocks; i++) { + displayProgressBar(i+1, size_blocks); + auxspi_read_data(i << 15, data, 0x8000, type); + WriteNorFlash(i << 15, data, 0x8000); + } + CloseNorWrite(); + + // Write a flag to tell the app what happens on restart + sNDSHeader nds; + cardReadHeader((u8*)&nds); + dsCardData data2; + memset(&data2, 0, sizeof(data2)); + data2.data[0] = RS_BACKUP; + data2.data[1] = 0; + data2.data[2] = size; + data2.data[3] = 0xffff00ff; + memcpy(&data2.name[0], &nds.gameTitle[0], 12); + WriteSram(0x0a000000, (u8*)&data2, sizeof(data2)); + char txt[128]; + sprintf(txt, "%.12s", &nds.gameTitle[0]); + //memcpy(&txt[0], &nds.gameTitle[0], 12); + //displayPrintState(txt); + + displayMessage("Save has been written to 3in1.\nPlease power off and restart\nthis tool."); + + while(1) {}; +} + +void hwDump3in1(uint32 size, const char *gamename) +{ + displayPrintState("Writing file to flash card"); + + u32 size_blocks = 1 << max(0, (uint8(size) - 18)); + + char path[256]; + char fname[256] = ""; + //fileSelect("/", path, fname/*, true*/); + //if (!fname[0]) { + uint32 cnt = 0; + sprintf(fname, "/%s.%i.sav", gamename, cnt); + while (fileExists(fname)) { + if (cnt < 65536) + cnt++; + else { + displayMessage("Unable to get a filename!\nThis means that you have more\nthan 65536 saves! (wow!)\nOops!"); + while(1); + } + sprintf(fname, "/%s.%i.sav", gamename, cnt); + } + //} + char fullpath[512]; + //sprintf(fullpath, "%s/%s", path, fname); + sprintf(fullpath, "%s", fname); + displayMessage(fullpath); + + FILE *file = fopen(fullpath, "wb"); + //u8 *data = (u8*)malloc(0x8000); + if (size < 15) + size_blocks = 1; + else + size_blocks = 1 << (uint8(size) - 15); + for (u32 i = 0; i < size_blocks; i++) { + displayProgressBar(i+1, size_blocks); + u32 LEN = 0x8000; + ReadNorFlash(data, i << 15, LEN); + fwrite(data, 1, LEN, file); + //if (j != LEN) + //iprintf ("WRITE ERROR %i\n", errno); + } + //free(data); + fclose(file); + + displayPrintState("Done! Please power off..."); + while (1); +} + +void hwRestore3in1() +{ + char path[256]; + char fname[256]; + displayMessage("Please select a .sav file."); + fileSelect("/", path, fname); + displayMessage(""); + char msg[256]; + sprintf(msg, "%s%s", path, fname); + + FILE *file = fopen(msg, "rb"); + uint32 size0 = fileSize(msg); + uint8 size = 1; + while (size0 > (1 << size)) { + size++; + } + int size_blocks = 1 << max(0, int8(size) - 18); // ... in units of 0x40000 bytes - that's 256 kB + + hwFormatNor(0, size_blocks); + + // Read save and write it to NOR + chip_reset(); + OpenNorWrite(); + SetSerialMode(); + displayPrintState("Writing save to NOR"); + if (size < 15) + size_blocks = 1; + else + size_blocks = 1 << (uint8(size) - 15); + for (int i = 0; i < size_blocks; i++) { + displayProgressBar(i+1, size_blocks); + fread(data, 1, 0x8000, file); + WriteNorFlash(i << 15, data, 0x8000); + } + CloseNorWrite(); + fclose(file); + + // FIXME: for some weird reason, reading the save written to NOR right now managed to mangle + // precisely 2 bytes in my HG save, but not in my Platinum one. Therefore, we need to + // make this a two-stage process as well, to prevent this weitd glitch. + // (It appears in two different hardware revisions of the 3in1!) + + // Write a flag to tell the app what happens on restart + sNDSHeader nds; + cardReadHeader((u8*)&nds); + dsCardData data2; + memset(&data2, 0, sizeof(data2)); + data2.data[0] = RS_BACKUP; + data2.data[1] = 0; + data2.data[2] = size; + data2.data[3] = 0xbad00bad; + WriteSram(0x0a000000, (u8*)&data2, sizeof(data2)); + + displayMessage("Thanks to some crazy bug,\nyou will need to restart your\nDS and this app. Sorry."); + while(0); +} + +void hwRestore3in1_b(uint32 size) +{ + + // Third, swap in a new game + swap_cart(); + displayPrintUpper(); + + uint8 type = auxspi_save_type(); + if (type == 3) { + displayPrintState("Formating Flash chip"); + auxspi_erase(); + } + + // And finally, write the save! + displayPrintState("Restoring save"); + u32 LEN = 0, num_blocks = 0, shift = 0; + switch (type) { + case 1: + shift = 4; // 16 bytes + break; + case 2: + shift = 5; // 32 bytes + break; + case 3: + shift = 8; // 256 bytes + break; + default: + return; + } + LEN = 1 << shift; + num_blocks = 1 << (size - shift); + //data = (u8*)malloc(LEN); + + chip_reset(); + OpenNorWrite(); + SetSerialMode(); + for (unsigned int i = 0; i < num_blocks; i++) { + if (i % (num_blocks >> 6) == 0) + displayProgressBar(i+1, num_blocks); + ReadNorFlash(data, i << shift, LEN); + auxspi_write_data(i << shift, data, LEN, type); + } + CloseNorWrite(); + displayProgressBar(1, 1); + + + displayPrintState("Done! Please turn your DS off..."); + + while (1) {}; +} + +void hwErase() +{ + displayMessage("This will WIPE OUT your entire\nsave! ARE YOU SURE?\n\nPress R+up+Y to confim!"); + while (!(keysCurrent() & (KEY_UP | KEY_R | KEY_Y))) {}; + auxspi_erase(); + displayMessage("Done! Your save is gone!"); + while(0); +} + +// ------------------------------------------------------------ +void hwBackupGBA() +{ + // TODO: test this, implement missing bits! + return; + + // TODO: select filename + char fullname[512]; + + u8 type = gbaGetSaveType(); + if (type == 0) + return; + uint32 size = gbaGetSaveSize(type); + u8 nbanks = 2; + + switch (type) { + case 1: + case 2: + // TODO: how to address this one? + return; + case 3: { + // SRAM - this is easy, just functions like conventional RAM + FILE *file = fopen(&fullname[0], "wb"); + for (u32 i = 0; i < size; i++) { + fwrite((u8*)(0x0e000000+i), 1, 1, file); + } + fclose(file); + return; + } + case 4: + nbanks = 1; + case 5: { + // FLASH - must be opened by register magic + FILE *file = fopen(&fullname[0], "wb"); + for (int j = 0; j < nbanks; j++) { + *(u8*)0x0e005555 = 0xaa; + *(u8*)0x0e002aaa = 0x55; + *(u8*)0x0e005555 = 0xb0; + *(u8*)0x0e000000 = j; + for (int i = 0; i < 0x10000; i++) { + fwrite((u8*)(0x0e000000+i), 1, 1, file); + } + } + fclose(file); + return; + } + } +} + +void hwRestoreGBA() +{ + // TODO: test this, implement missing bits! + return; + + // TODO: select filename + char fullname[512]; + + u8 type = gbaGetSaveType(); + if (type == 0) + return; + uint32 size = gbaGetSaveSize(type); + u8 nbanks = 2; + + switch (type) { + case 1: + case 2: + // TODO: how to address this one? + return; + case 3: { + // SRAM - this is easy, just functions like conventional RAM + FILE *file = fopen(&fullname[0], "rb"); + u8 *data = (u8*)malloc(size); + fread(&data[0], 1, size, file); + for (u32 i = 0; i < size; i++) { + *(u8*)(0x0e000000+i) = data[i]; + } + free(data); + fclose(file); + return; + } + case 4: + nbanks = 1; + case 5: { + // FLASH - must be opened by register magic + FILE *file = fopen(&fullname[0], "wb"); + for (int j = 0; j < nbanks; j++) { + *(u8*)0x0e005555 = 0xaa; + *(u8*)0x0e002aaa = 0x55; + *(u8*)0x0e005555 = 0xb0; + *(u8*)0x0e000000 = j; + for (int i = 0; i < 0x10000; i++) { + fwrite((u8*)(0x0e000000+i), 1, 1, file); + } + } + fclose(file); + return; + } + } +} + +void hwEraseGBA() +{ + // TODO: implement chip erase! +} diff --git a/arm9/source/hardware.h b/arm9/source/hardware.h new file mode 100644 index 0000000..b8696f6 --- /dev/null +++ b/arm9/source/hardware.h @@ -0,0 +1,63 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * hardware.h: header file for header.cpp + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HARDWARE_H +#define HARDWARE_H + +#include +#include + +#define RS_BACKUP 0x4b434142 + +extern uint32 boot; + +extern bool flash_card; + +struct dsCardData +{ + uint32 data[4]; + char name[12]; +}; + +void do_dump_nds_save_stage_1(); +void do_dump_nds_save_stage_2(int size); +void do_restore_nds_save(); + +bool swap_cart(); +bool is_flash_card(); + +void hwBackup3in1(); +void hwDump3in1(uint32 size, const char *gamename); +void hwRestore3in1(); +void hwRestore3in1_b(uint32 size); +void hwErase(); + +void hwBackupGBA(); +void hwRestoreGBA(); +void hwEraseGBA(); + +void hwFormatNor(uint32 page, uint32 count); + +#endif diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp new file mode 100644 index 0000000..13bdb3b --- /dev/null +++ b/arm9/source/main.cpp @@ -0,0 +1,200 @@ +/* + * savegame_manager: a tool to backup and restore savegames from Nintendo + * DS cartridges. Nintendo DS and all derivative names are trademarks + * by Nintendo. EZFlash 3-in-1 is a trademark by EZFlash. + * + * main.cpp: main file + * + * Copyright (C) Pokedoc (2010) + */ +/* + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "gba.h" +#include "display.h" +#include "dsCard.h" +#include "hardware.h" +#include "fileselect.h" + + + +uint32 ezflash = 0; +uint32 dstype = 0; +bool gba = 0; +uint32 mode = 0; + + + +// ============================================================================ +void mode_dsi() +{ + // DSi mode, does nothing at the moment + displayPrintState("DSi mode - unsupported!"); + while (1); +} + +void mode_3in1() +{ + displayPrintUpper(); + + dsCardData data2; + ReadSram(0x0a000000, (u8*)&data2, sizeof(data2)); + if ((data2.data[0] == RS_BACKUP) && (data2.data[1] == 0) && (data2.data[3] == 0xffff00ff)) { + uint32 size = data2.data[2]; + char name[13]; + memcpy(&name[0], &data2.name[0], 12); + name[12] = 0; + memset(&data2, 0, sizeof(data2)); + WriteSram(0x0a000000, (u8*)&data2, sizeof(data2)); + hwDump3in1(size, name); + } else if ((data2.data[0] == RS_BACKUP) && (data2.data[1] == 0) && (data2.data[3] == 0xbad00bad)) { + uint32 size = data2.data[2]; + char name[13]; + memcpy(&name[0], &data2.name[0], 12); + name[12] = 0; + memset(&data2, 0, sizeof(data2)); + WriteSram(0x0a000000, (u8*)&data2, sizeof(data2)); + hwRestore3in1_b(size); + } + + // use 3in1 to buffer data + displayPrintState("3in1 mode"); + displayPrintUpper(); + displayPrintLower(); + + touchPosition touchXY; + while(1) { + swiWaitForVBlank(); + touchRead(&touchXY); + + // backup + if ((touchXY.py > 8*0) && (touchXY.py < 8*8)) { + swap_cart(); + displayPrintUpper(); + hwBackup3in1(); + } + + // restore + if ((touchXY.py > 8*8) && (touchXY.py < 8*16)) { + hwRestore3in1(); + } + + // erase + if ((touchXY.py > 8*16) && (touchXY.py < 8*24)) { + swap_cart(); + displayPrintUpper(); + hwErase(); + } + } +} + +void mode_gba() +{ + // use 3in1 to buffer data + displayPrintState("gba mode"); + displayPrintUpper(); + displayPrintLower(); + + touchPosition touchXY; + while(1) { + swiWaitForVBlank(); + touchRead(&touchXY); + + // backup + if ((touchXY.py > 8*0) && (touchXY.py < 8*8)) { + displayPrintUpper(); + hwBackupGBA(); + //hwBackup3in1(); + } + + // restore + if ((touchXY.py > 8*8) && (touchXY.py < 8*16)) { + displayPrintUpper(); + hwRestoreGBA(); + } + + // erase + if ((touchXY.py > 8*16) && (touchXY.py < 8*24)) { + displayPrintUpper(); + hwEraseGBA(); + } + } +} + +void mode_wifi() +{ + // read/write to ftp server, does nothing at the moment + displayPrintState("FTP mode - unsupported!"); + while (1); +} + +int main(void) +{ + sysSetBusOwners(true, true); + + // Init the screens + displayInit(); + + // Init DLDI (file system driver) + int fat = fatInitDefault(); + if (fat == 0) { + displayPrintState("DLDI error\n"); + while (1) {}; + } + + // TODO: load ini file... + + // Identify hardware and branch to corresponding mode + displayPrintState("Identifying hardware..."); + OpenNorWrite(); + ezflash = ReadNorFlashID(); + CloseNorWrite(); + dstype = 0; // DS/DSL, no idea how to identify DSi etc. + gba = gbaIsGame(); + + if (dstype == 1) { + // DSi/DSiXL, will branch to SD-card mode when cracked. + mode = 3; + mode_dsi(); + } else if (ezflash != 0) { + // DS with EZFlash found -> branch to 3in1 mode + mode = 2; + mode_3in1(); + } else if (gba) { + // GBA game in slot 2 -> branch to GBA mode + mode = 1; + mode_gba(); + } else { + // failsafe: enter WiFi mode + mode = 0; + mode_wifi(); + } + + return 0; +} diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/license.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/savegame_manager.pnproj b/savegame_manager.pnproj new file mode 100644 index 0000000..68ea4f5 --- /dev/null +++ b/savegame_manager.pnproj @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/savegame_manager.pnps b/savegame_manager.pnps new file mode 100644 index 0000000..14f54a4 --- /dev/null +++ b/savegame_manager.pnps @@ -0,0 +1 @@ + \ No newline at end of file