├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── arm7 ├── Makefile └── source │ └── main.cpp ├── arm9 ├── Makefile ├── include │ ├── ID.h │ ├── app.h │ ├── file_browse.h │ └── util.h └── source │ ├── app.cpp │ ├── file_browse.cpp │ ├── main.cpp │ └── util.cpp ├── b2s_upscaled.png └── icon.bmp /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | *.nds 3 | */build 4 | .vscode 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 vrodin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | export TARGET := Burn2Slot 11 | export TOPDIR := $(CURDIR) 12 | 13 | 14 | .PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf 15 | 16 | #--------------------------------------------------------------------------------- 17 | # main targets 18 | #--------------------------------------------------------------------------------- 19 | all: $(TARGET).nds 20 | 21 | #--------------------------------------------------------------------------------- 22 | $(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf 23 | ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \ 24 | -b icon.bmp "Burn2Slot;VROdin" 25 | 26 | #--------------------------------------------------------------------------------- 27 | arm7/$(TARGET).elf: 28 | $(MAKE) -C arm7 29 | 30 | #--------------------------------------------------------------------------------- 31 | arm9/$(TARGET).elf: 32 | $(MAKE) -C arm9 33 | 34 | #--------------------------------------------------------------------------------- 35 | clean: 36 | $(MAKE) -C arm9 clean 37 | $(MAKE) -C arm7 clean 38 | rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Burn2Slot 2 | 3 | **Burn2Slot** is a Nintendo DS homebrew utility that allows you to reflash Game Boy Advance (GBA) bootleg cartridges through Slot-2. This is a convenient solution for rewriting compatible GBA carts directly from a DS or DS Lite, without the need for external hardware or a PC. 4 | 5 | --- 6 | 7 | ## 📦 Features 8 | 9 | - Flash `.gba` ROMs onto writable GBA bootleg cartridges 10 | - Runs from Slot-1 flashcarts (e.g. R4, Acekard) 11 | - Works on Nintendo DS and DS Lite 12 | - Fast and easy ROM programming via on-screen menu 13 | 14 | --- 15 | 16 | ## 🧰 Requirements 17 | 18 | - Nintendo DS or DS Lite 19 | - Slot-1 flashcart (e.g. R4, Acekard, etc.) 20 | - Writable GBA bootleg cartridge in Slot-2 21 | - GBA ROMs (must fit within cart capacity, e.g., 8 MB or 16 MB) 22 | 23 | --- 24 | 25 | ## 🚀 How to Use 26 | 27 | 1. Place `Burn2Slot.nds` on your Slot-1 flashcart. 28 | 2. Add your desired `.gba` ROM file(s) to the flashcart. 29 | 3. Insert a compatible bootleg GBA cartridge into Slot-2. 30 | 4. Launch `Burn2Slot.nds` from the DS menu. 31 | 5. Follow the on-screen instructions to select and flash the ROM. 32 | 33 | > ⚠️ This process will overwrite the contents of your bootleg GBA cart. Proceed with caution. 34 | 35 | --- 36 | 37 | ## 🛠️ Building from Source 38 | 39 | ```bash 40 | git clone https://github.com/vrodin/Burn2Slot.git 41 | cd Burn2Slot 42 | make 43 | ``` 44 | 45 | --- 46 | 47 | ## 🛠️ Dependencies 48 | 49 | - [devkitPro](https://devkitpro.org/) 50 | - devkitARM 51 | - libnds 52 | 53 | Make sure your environment variables (`DEVKITPRO` and `DEVKITARM`) are correctly set. 54 | 55 | --- 56 | 57 | ## 🧪 Compatibility 58 | 59 | - Bootleg GBA cartridges with NOR flash 60 | - Recommended sizes: **8 MB**, **16 MB**, possibly **32 MB** 61 | - Does *not* support EEPROM or SRAM-based flash carts 62 | 63 | Not all bootleg cartridges are supported. Compatibility may vary depending on manufacturer and flash chip. 64 | 65 | --- 66 | 67 | ## 🙌 Credits 68 | 69 | Developed by [vrodin](https://github.com/vrodin) 70 | 71 | Inspired by other DS/GBA homebrew flasher projects. 72 | 73 | --- 74 | 75 | ## Research and References 76 | 77 | - [Console Technical Info](http://problemkaputt.de/gbatek.htm) 78 | - [Common Flash Memory Interface](https://en.wikipedia.org/wiki/Common_Flash_Memory_Interface) 79 | - [Flash Memory Interface](https://www.fujitsu.com/downloads/MICRO/fmal/e-ds/e520904.pdf) 80 | - [cartreader by sanni](https://github.com/sanni/cartreader) 81 | - [nds-gbabf by nflsilva](https://github.com/nflsilva/nds-gbabf) 82 | - [gbabf by Fexean](https://gitlab.com/Fexean/gbabf) 83 | - [GBxCart-RW by insidegadgets](https://github.com/insidegadgets/GBxCart-RW) 84 | -------------------------------------------------------------------------------- /arm7/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include build 20 | DATA := 21 | 22 | #--------------------------------------------------------------------------------- 23 | # options for code generation 24 | #--------------------------------------------------------------------------------- 25 | ARCH := -mthumb-interwork 26 | 27 | CFLAGS := -g -Wall -O3\ 28 | -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ 29 | -ffast-math \ 30 | $(ARCH) 31 | 32 | CFLAGS += $(INCLUDE) -DARM7 33 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti 34 | 35 | 36 | ASFLAGS := -g $(ARCH) 37 | LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map 38 | 39 | LIBS := -lnds7 40 | 41 | #--------------------------------------------------------------------------------- 42 | # list of directories containing libraries, this must be the top level containing 43 | # include and lib 44 | #--------------------------------------------------------------------------------- 45 | LIBDIRS := $(LIBNDS) 46 | 47 | 48 | #--------------------------------------------------------------------------------- 49 | # no real need to edit anything past this point unless you need to add additional 50 | # rules for different file extensions 51 | #--------------------------------------------------------------------------------- 52 | ifneq ($(BUILD),$(notdir $(CURDIR))) 53 | #--------------------------------------------------------------------------------- 54 | 55 | export ARM7ELF := $(CURDIR)/$(TARGET).elf 56 | export DEPSDIR := $(CURDIR)/$(BUILD) 57 | 58 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 59 | 60 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 61 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 62 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 63 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 64 | 65 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 66 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 67 | 68 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 69 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 70 | -I$(CURDIR)/$(BUILD) 71 | 72 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 73 | 74 | #--------------------------------------------------------------------------------- 75 | # use CXX for linking C++ projects, CC for standard C 76 | #--------------------------------------------------------------------------------- 77 | ifeq ($(strip $(CPPFILES)),) 78 | #--------------------------------------------------------------------------------- 79 | export LD := $(CC) 80 | #--------------------------------------------------------------------------------- 81 | else 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CXX) 84 | #--------------------------------------------------------------------------------- 85 | endif 86 | #--------------------------------------------------------------------------------- 87 | 88 | .PHONY: $(BUILD) clean 89 | 90 | #--------------------------------------------------------------------------------- 91 | $(BUILD): 92 | @[ -d $@ ] || mkdir -p $@ 93 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 94 | 95 | #--------------------------------------------------------------------------------- 96 | clean: 97 | @echo clean ... 98 | @rm -fr $(BUILD) *.elf 99 | 100 | 101 | #--------------------------------------------------------------------------------- 102 | else 103 | 104 | DEPENDS := $(OFILES:.o=.d) 105 | 106 | #--------------------------------------------------------------------------------- 107 | # main targets 108 | #--------------------------------------------------------------------------------- 109 | $(ARM7ELF) : $(OFILES) 110 | @echo linking $(notdir $@) 111 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 112 | 113 | 114 | #--------------------------------------------------------------------------------- 115 | # you need a rule like this for each extension you use as binary data 116 | #--------------------------------------------------------------------------------- 117 | %.bin.o : %.bin 118 | #--------------------------------------------------------------------------------- 119 | @echo $(notdir $<) 120 | @$(bin2o) 121 | 122 | -include $(DEPENDS) 123 | 124 | #--------------------------------------------------------------------------------------- 125 | endif 126 | #--------------------------------------------------------------------------------------- 127 | -------------------------------------------------------------------------------- /arm7/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | void BootGbaARM7(u32 useBottomScreen) 7 | { 8 | u8 powcnt; 9 | 10 | if(useBottomScreen) { 11 | powcnt = 5; 12 | } 13 | else { 14 | powcnt = 9; 15 | } 16 | 17 | REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz | SPI_CONTINUOUS; 18 | REG_SPIDATA = 0; 19 | SerialWaitBusy(); 20 | 21 | REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz; 22 | REG_SPIDATA = powcnt; 23 | SerialWaitBusy(); 24 | 25 | 26 | REG_IME = 0; 27 | REG_IE = 0; 28 | while(REG_VCOUNT != 200); // Wait for VBlank 29 | // enter GBA mode 30 | asm volatile ( 31 | "mov r2,#0x40\n" 32 | "swi 0x1f0000\n" 33 | : 34 | : 35 | : "r2" 36 | ); 37 | 38 | } 39 | 40 | void VcountHandler() 41 | { 42 | inputGetAndSend(); 43 | } 44 | 45 | volatile bool exitflag = false; 46 | 47 | void powerButtonCB() 48 | { 49 | exitflag = true; 50 | } 51 | 52 | int main() 53 | { 54 | readUserSettings(); 55 | 56 | irqInit(); 57 | fifoInit(); 58 | SetYtrigger(80); 59 | installSystemFIFO(); 60 | 61 | irqSet(IRQ_VCOUNT, VcountHandler); 62 | 63 | irqEnable( IRQ_VBLANK | IRQ_VCOUNT); 64 | setPowerButtonCB(powerButtonCB); 65 | 66 | while(!exitflag) 67 | { 68 | //swiWaitForVBlank(); 69 | 70 | if(fifoCheckValue32(FIFO_USER_01)){ 71 | u32 screen = fifoGetValue32(FIFO_USER_01); 72 | irqDisable(IRQ_ALL); 73 | BootGbaARM7(screen); 74 | } 75 | 76 | swiIntrWait(1,IRQ_FIFO_NOT_EMPTY); 77 | } 78 | } 79 | 80 | 81 | -------------------------------------------------------------------------------- /arm9/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include 20 | DATA := 21 | 22 | 23 | #--------------------------------------------------------------------------------- 24 | # options for code generation 25 | #--------------------------------------------------------------------------------- 26 | ARCH := #-mthumb -mthumb-interwork 27 | 28 | CFLAGS := -g -Wall -O3\ 29 | -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ 30 | -ffast-math \ 31 | $(ARCH) 32 | 33 | CFLAGS += $(INCLUDE) -DARM9 34 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 35 | 36 | ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s 37 | 38 | LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 39 | 40 | #--------------------------------------------------------------------------------- 41 | # any extra libraries we wish to link with the project 42 | #--------------------------------------------------------------------------------- 43 | LIBS := -lfat -lnds9 44 | 45 | #--------------------------------------------------------------------------------- 46 | # list of directories containing libraries, this must be the top level containing 47 | # include and lib 48 | #--------------------------------------------------------------------------------- 49 | LIBDIRS := $(LIBNDS) 50 | 51 | #--------------------------------------------------------------------------------- 52 | # no real need to edit anything past this point unless you need to add additional 53 | # rules for different file extensions 54 | #--------------------------------------------------------------------------------- 55 | ifneq ($(BUILD),$(notdir $(CURDIR))) 56 | #--------------------------------------------------------------------------------- 57 | 58 | export ARM9ELF := $(CURDIR)/$(TARGET).elf 59 | export DEPSDIR := $(CURDIR)/$(BUILD) 60 | 61 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 62 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 63 | 64 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 65 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 66 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 67 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 68 | 69 | #--------------------------------------------------------------------------------- 70 | # use CXX for linking C++ projects, CC for standard C 71 | #--------------------------------------------------------------------------------- 72 | ifeq ($(strip $(CPPFILES)),) 73 | #--------------------------------------------------------------------------------- 74 | export LD := $(CC) 75 | #--------------------------------------------------------------------------------- 76 | else 77 | #--------------------------------------------------------------------------------- 78 | export LD := $(CXX) 79 | #--------------------------------------------------------------------------------- 80 | endif 81 | #--------------------------------------------------------------------------------- 82 | 83 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 84 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 85 | 86 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 87 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 88 | -I$(CURDIR)/$(BUILD) 89 | 90 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 91 | 92 | .PHONY: $(BUILD) clean 93 | 94 | #--------------------------------------------------------------------------------- 95 | $(BUILD): 96 | @[ -d $@ ] || mkdir -p $@ 97 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 98 | 99 | #--------------------------------------------------------------------------------- 100 | clean: 101 | @echo clean ... 102 | @rm -fr $(BUILD) *.elf *.nds* *.bin 103 | 104 | 105 | #--------------------------------------------------------------------------------- 106 | else 107 | 108 | #--------------------------------------------------------------------------------- 109 | # main targets 110 | #--------------------------------------------------------------------------------- 111 | $(ARM9ELF) : $(OFILES) 112 | @echo linking $(notdir $@) 113 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 114 | 115 | #--------------------------------------------------------------------------------- 116 | # you need a rule like this for each extension you use as binary data 117 | #--------------------------------------------------------------------------------- 118 | %.bin.o : %.bin 119 | #--------------------------------------------------------------------------------- 120 | @echo $(notdir $<) 121 | @$(bin2o) 122 | 123 | -include $(DEPSDIR)/*.d 124 | 125 | #--------------------------------------------------------------------------------------- 126 | endif 127 | #--------------------------------------------------------------------------------------- 128 | -------------------------------------------------------------------------------- /arm9/include/ID.h: -------------------------------------------------------------------------------- 1 | #define ALLIANCE_ID 0x52 2 | #define ATMEL_ID 0x1F 3 | #define FUJITSU_ID 0x04 4 | #define INTEL_ID 0x89 5 | #define MACRONIX_ID 0xC2 6 | #define SANYO_ID 0x62 7 | #define SHARP_ID 0xB0 8 | #define SPANSION_ID 0x01 9 | #define SST_ID 0xBF 10 | #define ST_ID 0x20 11 | #define WINBOND_ID 0xDA 12 | #define MITSUBISHI_ID 0x1C 13 | 14 | char* manufactur = (char*)malloc(sizeof(char) * 12); 15 | 16 | static char* getManufacturByID(u8 ID) 17 | { 18 | switch(ID) { 19 | case ALLIANCE_ID: 20 | manufactur = "Alliance"; 21 | break; 22 | case ATMEL_ID: 23 | manufactur = "Atmel"; 24 | break; 25 | case FUJITSU_ID: 26 | manufactur = "Fujitsu"; 27 | break; 28 | case INTEL_ID: 29 | manufactur = "Intel"; 30 | break; 31 | case MACRONIX_ID: 32 | manufactur = "Macronix"; 33 | case SHARP_ID: 34 | manufactur = "Sharp"; 35 | break; 36 | case SPANSION_ID: 37 | manufactur = "Spansion"; 38 | break; 39 | case SST_ID: 40 | manufactur = "SST"; 41 | break; 42 | case ST_ID: 43 | manufactur = "ST"; 44 | break; 45 | case WINBOND_ID: 46 | manufactur = "Winbond"; 47 | break; 48 | case MITSUBISHI_ID: 49 | manufactur = "Mitsubishi"; 50 | break; 51 | default: 52 | manufactur = "Unknown"; 53 | } 54 | 55 | return manufactur; 56 | } 57 | -------------------------------------------------------------------------------- /arm9/include/app.h: -------------------------------------------------------------------------------- 1 | #ifndef _APP_H_ 2 | #define _APP_H_ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "nds.h" 13 | #include "fat.h" 14 | #include "file_browse.h" 15 | 16 | #define WAIT_STATUS_READY [](u16 a){return (a | 0xFF7F) != 0xFFFF;} 17 | #define WAIT_NON_FFFF [](u16 a){return a!=0xFFFF;} 18 | #define WAIT_FOR_FFFF [](u16 a){return a==0xFFFF;} 19 | #define WAIT_NON_0 [](u16 a){return a!=0;} 20 | #define WAIT_FOR_0 [](u16 a){return a==0;} 21 | 22 | const u32 TIMEOUT_5S = 0xA00000; 23 | const u32 TIMEOUT_8S = 0xF00000; 24 | 25 | typedef struct{ 26 | u8 busType; 27 | union { 28 | u8 intelType; 29 | u8 adressSeqType; 30 | }; 31 | 32 | u16 flashid; 33 | u16 manufactorID; 34 | u16 bufferSize; 35 | u32 size; 36 | } CartInfo; 37 | 38 | bool flashRepro_GBA(); 39 | 40 | #endif//_APP_H_ 41 | -------------------------------------------------------------------------------- /arm9/include/file_browse.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | Copyright (C) 2005 - 2017 3 | Michael "Chishm" Chisholm 4 | Dave "WinterMute" Murphy 5 | 6 | This program is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU General Public License 8 | as published by the Free Software Foundation; either version 2 9 | of the License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | 20 | ------------------------------------------------------------------*/ 21 | 22 | #ifndef FILE_BROWSE_H 23 | #define FILE_BROWSE_H 24 | 25 | #include 26 | #include 27 | 28 | std::string browseForFile (const std::vector& extensionList); 29 | 30 | 31 | 32 | #endif //FILE_BROWSE_H 33 | -------------------------------------------------------------------------------- /arm9/include/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void initGraphics(); 6 | void printTop(const char* str, ...); 7 | void BootGbaARM9(u32 useBottomScreen);//, cBMP15& border); 8 | 9 | -------------------------------------------------------------------------------- /arm9/source/app.cpp: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | #include "util.h" 3 | #include "ID.h" 4 | 5 | #define WRITE_BUS_COUNT 6 6 | #define ADD_SEQ_COUNT 6 7 | u8* sdBuffer = (u8*)malloc(sizeof(u8) * 512); 8 | CartInfo* cart = (CartInfo*)malloc(sizeof(CartInfo) + 1); 9 | 10 | u32 seq_0[] = { 0x555, 0x2AA, 0x555, 0x555, 0x2AA, 0x555}; 11 | u32 seq_1[] = { 0xAAA, 0x555, 0xAAA, 0xAAA, 0x555, 0xAAA}; 12 | u32 seq_2[] = { 0xAAA, 0x554, 0xAAA, 0xAAA, 0x554, 0xAAA}; 13 | u32 seq_3[] = { 0x5555, 0x2AAA, 0x5555, 0x5555, 0x2AAA, 0x5555}; 14 | u32 seq_4[] = { 0xAAAA, 0x5554, 0xAAAA, 0xAAAA, 0x5554, 0xAAAA}; 15 | u32 seq_5[] = { 0x1554, 0xAAA, 0x1554, 0x1554, 0xAAA, 0x1554}; 16 | 17 | 18 | u8 bus_1[] = { 15, 7, 14, 6, 13, 5, 12, 4, 0, 8, 1, 9, 2, 10, 3, 11}; 19 | u8 bus_2[] = { 0, 8, 1, 9, 6, 14, 7, 15, 2, 10, 3, 11, 4, 12, 5, 13}; 20 | u32 fileSize = 0; 21 | u16 bufferSize = 0; 22 | FILE* fd; 23 | 24 | u32 lag = 0xF; 25 | 26 | void wait(u32 count = 1) 27 | { 28 | while(count) { 29 | asm("nop"); 30 | count--; 31 | } 32 | } 33 | 34 | u16 swapBits(u16 data) 35 | { 36 | u16 bit1 = (data >> 0) & 1; 37 | u16 bit2 = (data >> 1) & 1; 38 | u16 x = (bit1 ^ bit2); 39 | x = (x << 0) | (x << 1); 40 | u16 result = data ^ x; 41 | return result; 42 | } 43 | 44 | u16 swapTo(u8 *bus, u16 data) 45 | { 46 | u16 result = 0; 47 | for(int i = 0; i < 16; ++i) { 48 | result |= ((data >> i) & 1) << bus[i]; 49 | } 50 | 51 | return result; 52 | } 53 | 54 | u16 swapFrom(u8 *bus, u16 data) 55 | { 56 | u16 result = 0; 57 | for(int i = 0; i < 16; ++i) { 58 | result |= ((data >> bus[i]) & 1) << i; 59 | } 60 | 61 | return result; 62 | } 63 | 64 | u16 read_word_rom(u32 address) 65 | { 66 | return GBAROM[address]; 67 | } 68 | 69 | u16 read_swapped_word_rom(u32 address) 70 | { 71 | return swapBits(read_word_rom(address)); 72 | } 73 | 74 | u16 read_swapped_word_rom_bus_1(u32 address) 75 | { 76 | return swapFrom(bus_1, read_word_rom(address)); 77 | } 78 | 79 | u16 read_swapped_word_rom_bus_2(u32 address) 80 | { 81 | return swapFrom(bus_2, read_word_rom(address)); 82 | } 83 | 84 | void write_word_rom(u32 address, u16 byte) 85 | { 86 | GBA_BUS[address] = byte; 87 | wait(lag); 88 | } 89 | 90 | void write_swapped_word_rom(u32 address, u16 byte) 91 | { 92 | write_word_rom(address, swapBits(byte)); 93 | } 94 | 95 | void write_swapped_word_rom_bus_1(u32 address, u16 byte) 96 | { 97 | write_word_rom(address, swapTo(bus_1, byte)); 98 | } 99 | 100 | void write_swapped_word_rom_bus_2(u32 address, u16 byte) 101 | { 102 | write_word_rom(address, swapTo(bus_2, byte)); 103 | } 104 | 105 | void write_doubled_word(u32 address, u16 byte) 106 | { 107 | write_word_rom(address, byte << 8 | byte); 108 | } 109 | 110 | void write_swapped_doubled_word(u32 address, u16 byte) 111 | { 112 | write_swapped_word_rom(address, byte << 8 | byte); 113 | } 114 | 115 | void ( *( write_word() ) )(u32 address, u16 byte) 116 | { 117 | switch(cart->busType) { 118 | case 0: return write_word_rom; 119 | case 1: return write_swapped_word_rom; 120 | case 2: return write_swapped_word_rom_bus_1; 121 | case 3: return write_swapped_word_rom_bus_2; 122 | case 4: return write_doubled_word; 123 | case 5: return write_swapped_doubled_word; 124 | } 125 | 126 | } 127 | 128 | u16 ( *( read_word() ) )(u32 address) 129 | { 130 | switch(cart->busType) { 131 | case 0: return read_word_rom; 132 | case 1: return read_swapped_word_rom; 133 | case 2: return read_swapped_word_rom_bus_1; 134 | case 3: return read_swapped_word_rom_bus_2; 135 | case 4: return read_word_rom; 136 | case 5: return read_swapped_word_rom; 137 | } 138 | 139 | } 140 | 141 | bool waitForFlash(u32 address, bool (*isReady)(u16), int timeout){ 142 | while(timeout && !isReady(read_word_rom(address)) ){ 143 | wait(); 144 | timeout--; 145 | } 146 | if(!timeout){ 147 | return false; 148 | } 149 | return true; 150 | } 151 | 152 | 153 | u32* getAddressSeq22XX() 154 | { 155 | u32* add_sec; 156 | switch(cart->adressSeqType) { 157 | case 0: add_sec = seq_0; break; 158 | case 1: add_sec = seq_1; break; 159 | case 2: add_sec = seq_2; break; 160 | case 3: add_sec = seq_3; break; 161 | case 4: add_sec = seq_4; break; 162 | case 5: add_sec = seq_5; break; 163 | } 164 | 165 | return add_sec; 166 | } 167 | 168 | void reset22XX() 169 | { 170 | u8 data_sec[] = { 0xAA, 0x55, 0xF0}; 171 | u32* addr_sec = getAddressSeq22XX(); 172 | 173 | for(u8 i = 0; i < 3; ++i) { 174 | write_word()(addr_sec[i], data_sec[i]); 175 | } 176 | } 177 | 178 | void detect22XX() 179 | { 180 | u8 data_sec[] = { 0xAA, 0x55, 0x90}; 181 | u16 flashid, manufactorID; 182 | for(cart->adressSeqType = 0; cart->adressSeqType < ADD_SEQ_COUNT; cart->adressSeqType++) { 183 | u32* addr_sec = getAddressSeq22XX(); 184 | for(cart->busType = 0; cart->busType < WRITE_BUS_COUNT; cart->busType++) { 185 | for(u8 i = 0; i < 3; ++i) { 186 | write_word()(addr_sec[i], data_sec[i]); 187 | } 188 | flashid = read_word()(0x1); 189 | manufactorID = read_word()(0x0); 190 | if (((flashid >> 8) & 0xFF) == 0x22 || flashid == 0x7E7E || flashid == 0x57 || flashid == 0xF8) { 191 | cart->flashid = flashid; 192 | cart->manufactorID = manufactorID; 193 | reset22XX(); 194 | return; 195 | } 196 | } 197 | } 198 | cart->adressSeqType = 0; 199 | cart->busType = 0; 200 | } 201 | 202 | void eraseSector22XX(u32 addr) 203 | { 204 | u8 data_sec[] = { 0xAA, 0x55, 0x80, 0xAA, 0x55}; 205 | u32* addr_sec = getAddressSeq22XX(); 206 | 207 | for(u8 i = 0; i < 5; ++i) { 208 | write_word()(addr_sec[i], data_sec[i]); 209 | } 210 | write_word()(addr, 0x30); 211 | 212 | u16 statusReg = 0; 213 | while ((statusReg | 0xFF7F) != 0xFFFF) { 214 | statusReg = read_word()(addr); 215 | wait(); 216 | } 217 | reset22XX(); 218 | } 219 | 220 | void writeWord22XX(u32 addr, u16 data) 221 | { 222 | u8 data_sec[] = { 0xAA, 0x55, 0xA0}; 223 | u32* addr_sec = getAddressSeq22XX(); 224 | 225 | for(u8 i = 0; i < 3; ++i) { 226 | write_word()(addr_sec[i], data_sec[i]); 227 | } 228 | write_word_rom(addr, data); 229 | 230 | int timeout = 0x2000; 231 | u16 statusReg = read_word_rom(addr); 232 | while(timeout && (statusReg != data)){ 233 | timeout--; 234 | wait(); 235 | statusReg = read_word_rom(addr); 236 | } 237 | 238 | if(!timeout){ 239 | reset22XX(); 240 | eraseSector22XX(addr); 241 | writeWord22XX(addr, data); 242 | } 243 | 244 | } 245 | 246 | void resetIntel(u32 partitionSize) 247 | { 248 | for (u32 currPartition = 0; currPartition < cart->size; currPartition += partitionSize) { 249 | write_word()(currPartition, 0xFFFF); 250 | } 251 | } 252 | 253 | int eraseSectorIntel(u32 addr) 254 | { 255 | write_word_rom(addr,0x50); 256 | write_word_rom(addr,0x60); 257 | write_word_rom(addr,0xD0); 258 | write_word_rom(addr,0x20); 259 | write_word_rom(addr,0xD0); 260 | 261 | waitForFlash(addr, WAIT_NON_FFFF, 0x10000); 262 | 263 | u16 statusReg = 0; 264 | while ((statusReg | 0xFF7F) != 0xFFFF) { 265 | statusReg = read_word_rom(addr); 266 | wait(); 267 | } 268 | 269 | write_word_rom(addr, 0xFF); 270 | return 0; 271 | } 272 | 273 | int writeWordIntel(u32 addr, u16 data) 274 | { 275 | write_word_rom(addr, 0x50); 276 | write_word_rom(addr, 0xFF); 277 | 278 | write_word_rom(addr, 0x40); 279 | write_word_rom(addr, data); 280 | int timeout = 0x1000; 281 | 282 | while(timeout && read_word_rom(addr) == 0xFFFF){timeout--;wait();} 283 | while(timeout && read_word_rom(addr) == 0){timeout--;wait();} 284 | while(timeout && !(read_word_rom(addr)&0x80)){ 285 | timeout--;wait(); 286 | } 287 | 288 | //Sector was locked, unlock & erase, then try again 289 | if(read_word_rom(addr) & 3){ 290 | eraseSectorIntel(addr); 291 | writeWordIntel(addr, data); 292 | } 293 | 294 | if(!timeout || (read_word_rom(addr) & 0x10)){ 295 | write_word_rom(addr, 0xFF); 296 | return -1; 297 | } 298 | 299 | write_word_rom(addr, 0xFF); 300 | 301 | return 0; 302 | 303 | } 304 | 305 | void erase(u32 needSpace, bool isIntel) 306 | { 307 | for(int addr = 0; addr < needSpace; addr += 0x8000) { 308 | if(isIntel) { 309 | for(int smallAddr = addr; smallAddr < addr + 0x8000; smallAddr += 0x2000) 310 | eraseSectorIntel(smallAddr); 311 | } 312 | else eraseSector22XX(addr); 313 | printTop("\rERASE %d\%", (addr + 0x8000) * 100/needSpace ); 314 | } 315 | printTop("\n"); 316 | } 317 | 318 | void detectIntel() 319 | { 320 | cart->intelType = 0; 321 | u16 bufSigns[] = {0x8902, 0x8904, 0x887D, 0x887E, 0x88B0}; 322 | write_word_rom(0x0, 0xFF); 323 | write_word_rom(0x0, 0x50); 324 | write_word_rom(0x0, 0x90); 325 | u16 manufactorID = read_word_rom(0x0); 326 | u16 flashid = read_word_rom(0x1); 327 | 328 | for(u8 i = 0; i < 4; i++){ 329 | if(flashid == bufSigns[i]) { 330 | cart->manufactorID = manufactorID; 331 | cart->flashid = flashid; 332 | cart->intelType = 2; 333 | write_word_rom(0, 0xF0); 334 | return; 335 | } 336 | } 337 | 338 | if(((flashid >> 8) & 0xFF) == 0x88) { 339 | cart->manufactorID = manufactorID; 340 | cart->flashid = flashid; 341 | cart->intelType = 1; 342 | write_word_rom(0, 0xF0); 343 | return; 344 | } 345 | 346 | if(flashid == 0xB0 && manufactorID == 0xB0) { 347 | cart->manufactorID = manufactorID; 348 | cart->flashid = 0x88FF; 349 | cart->intelType = 1; 350 | write_word_rom(0, 0xF0); 351 | return; 352 | } 353 | 354 | if(manufactorID == 0x1C) { 355 | cart->manufactorID = manufactorID; 356 | cart->flashid = flashid; 357 | cart->intelType = 1; 358 | write_word_rom(0, 0xF0); 359 | return; 360 | } 361 | cart->intelType = 0; 362 | } 363 | 364 | 365 | void idFlashrom_GBA() 366 | { 367 | cart->flashid = 0; 368 | 369 | detectIntel(); 370 | if (cart->flashid != 0) { 371 | return; 372 | } 373 | 374 | detect22XX(); 375 | if(cart->flashid != 0) { 376 | reset22XX(); 377 | return; 378 | } 379 | 380 | cart->flashid = 0; 381 | } 382 | 383 | void chipSize() 384 | { 385 | write_word()(0x0, 0x50); 386 | write_word()(0x0, 0xFF); 387 | write_word()(0x55, 0x98); 388 | if( read_word()(0x10) == 0x51 && 389 | read_word()(0x11) == 0x52 && 390 | read_word()(0x12) == 0x59 391 | ) { 392 | cart->size = (u32)(1<bufferSize = (u16)(1<flashid; 487 | u16 manufactorID = cart->manufactorID; 488 | u32 chipSize = cart->size; 489 | 490 | if (flashid != 0) { 491 | printTop("ID: %04X Size: %DMB\n", flashid, chipSize / 0x100000); 492 | printTop("%s \n", getManufacturByID(manufactorID)); 493 | getFileSize(); 494 | 495 | // Open file on sd card 496 | if (fileSize) { 497 | // Get rom size from file 498 | printTop("File size: %DMB\n", fileSize / 0x100000); 499 | 500 | // Erase needed sectors 501 | if ((((flashid >> 8) & 0XFF) == 0x88) || (((flashid >> 8) & 0XFF) == 0x89) || manufactorID == 0x1C) { 502 | erase(fileSize >> 1, true); 503 | } 504 | else if (((flashid >> 8) & 0XFF) == 0x22 || flashid == 0x7E7E || flashid == 0x57 || flashid == 0xF8) { 505 | erase(fileSize >> 1, false); 506 | } 507 | 508 | //Write flashrom 509 | if ((((flashid >> 8) & 0XFF) == 0x88) || (((flashid >> 8) & 0XFF) == 0x89) || manufactorID == 0x1C) { 510 | writeByWord(true); 511 | } 512 | else if (((flashid >> 8) & 0xFF) == 0x22 || flashid == 0x7E7E || flashid == 0x57 || flashid == 0xF8) { 513 | writeByWord(false); 514 | } 515 | 516 | return true; 517 | } 518 | else { 519 | printTop("Can't open file"); 520 | } 521 | } 522 | else { 523 | printTop("Error\n\nUnknown Flash\nFlash ID: %04X\n\n", flashid); 524 | } 525 | 526 | return false; 527 | } 528 | -------------------------------------------------------------------------------- /arm9/source/file_browse.cpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | Copyright (C) 2005 - 2017 3 | Michael "Chishm" Chisholm 4 | Dave "WinterMute" Murphy 5 | Claudio "sverx" 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | 21 | ------------------------------------------------------------------*/ 22 | 23 | #include "file_browse.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | 34 | #define SCREEN_COLS 32 35 | #define ENTRIES_PER_SCREEN 22 36 | #define ENTRIES_START_ROW 2 37 | #define ENTRY_PAGE_LENGTH 10 38 | 39 | using namespace std; 40 | 41 | struct DirEntry { 42 | string name; 43 | bool isDirectory; 44 | } ; 45 | 46 | bool nameEndsWith (const string& name, const vector extensionList) { 47 | 48 | if (name.size() == 0) return false; 49 | if (name.front() == '.') return false; 50 | 51 | if (extensionList.size() == 0) return true; 52 | 53 | for (int i = 0; i < (int)extensionList.size(); i++) { 54 | const string ext = extensionList.at(i); 55 | if ( strcasecmp (name.c_str() + name.size() - ext.size(), ext.c_str()) == 0) return true; 56 | } 57 | return false; 58 | } 59 | 60 | bool dirEntryPredicate (const DirEntry& lhs, const DirEntry& rhs) { 61 | 62 | if (!lhs.isDirectory && rhs.isDirectory) { 63 | return false; 64 | } 65 | if (lhs.isDirectory && !rhs.isDirectory) { 66 | return true; 67 | } 68 | return strcasecmp(lhs.name.c_str(), rhs.name.c_str()) < 0; 69 | } 70 | 71 | void getDirectoryContents (vector& dirContents, const vector extensionList) { 72 | struct stat st; 73 | 74 | dirContents.clear(); 75 | 76 | DIR *pdir = opendir ("."); 77 | 78 | if (pdir == NULL) { 79 | iprintf ("Unable to open the directory.\n"); 80 | } else { 81 | 82 | while(true) { 83 | DirEntry dirEntry; 84 | 85 | struct dirent* pent = readdir(pdir); 86 | if(pent == NULL) break; 87 | 88 | stat(pent->d_name, &st); 89 | dirEntry.name = pent->d_name; 90 | dirEntry.isDirectory = (st.st_mode & S_IFDIR) ? true : false; 91 | 92 | if (dirEntry.name.compare(".") != 0 && (dirEntry.isDirectory || nameEndsWith(dirEntry.name, extensionList))) { 93 | dirContents.push_back (dirEntry); 94 | } 95 | 96 | } 97 | 98 | closedir(pdir); 99 | } 100 | 101 | sort(dirContents.begin(), dirContents.end(), dirEntryPredicate); 102 | } 103 | 104 | void getDirectoryContents (vector& dirContents) { 105 | vector extensionList; 106 | getDirectoryContents (dirContents, extensionList); 107 | } 108 | 109 | void showDirectoryContents (const vector& dirContents, int startRow) { 110 | char path[PATH_MAX]; 111 | 112 | 113 | getcwd(path, PATH_MAX); 114 | 115 | // Clear the screen 116 | iprintf ("\x1b[2J"); 117 | 118 | // Print the path 119 | if (strlen(path) < SCREEN_COLS) { 120 | iprintf ("%s", path); 121 | } else { 122 | iprintf ("%s", path + strlen(path) - SCREEN_COLS); 123 | } 124 | 125 | // Move to 2nd row 126 | iprintf ("\x1b[1;0H"); 127 | // Print line of dashes 128 | iprintf ("--------------------------------"); 129 | 130 | // Print directory listing 131 | for (int i = 0; i < ((int)dirContents.size() - startRow) && i < ENTRIES_PER_SCREEN; i++) { 132 | const DirEntry* entry = &dirContents.at(i + startRow); 133 | char entryName[SCREEN_COLS + 1]; 134 | 135 | // Set row 136 | iprintf ("\x1b[%d;0H", i + ENTRIES_START_ROW); 137 | 138 | if (entry->isDirectory) { 139 | strncpy (entryName, entry->name.c_str(), SCREEN_COLS); 140 | entryName[SCREEN_COLS - 3] = '\0'; 141 | iprintf (" [%s]", entryName); 142 | } else { 143 | strncpy (entryName, entry->name.c_str(), SCREEN_COLS); 144 | entryName[SCREEN_COLS - 1] = '\0'; 145 | iprintf (" %s", entryName); 146 | } 147 | } 148 | } 149 | 150 | string browseForFile (const vector& extensionList) { 151 | int pressed = 0; 152 | int screenOffset = 0; 153 | int fileOffset = 0; 154 | vector dirContents; 155 | 156 | getDirectoryContents (dirContents, extensionList); 157 | showDirectoryContents (dirContents, screenOffset); 158 | 159 | while (true) { 160 | // Clear old cursors 161 | for (int i = ENTRIES_START_ROW; i < ENTRIES_PER_SCREEN + ENTRIES_START_ROW; i++) { 162 | iprintf ("\x1b[%d;0H ", i); 163 | } 164 | // Show cursor 165 | iprintf ("\x1b[%d;0H*", fileOffset - screenOffset + ENTRIES_START_ROW); 166 | 167 | //iconTitleUpdate (dirContents.at(fileOffset).isDirectory, dirContents.at(fileOffset).name); 168 | 169 | // Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do 170 | do { 171 | scanKeys(); 172 | pressed = keysDownRepeat(); 173 | swiWaitForVBlank(); 174 | } while (!pressed); 175 | 176 | if (pressed & KEY_UP) fileOffset -= 1; 177 | if (pressed & KEY_DOWN) fileOffset += 1; 178 | if (pressed & KEY_LEFT) fileOffset -= ENTRY_PAGE_LENGTH; 179 | if (pressed & KEY_RIGHT) fileOffset += ENTRY_PAGE_LENGTH; 180 | 181 | if (fileOffset < 0) fileOffset = dirContents.size() - 1; // Wrap around to bottom of list 182 | if (fileOffset > ((int)dirContents.size() - 1)) fileOffset = 0; // Wrap around to top of list 183 | 184 | // Scroll screen if needed 185 | if (fileOffset < screenOffset) { 186 | screenOffset = fileOffset; 187 | showDirectoryContents (dirContents, screenOffset); 188 | } 189 | if (fileOffset > screenOffset + ENTRIES_PER_SCREEN - 1) { 190 | screenOffset = fileOffset - ENTRIES_PER_SCREEN + 1; 191 | showDirectoryContents (dirContents, screenOffset); 192 | } 193 | 194 | if (pressed & KEY_A) { 195 | DirEntry* entry = &dirContents.at(fileOffset); 196 | if (entry->isDirectory) { 197 | iprintf("Entering directory\n"); 198 | // Enter selected directory 199 | chdir (entry->name.c_str()); 200 | getDirectoryContents (dirContents, extensionList); 201 | screenOffset = 0; 202 | fileOffset = 0; 203 | showDirectoryContents (dirContents, screenOffset); 204 | } else { 205 | // Clear the screen 206 | iprintf ("\x1b[2J"); 207 | // Return the chosen file 208 | return entry->name; 209 | } 210 | } 211 | 212 | if (pressed & KEY_B) { 213 | // Go up a directory 214 | chdir (".."); 215 | getDirectoryContents (dirContents, extensionList); 216 | screenOffset = 0; 217 | fileOffset = 0; 218 | showDirectoryContents (dirContents, screenOffset); 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /arm9/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "app.h" 11 | #include "util.h" 12 | 13 | int main(int argc, char **argv) { 14 | //--------------------------------------------------------------------------------- 15 | extern u64 *fake_heap_end; 16 | *fake_heap_end = 0; 17 | 18 | initGraphics(); 19 | if (!fatInitDefault()) { 20 | iprintf ("fatinitDefault failed!\n"); 21 | } 22 | 23 | keysSetRepeat(25,5); 24 | sysSetBusOwners(BUS_OWNER_ARM9,BUS_OWNER_ARM9); 25 | while(1) { 26 | flashRepro_GBA(); 27 | //BootGbaARM9(1); 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /arm9/source/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | PrintConsole topScreen; 4 | PrintConsole bottomScreen; 5 | 6 | void initGraphics(){ 7 | videoSetMode(MODE_0_2D); 8 | videoSetModeSub(MODE_0_2D); 9 | vramSetBankA(VRAM_A_MAIN_BG); 10 | vramSetBankC(VRAM_C_SUB_BG); 11 | consoleInit(&topScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true); 12 | consoleInit(&bottomScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true); 13 | consoleSelect(&bottomScreen); 14 | } 15 | 16 | void printTop(const char* str, ...){ 17 | REG_IME = 0; 18 | va_list args; 19 | va_start(args, str); 20 | consoleSelect(&topScreen); 21 | vprintf(str, args); 22 | consoleSelect(&bottomScreen); 23 | va_end(args); 24 | REG_IME = 1; 25 | } 26 | 27 | void BootGbaARM9(u32 useBottomScreen)//, cBMP15& border) 28 | { 29 | //start arm7 sequence 30 | fifoSendValue32(FIFO_USER_01, useBottomScreen); 31 | 32 | 33 | videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE); 34 | videoSetModeSub(MODE_5_2D | DISPLAY_BG3_ACTIVE); 35 | vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_BG_0x06020000, VRAM_C_SUB_BG_0x06200000, VRAM_D_LCD); 36 | 37 | REG_BG3CNT = BG_BMP16_256x256 | BG_BMP_BASE(0) | BG_WRAP_OFF; 38 | REG_BG3PA = 1 << 8; 39 | REG_BG3PB = 0; 40 | REG_BG3PC = 0; 41 | REG_BG3PD = 1 << 8; 42 | REG_BG3VOFS = 0; 43 | REG_BG3HOFS = 0; 44 | 45 | //if(border.valid()){ 46 | // memcpy((u16*)BG_BMP_RAM(0), border.buffer(), SCREEN_WIDTH*SCREEN_HEIGHT*2); 47 | // memcpy((u16*)BG_BMP_RAM(8), border.buffer(), SCREEN_WIDTH*SCREEN_HEIGHT*2); 48 | //}else{ 49 | memset((void*)BG_BMP_RAM(0), 0, 0x18000); 50 | memset((void*)BG_BMP_RAM(8), 0, 0x18000); 51 | //} 52 | 53 | //POWCNT = 8003h / 0003h 54 | if(useBottomScreen) { 55 | REG_POWERCNT = 3; 56 | }else { 57 | REG_POWERCNT = 0x8003; 58 | } 59 | 60 | REG_EXMEMCNT |= 0x8080; // ARM7 has access to GBA cart 61 | REG_EXMEMCNT &= ~0x4000; // set Async Main Memory mode 62 | 63 | // halt indefinitly, since irqs are disabled 64 | REG_IME = 0; 65 | swiWaitForIRQ(); 66 | 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /b2s_upscaled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrodin/Burn2Slot/3d3153e419b90988c71dab14523f072c98f54c6c/b2s_upscaled.png -------------------------------------------------------------------------------- /icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrodin/Burn2Slot/3d3153e419b90988c71dab14523f072c98f54c6c/icon.bmp --------------------------------------------------------------------------------