Initial Branch Commit...

* Update sckill with improved version that supports SuperCard Lite
MicroSD (not to beconfused with the one that has Rumble)
This commit is contained in:
ApacheThunder 2024-05-26 15:15:55 -05:00
parent 93fb8d7574
commit 87c9d70a04
52 changed files with 864 additions and 13605 deletions

57
Makefile Normal file
View File

@ -0,0 +1,57 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
export TARGET := sckill
export TOPDIR := $(CURDIR)
# specify a directory which contains the nitro filesystem
# this is relative to the Makefile
NITRO_FILES :=
# These set the information text in the nds file
# GAME_TITLE := SuperCard FW Writer
# GAME_SUBTITLE1 := Metroid Maniac
# GAME_SUBTITLE2 := Modified by ApacheThunder
include $(DEVKITARM)/ds_rules
.PHONY: checkarm7 checkarm9 clean
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: checkarm7 checkarm9 $(TARGET).nds
#---------------------------------------------------------------------------------
checkarm7:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
checkarm9:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
$(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
-t banner.bin \
$(_ADDFILES)
# -b $(CURDIR)/icon.bmp "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \
#---------------------------------------------------------------------------------
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).arm7 $(TARGET).arm9

View File

@ -1,31 +1,7 @@
# SCFW: Custom Firmware & Kernel for Supercard
# SCFW - SCKILL: FW Updator for Custom Firmware & Kernel for Supercard
SCFW is a custom firmware and kernel for the Supercard SD.
Currently it is in a preview state with minimum functionality.
Dedicated fork for updating SCKILL a NDS mode updator for updating FW flash on SuperCard devices.
## Installation
Download the current release and copy the scfw folder to the root of your SD card.
That's it! You can now use the kernel by loading scfw/kernel.gba from the official firmware.
You can also select the firmware.frm file from within the kernel to flash SCFW to the Supercard's firmware. Because the firmware is minimal and the kernel is loaded from the SD card, updates to the firmware should be rare. You can enjoy kernel updates without updating the firmware.
## Current features
- Can browse files
- Can load a GBA ROM
- Can flash a Supercard firmware.
- Automatic SRAM, waitstate, and prefetch patching (buggy)
- Automatic SRAM loading & saving
- Manual SRAM management
- SDHC
- Soft reset patch
## Planned features
- Nicer file browser
- Support for more filetypes with builtin goomba/pocketnes etc.
- NDS mode
- Code cleanup, lots of it.
- Cache patches after creating them to increase loading speed
- Faster loading speeds
- Cheats(?)
- Save states(?)
## Links
GBATemp discussion thread
https://gbatemp.net/threads/scfw-custom-firmware-kernel-for-supercard.647238/

View File

@ -1,191 +0,0 @@
#include "find.h"
#include "Save.h"
#include "EepromSave.h"
extern u32 romSize;
//todo: Moero!! Jaleco Collection (Japan) reports EEPROM_V124, but the signatures below don't work!
static const u8 sReadEepromDwordV111Sig[0x10] =
{0xB0, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88};
static const u8 sReadEepromDwordV120Sig[0x10] =
{0x70, 0xB5, 0xA2, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x03, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88};
static const u8 sProgramEepromDwordV111Sig[0x10] =
{0x80, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88};
//changed in EEPROM_V124
static const u8 sProgramEepromDwordV120Sig[0x10] =
{0x30, 0xB5, 0xA9, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x04, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88};
//changed in EEPROM_V126
static const u8 sProgramEepromDwordV124Sig[0x10] =
{0xF0, 0xB5, 0xAC, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x01, 0x0C, 0x12, 0x06, 0x17, 0x0E, 0x03, 0x48};
static const u8 sProgramEepromDwordV126Sig[0x10] =
{0xF0, 0xB5, 0x47, 0x46, 0x80, 0xB4, 0xAC, 0xB0, 0x0E, 0x1C, 0x00, 0x04, 0x05, 0x0C, 0x12, 0x06};
//not in EEPROM_V111
//could be used to identify the eeprom size, but not strictly needed
/*static u16 identifyEeprom(u16 kbitSize)
{
return 0;
}*/
const u8 patch_eeprom_1[]=
{
0x00,0x04, // LSL R0, R0, #0x10
0x0a,0x1c, // ADD R2, R1, #0
0x40,0x0b, // LSR R0, R0, #0xD
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
0x41,0x18, // ADD R1, R0, R1
0x07,0x31, // ADD R1, #7
0x00,0x23, // MOV R3, #0
//l1:
0x08,0x78, // LDRB R0, [R1]
0x10,0x70, // STRB R0, [R2]
0x01,0x33, // ADD R3, #1
0x01,0x32, // ADD R2, #1
0x01,0x39, // SUB R1, #1
0x07,0x2b, // CMP R3, #7
0xf8,0xd9, // BLS l1
0x00,0x20, // MOV R0, #0
0x70,0x47 // BX LR
};
const u8 patch_eeprom_2[]=
{
0x00,0x04, // LSL R0, R0, #0x10
0x0a,0x1c, // ADD R2, R1, #0
0x40,0x0b, // LSR R0, R0, #0xD
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
0x41,0x18, // ADD R1, R0, R1
0x07,0x31, // ADD R1, #7
0x00,0x23, // MOV R3, #0
//l1:
0x10,0x78, // LDRB R0, [R2]
0x08,0x70, // STRB R0, [R1]
0x01,0x33, // ADD R3, #1
0x01,0x32, // ADD R2, #1
0x01,0x39, // SUB R1, #1
0x07,0x2b, // CMP R3, #7
0xf8,0xd9, // BLS l1
0x00,0x20, // MOV R0, #0
0x70,0x47 // BX LR
};
bool eeprom_patchV111(const struct save_type* type)
{
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV111Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV111Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
return true;
}
bool eeprom_patchV120(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 3; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2-3 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV120Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
}
return true;
}
bool eeprom_patchV124(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 2; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV124Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
}
return true;
}
bool eeprom_patchV126(const struct save_type* type)
{
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV126Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
return true;
}

View File

@ -1,7 +0,0 @@
#pragma once
#include "Save.h"
bool eeprom_patchV111(const struct save_type* type);
bool eeprom_patchV120(const struct save_type* type);
bool eeprom_patchV124(const struct save_type* type);
bool eeprom_patchV126(const struct save_type* type);

View File

@ -1,358 +0,0 @@
#include "find.h"
#include "Save.h"
#include "FlashSave.h"
extern u32 romSize;
static const u8 flash1M_V102_find1[48] = {
0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,0xe0,0x21,
0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x30,0xb5,
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20
};
static const u8 flash1M_V102_replace1[136] = {
0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,0xc3,0x02,
0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x30,0xb5,
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20,
0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,0x03,0x4a,
0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x20,0x4e,
0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,0x0c,0x48,
0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,0x62,0x20,
0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,0x55,0x20,
0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find2[24] = {
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
};
static const u8 flash1M_V102_replace2[24] = {
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find3[22] = {
0xaa,0x25,0x0d,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
0x1a,0x70,0x30,0x20,0x20,0x70
};
static const u8 flash1M_V102_replace3[22] = {
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find4[12] = {
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
};
static const u8 flash1M_V102_replace4[12] = {
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
};
static const u8 flash1M_V103_find1[98] = {
0x05,0x4b,0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,
0xe0,0x21,0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
0xaa,0x20,0x10,0x70,0x05,0x49,0x55,0x20,0x08,0x70,0x90,0x20,0x10,0x70,0x10,0xa9,
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
0x0c,0x48
};
static const u8 flash1M_V103_replace1[138] = {
0x05,0x4b,0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,
0xc3,0x02,0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
0xaa,0x20,0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
0x0c,0x48,0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,
0x62,0x20,0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,
0x55,0x20,0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find2[24] = {
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
};
static const u8 flash1M_V103_replace2[24] = {
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find3[22] = {
0xaa,0x25,0x0d,0x70,0x14,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
0x1a,0x70,0x30,0x20,0x20,0x70
};
static const u8 flash1M_V103_replace3[22] = {
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find4[12] = {
0x10,0x70,0x0b,0x49,0x55,0x20,0x08,0x70,0xa0,0x20,0x10,0x70
};
static const u8 flash1M_V103_replace4[12] = {
0x00,0x00,0x0b,0x49,0x55,0x20,0x00,0x00,0xa0,0x20,0x00,0x00
};
static const u8 flash1M_V103_find5[12] = {
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
};
static const u8 flash1M_V103_replace5[12] = {
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
};
// FLASH512_V130, V131, and V133 have all the same patches.
// Patches are from gbatemp thread, but gbata doesn't actually support V133.
static const u8 flash512_V13X_find1[38] = {
0xf0,0xb5,0xa0,0xb0,0x0d,0x1c,0x16,0x1c,0x1f,0x1c,0x03,0x04,0x1c,0x0c,0x0f,0x4a,
0x10,0x88,0x0f,0x49,0x08,0x40,0x03,0x21,0x08,0x43,0x10,0x80,0x0d,0x48,0x00,0x68,
0x01,0x68,0x80,0x20,0x80,0x02
};
static const u8 flash512_V13X_replace1[38] = {
0x70,0xb5,0xa0,0xb0,0x00,0x03,0x40,0x18,0xe0,0x21,0x09,0x05,0x09,0x18,0x08,0x78,
0x10,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,0x20,0xb0,
0x70,0xbc,0x02,0xbc,0x08,0x47
};
static const u8 flash512_V13X_find2[8] = {
0xff,0xf7,0x88,0xfd,0x00,0x04,0x03,0x0c
};
static const u8 flash512_V13X_replace2[8] = {
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
};
static const u8 flash512_V13X_find3[8] = {
0x70,0xb5,0x90,0xb0,0x15,0x4d,0x29,0x88
};
static const u8 flash512_V13X_find4[8] = {
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0
};
static const u8 flash512_V13X_replace3_4[8] = {
0x00,0xb5,0x00,0x20,0x02,0xbc,0x08,0x47
};
static const u8 flash512_V13X_find5[24] = {
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x03,0x48,0x00,0x68,0x40,0x89,
0x84,0x42,0x05,0xd3,0x01,0x48,0x41,0xe0
};
static const u8 flash512_V13X_replace5[42] = {
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x02,0xbc,0x08,0x47
};
// Encompasses FLASH_V120 and V121.
static const u8 flash_V12X_find1[12] = {
0x90,0xb5,0x93,0xb0,0x6f,0x46,0x39,0x1d,0x08,0x1c,0x00,0xf0
};
static const u8 flash_V12X_replace1[14] = {
0x00,0xb5,0x3d,0x20,0x00,0x02,0x1f,0x21,0x08,0x43,0x02,0xbc,0x08,0x47
};
static const u8 flash_V12X_find2[35] = {
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,0x0f,0x29,
0x04,0xd9,0x01,0x48,0x56,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x23,0x48,0x23,0x49,
0x0a,0x88,0x23
};
static const u8 flash_V12X_replace2[36] = {
0x7c,0xb5,0x00,0x07,0x00,0x0c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,0x1b,0x03,
0xff,0x20,0x08,0x70,0x01,0x3b,0x01,0x31,0x00,0x2b,0xfa,0xd1,0x00,0x20,0x7c,0xbc,
0x02,0xbc,0x08,0x47
};
static const u8 flash_V12X_find3[42] = {
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x79,0x60,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,
0x0f,0x29,0x03,0xd9,0x00,0x48,0x73,0xe0,0xff,0x80,0x00,0x00,0x38,0x1c,0x01,0x88,
0x08,0x1c,0xff,0xf7,0x21,0xfe,0x39,0x1c,0x0c,0x31
};
static const u8 flash_V12X_replace3[42] = {
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x08,0xbc,0x08,0x47
};
// Encompasses FLASH_V123, V124, V125, and V126.
// FIXME for FLASH_V125 and FLASH_V126: Medabots/Metarot and Super Monkey Ball Jr. (U) don't patch 1:1 with gbata.
static const u8 flash_V12Y_find1[8] = {
0xff,0xf7,0xaa,0xff,0x00,0x04,0x03,0x0c
};
static const u8 flash_V12Y_replace1[8] = {
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
};
static const u8 flash_V12Y_find2[6] = {
0x70,0xb5,0x90,0xb0,0x15,0x4d
};
static const u8 flash_V12Y_replace2[4] = {
0x00,0x20,0x70,0x47/*,0x15,0x4d*/
};
// Patch 3 differs from GBATemp tutorial.
// The added bytes at the end have significance.
static const u8 flash_V12Y_find3[9] = {
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0,0x00
};
static const u8 flash_V12Y_replace3[4] = {
0x00,0x20,0x70,0x47/*,0x40,0xb4,0x90,0xb0,0x00*/
};
static const u8 flash_V12Y_find4[38] = {
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x0f,0x2c,0x04,0xd9,0x01,0x48,
0x40,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x20,0x1c,0xff,0xf7,0xd7,0xfe,0x00,0x04,
0x05,0x0c,0x00,0x2d,0x35,0xd1
};
static const u8 flash_V12Y_replace4[38] = {
0x70,0xb5,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x41,0x18,0x01,0x23,0x1b,0x03,
0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,
0x70,0xbc,0x02,0xbc,0x08,0x47
};
bool flash_patchV120(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find1, sizeof(flash_V12X_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash_V12X_replace1, sizeof(flash_V12X_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find2, sizeof(flash_V12X_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash_V12X_replace2, sizeof(flash_V12X_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find3, sizeof(flash_V12X_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash_V12X_replace3, sizeof(flash_V12X_replace3));
return true;
}
bool flash_patchV123(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find1, sizeof(flash_V12Y_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash_V12Y_replace1, sizeof(flash_V12Y_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find2, sizeof(flash_V12Y_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash_V12Y_replace2, sizeof(flash_V12Y_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find3, sizeof(flash_V12Y_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash_V12Y_replace3, sizeof(flash_V12Y_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find4, sizeof(flash_V12Y_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash_V12Y_replace4, sizeof(flash_V12Y_replace4));
return true;
}
/*bool flash_patchV126(const struct save_type* type)
{
}*/
bool flash_patch512V130(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 2; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* func1 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find1, sizeof(flash512_V13X_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash512_V13X_replace1, sizeof(flash512_V13X_replace1));
u8* func2 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find2, sizeof(flash512_V13X_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash512_V13X_replace2, sizeof(flash512_V13X_replace2));
u8* func3 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find3, sizeof(flash512_V13X_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
u8* func4 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find4, sizeof(flash512_V13X_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
u8* func5 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find5, sizeof(flash512_V13X_find5), true);
if (!func5)
return false;
twoByteCpy((u16*)func5, (const u16*)flash512_V13X_replace5, sizeof(flash512_V13X_replace5));
}
return true;
}
bool flash_patch1MV102(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find1, sizeof(flash1M_V102_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash1M_V102_replace1, sizeof(flash1M_V102_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find2, sizeof(flash1M_V102_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash1M_V102_replace2, sizeof(flash1M_V102_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find3, sizeof(flash1M_V102_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash1M_V102_replace3, sizeof(flash1M_V102_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find4, sizeof(flash1M_V102_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash1M_V102_replace4, sizeof(flash1M_V102_replace4));
return true;
}
bool flash_patch1MV103(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find1, sizeof(flash1M_V103_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash1M_V103_replace1, sizeof(flash1M_V103_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find2, sizeof(flash1M_V103_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash1M_V103_replace2, sizeof(flash1M_V103_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find3, sizeof(flash1M_V103_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash1M_V103_replace3, sizeof(flash1M_V103_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find4, sizeof(flash1M_V103_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash1M_V103_replace4, sizeof(flash1M_V103_replace4));
u8* func5 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find5, sizeof(flash1M_V103_find5), true);
if (!func5)
return false;
twoByteCpy((u16*)func5, (const u16*)flash1M_V103_replace5, sizeof(flash1M_V103_replace5));
return true;
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "Save.h"
bool flash_patchV120(const struct save_type* type);
bool flash_patchV123(const struct save_type* type);
bool flash_patchV126(const struct save_type* type);
bool flash_patch512V130(const struct save_type* type);
bool flash_patch1MV102(const struct save_type* type);
bool flash_patch1MV103(const struct save_type* type);

View File

@ -1,139 +0,0 @@
#include <gba.h>
#include "EepromSave.h"
#include "FlashSave.h"
#include "Save.h"
#include "string.h"
u32 romSize;
#define SAVE_TYPE_COUNT 25
static const struct save_type sSaveTypes[SAVE_TYPE_COUNT] =
{
{"EEPROM_V111", 12, SAVE_TYPE_EEPROM_V111, 512, eeprom_patchV111},
{"EEPROM_V120", 12, SAVE_TYPE_EEPROM_V120, 8 * 1024, eeprom_patchV120},
{"EEPROM_V121", 12, SAVE_TYPE_EEPROM_V121, 8 * 1024, eeprom_patchV120},
{"EEPROM_V122", 12, SAVE_TYPE_EEPROM_V122, 8 * 1024, eeprom_patchV120},
{"EEPROM_V124", 12, SAVE_TYPE_EEPROM_V124, 8 * 1024, eeprom_patchV124},
{"EEPROM_V125", 12, SAVE_TYPE_EEPROM_V125, 8 * 1024, eeprom_patchV124},
{"EEPROM_V126", 12, SAVE_TYPE_EEPROM_V126, 8 * 1024, eeprom_patchV126},
{"FLASH_V120", 11, SAVE_TYPE_FLASH_V120, 64 * 1024, flash_patchV120},
{"FLASH_V121", 11, SAVE_TYPE_FLASH_V121, 64 * 1024, flash_patchV120},
{"FLASH_V123", 11, SAVE_TYPE_FLASH_V123, 64 * 1024, flash_patchV123},
{"FLASH_V124", 11, SAVE_TYPE_FLASH_V124, 64 * 1024, flash_patchV123},
{"FLASH_V125", 11, SAVE_TYPE_FLASH_V125, 64 * 1024, flash_patchV123},
{"FLASH_V126", 11, SAVE_TYPE_FLASH_V126, 64 * 1024, /*flash_patchV126*/ flash_patchV123},
{"FLASH512_V130", 14, SAVE_TYPE_FLASH512_V130, 64 * 1024, flash_patch512V130},
{"FLASH512_V131", 14, SAVE_TYPE_FLASH512_V131, 64 * 1024, flash_patch512V130},
{"FLASH512_V133", 14, SAVE_TYPE_FLASH512_V133, 64 * 1024, flash_patch512V130},
{"FLASH1M_V102", 13, SAVE_TYPE_FLASH1M_V102, 128 * 1024, flash_patch1MV102},
{"FLASH1M_V103", 13, SAVE_TYPE_FLASH1M_V103, 128 * 1024, flash_patch1MV103},
//sram does not require patching
{"SRAM_F_V100", 12, SAVE_TYPE_SRAM_F_V100, 32 * 1024, NULL},
{"SRAM_F_V102", 12, SAVE_TYPE_SRAM_F_V102, 32 * 1024, NULL},
{"SRAM_F_V103", 12, SAVE_TYPE_SRAM_F_V103, 32 * 1024, NULL},
{"SRAM_V110", 10, SAVE_TYPE_SRAM_V110, 32 * 1024, NULL},
{"SRAM_V111", 10, SAVE_TYPE_SRAM_V111, 32 * 1024, NULL},
{"SRAM_V112", 10, SAVE_TYPE_SRAM_V112, 32 * 1024, NULL},
{"SRAM_V113", 10, SAVE_TYPE_SRAM_V113, 32 * 1024, NULL},
};
const struct save_type* save_findTag()
{
u32 curAddr = 0x080000C0;
char saveTag[16];
while (curAddr < 0x08000000+romSize) {
u32 fst = *(u32*)curAddr;
// tonccpy(&saveTag, (u8*)curAddr, 16);
((u32*)saveTag)[0] = ((u32*)curAddr)[0];
((u32*)saveTag)[1] = ((u32*)curAddr)[1];
((u32*)saveTag)[2] = ((u32*)curAddr)[2];
((u32*)saveTag)[3] = ((u32*)curAddr)[3];
enum SaveType type = SAVE_TYPE_NONE;
if (fst == 0x53414C46 && (saveTag[5] == '_' || saveTag[5] == '5' || saveTag[5] == '1')) {
//FLAS
type = SAVE_TYPE_FLASH;
} else if (fst == 0x4D415253) {
//SRAM
type = SAVE_TYPE_SRAM;
} else if (fst == 0x52504545 && saveTag[6] == '_') {
//EEPR
type = SAVE_TYPE_EEPROM;
}
if (type != SAVE_TYPE_NONE) {
for (int i = 0; i < SAVE_TYPE_COUNT; i++) {
if (strncmp(saveTag, sSaveTypes[i].tag, sSaveTypes[i].tagLength) != 0)
continue;
return &sSaveTypes[i];
}
}
curAddr += 4;
}
return NULL;
}
//tonccpy
//
void twoByteCpy(u16 *dst, const u16 *src, u32 size){
if (size == 0 || dst == NULL || src == NULL)
return;
u32 count;
u16 *dst16; // hword destination
u8 *src8; // byte source
// Ideal case: copy by 4x words. Leaves tail for later.
if (((u32)src|(u32)dst) %4 == 0 && size >= 4) {
u32 *src32= (u32*)src, *dst32= (u32*)dst;
count = size/4;
u32 tmp = count&3;
count /= 4;
// Duff's Device, good friend!
switch(tmp) {
do { *dst32++ = *src32++;
case 3: *dst32++ = *src32++;
case 2: *dst32++ = *src32++;
case 1: *dst32++ = *src32++;
case 0: ; } while (count--);
}
// Check for tail
size &= 3;
if (size == 0)
return;
src8 = (u8*)src32;
dst16 = (u16*)dst32;
} else {
// Unaligned
u32 dstOfs = (u32)dst&1;
src8 = (u8*)src;
dst16 = (u16*)(dst-dstOfs);
// Head: 1 byte.
if (dstOfs != 0) {
*dst16 = (*dst16 & 0xFF) | *src8++<<8;
dst16++;
if (--size == 0)
return;
}
}
// Unaligned main: copy by 2x byte.
count = size/2;
while (count--) {
*dst16++ = src8[0] | src8[1]<<8;
src8 += 2;
}
// Tail: 1 byte.
if (size & 1)
*dst16 = (*dst16 &~ 0xFF) | *src8;
}

View File

@ -1,63 +0,0 @@
#pragma once
// #ifdef __cplusplus
// extern "C" {
// #endif
enum SaveType
{
SAVE_TYPE_NONE = 0,
SAVE_TYPE_EEPROM = (1 << 14),
SAVE_TYPE_EEPROM_V111,
SAVE_TYPE_EEPROM_V120,
SAVE_TYPE_EEPROM_V121,
SAVE_TYPE_EEPROM_V122,
SAVE_TYPE_EEPROM_V124,
SAVE_TYPE_EEPROM_V125,
SAVE_TYPE_EEPROM_V126,
SAVE_TYPE_FLASH = (2 << 14),
SAVE_TYPE_FLASH512 = SAVE_TYPE_FLASH | (0 << 13),
SAVE_TYPE_FLASH_V120,
SAVE_TYPE_FLASH_V121,
SAVE_TYPE_FLASH_V123,
SAVE_TYPE_FLASH_V124,
SAVE_TYPE_FLASH_V125,
SAVE_TYPE_FLASH_V126,
SAVE_TYPE_FLASH512_V130,
SAVE_TYPE_FLASH512_V131,
SAVE_TYPE_FLASH512_V133,
SAVE_TYPE_FLASH1M = SAVE_TYPE_FLASH | (1 << 13),
SAVE_TYPE_FLASH1M_V102,
SAVE_TYPE_FLASH1M_V103,
SAVE_TYPE_SRAM = (3 << 14),
SAVE_TYPE_SRAM_F_V100,
SAVE_TYPE_SRAM_F_V102,
SAVE_TYPE_SRAM_F_V103,
SAVE_TYPE_SRAM_V110,
SAVE_TYPE_SRAM_V111,
SAVE_TYPE_SRAM_V112,
SAVE_TYPE_SRAM_V113,
SAVE_TYPE_TYPE_MASK = (3 << 14)
};
struct save_type
{
char tag[16];
u16 tagLength;
u16 type;
u32 size;
bool (* patchFunc)(const struct save_type* type);
};
extern u32 romSize;
const struct save_type* save_findTag();
void twoByteCpy(u16 *dst, const u16 *src, u32 size);
// #ifdef __cplusplus
// }
// #endif

View File

@ -1,487 +0,0 @@
#include "gba.h"
#include "Save.h"
extern u32 romSize;
extern bool savingAllowed;
u32 prefetchPatch[8] = {
0xE59F000C, // LDR R0, =0x4000204
0xE59F100C, // LDR R1, =0x4000
0xE4A01000, // STRT R1, [R0]
0xE59F0008, // LDR R0, =0x80000C0 (this changes, depending on the ROM)
0xE1A0F000, // MOV PC, R0
0x04000204,
0x00004000,
0x080000C0
};
static const u8 sDbzLoGUPatch1[0x24] =
{0x0A, 0x1C, 0x40, 0x0B, 0xE0, 0x21, 0x09, 0x05, 0x41, 0x18, 0x07, 0x31, 0x00, 0x23, 0x08, 0x78,
0x10, 0x70, 0x01, 0x33, 0x01, 0x32, 0x01, 0x39, 0x07, 0x2B, 0xF8, 0xD9, 0x00, 0x20, 0x70, 0xBC,
0x02, 0xBC, 0x08, 0x47
};
static const u8 sDbzLoGUPatch2[0x28] =
{0x70, 0xB5, 0x00, 0x04, 0x0A, 0x1C, 0x40, 0x0B, 0xE0, 0x21, 0x09, 0x05, 0x41, 0x18, 0x07, 0x31,
0x00, 0x23, 0x10, 0x78, 0x08, 0x70, 0x01, 0x33, 0x01, 0x32, 0x01, 0x39, 0x07, 0x2B, 0xF8, 0xD9,
0x00, 0x20, 0x70, 0xBC, 0x02, 0xBC, 0x08, 0x47
};
static const u8 wwTwistedPatch[0xF0] =
{
0x1F, 0x24, 0x1F, 0xB4, 0x33, 0x48, 0x01, 0x21, 0x01, 0x60, 0x33, 0x48, 0x01, 0x21, 0x01, 0x60,
0x32, 0x49, 0x0A, 0x68, 0x10, 0x23, 0x1A, 0x40, 0x1E, 0xD1, 0x30, 0x49, 0x0A, 0x68, 0x02, 0x23,
0x1A, 0x40, 0x0D, 0xD0, 0x2E, 0x48, 0x01, 0x68, 0x01, 0x22, 0x91, 0x42, 0x02, 0xDB, 0x09, 0x19,
0x01, 0x60, 0x38, 0xE0, 0x2A, 0x48, 0x01, 0x22, 0x02, 0x60, 0x12, 0x19, 0x02, 0x60, 0x32, 0xE0,
0x27, 0x48, 0x01, 0x68, 0x01, 0x22, 0x91, 0x42, 0x00, 0xDB, 0x01, 0xE0, 0x02, 0x60, 0x11, 0x1C,
0x24, 0x4B, 0xC9, 0x18, 0x01, 0x60, 0x26, 0xE0, 0x20, 0x49, 0x0A, 0x68, 0x20, 0x23, 0x1A, 0x40,
0x1E, 0xD1, 0x1E, 0x49, 0x0A, 0x68, 0x02, 0x23, 0x1A, 0x40, 0x0D, 0xD0, 0x1C, 0x48, 0x01, 0x68,
0x1D, 0x4A, 0x91, 0x42, 0x02, 0xDC, 0x09, 0x1B, 0x01, 0x60, 0x14, 0xE0, 0x18, 0x48, 0x1A, 0x4A,
0x02, 0x60, 0x12, 0x1B, 0x02, 0x60, 0x0E, 0xE0, 0x15, 0x48, 0x01, 0x68, 0x16, 0x4A, 0x91, 0x42,
0x00, 0xDC, 0x01, 0xE0, 0x02, 0x60, 0x11, 0x1C, 0x12, 0x4B, 0xC9, 0x1A, 0x01, 0x60, 0x02, 0xE0,
0x0F, 0x48, 0x01, 0x21, 0x01, 0x60, 0x1F, 0xBC, 0x0C, 0x48, 0x00, 0x88, 0x0F, 0x4A, 0x10, 0x47,
0x00, 0x7F, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0x03, 0x30, 0x01, 0x00, 0x04, 0x4B, 0x13, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x03, 0x98, 0x0F, 0x00, 0x03, 0x30, 0x01, 0x00, 0x04,
0x30, 0x10, 0x00, 0x03, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4B, 0x13, 0x00, 0x08
};
static const u8 yoshiTopsyTurvyPatch[0x18C] =
{
0x0C, 0x20, 0x9F, 0xE5, 0x80, 0x30, 0xA0, 0xE3, 0x00, 0x30, 0xE2, 0xE4, 0x04, 0x30, 0x9F, 0xE5,
0x13, 0xFF, 0x2F, 0xE1, 0xE0, 0x7F, 0x00, 0x03, 0x69, 0x51, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xB5, 0x01, 0x4F, 0x00, 0x00, 0x09, 0xE0, 0xE0, 0x7F, 0x00, 0x03, 0x02, 0x49, 0x09, 0x88,
0x01, 0x23, 0x08, 0x40, 0x70, 0x47, 0x00, 0x00, 0x30, 0x01, 0x00, 0x04, 0x3D, 0x78, 0x7F, 0x1C,
0x80, 0x26, 0x35, 0x42, 0x24, 0xD0, 0x33, 0x48, 0x00, 0x21, 0x00, 0x88, 0x88, 0x42, 0x04, 0xD1,
0x31, 0x49, 0x20, 0x20, 0x00, 0x02, 0x02, 0x30, 0x08, 0x80, 0x30, 0x48, 0x03, 0x21, 0x00, 0x88,
0x88, 0x42, 0x04, 0xD1, 0x2E, 0x49, 0x20, 0x20, 0x00, 0x02, 0x02, 0x30, 0x08, 0x80, 0x02, 0x20,
0x00, 0x02, 0x00, 0x30, 0xFF, 0xF7, 0xDA, 0xFF, 0x02, 0xD1, 0x2A, 0x49, 0x00, 0x20, 0x08, 0x80,
0x01, 0x20, 0xFF, 0x30, 0xFF, 0xF7, 0xD2, 0xFF, 0x02, 0xD1, 0x27, 0x49, 0x03, 0x20, 0x08, 0x80,
0x76, 0x08, 0x35, 0x42, 0x02, 0xD0, 0x25, 0x49, 0x63, 0x20, 0x08, 0x70, 0x76, 0x08, 0x35, 0x42,
0x04, 0xD0, 0x23, 0x49, 0x27, 0x20, 0x00, 0x02, 0x0F, 0x30, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42,
0x02, 0xD0, 0x20, 0x49, 0x03, 0x20, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42, 0x22, 0xD0, 0x1E, 0x49,
0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x1C, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30,
0x08, 0x80, 0x1B, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x19, 0x49, 0xAA, 0x20,
0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x18, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80,
0x16, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x15, 0x49, 0xAA, 0x20, 0x00, 0x02,
0xAA, 0x30, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42, 0x02, 0xD0, 0x12, 0x49, 0x0A, 0x20, 0x08, 0x80,
0x00, 0x00, 0x21, 0xE0, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03,
0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xD8, 0x03, 0x00, 0x03,
0xF8, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0xDA, 0x03, 0x00, 0x03, 0xDC, 0x03, 0x00, 0x03,
0xDE, 0x03, 0x00, 0x03, 0xE0, 0x03, 0x00, 0x03, 0xE2, 0x03, 0x00, 0x03, 0xE4, 0x03, 0x00, 0x03,
0xE6, 0x03, 0x00, 0x03, 0x48, 0x29, 0x00, 0x02, 0xFF, 0xBD, 0x00, 0x00, 0x00, 0xB5, 0x03, 0x48,
0xFE, 0x46, 0x00, 0x47, 0x01, 0xBC, 0x86, 0x46, 0x01, 0xBC, 0x01, 0xE0, 0x01, 0x9C, 0x7B, 0x08,
0x02, 0x48, 0x00, 0x88, 0xC0, 0x43, 0x80, 0x05, 0x81, 0x0D, 0x01, 0xE0, 0x30, 0x01, 0x00, 0x04,
0x03, 0xB4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xBD, 0x18, 0x1A, 0x00, 0x08
};
void patchGeneralWhiteScreen()
{
u32 entryPoint = *(u32*)0x08000000;
entryPoint -= 0xEA000000;
entryPoint += 2;
prefetchPatch[7] = 0x08000000+(entryPoint*4);
u32 patchOffset = 0x01FFFFDC;
{
vu32 *patchAddr = (vu32*)(0x08000000+patchOffset);
for(int i=0;i<8;i++){
patchAddr[i] = prefetchPatch[i];
}
}
u32 branchCode = 0xEA000000+(patchOffset/sizeof(u32))-2;
*(vu32*)0x08000000 = branchCode;
u32 searchRange = 0x08000000+romSize;
if (romSize > 0x01FFFFDC) searchRange = 0x09FFFFDC;
// General fix for white screen crash
// Patch out wait states
for (u32 addr = 0x080000C0; addr < searchRange; addr+=4) {
if (*(u32*)addr == 0x04000204 &&
(*(u8*)(addr-1) == 0x00 || *(u8*)(addr-1) == 0x03 || *(u8*)(addr-1) == 0x04 || *(u8*)(addr+7) == 0x04
|| *(u8*)(addr-1) == 0x08 || *(u8*)(addr-1) == 0x09
|| *(u8*)(addr-1) == 0x47 || *(u8*)(addr-1) == 0x81 || *(u8*)(addr-1) == 0x85
|| *(u8*)(addr-1) == 0xE0 || *(u8*)(addr-1) == 0xE7 || *(u16*)(addr-2) == 0xFFFE))
{
*(vu32*)addr = 0;
}
}
// Also check at 0x410
if (*(u32*)0x08000410 == 0x04000204) {
*(vu32*)0x08000410 = 0;
}
}
void patchSpecificGame(){
u32 nop = 0xE1A00000;
u32 gameCode = *(u32*)(0x080000AC);
if (gameCode == 0x50584C42) {
//Astreix & Obelix XXL (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x50118) == 0x4014)
*(u16*)(0x08000000 + 0x50118) = 0x4000;
} else if (gameCode == 0x454D4441) {
//Doom (USA)
//Fix black screen crash
if (*(u16*)(0x08000000 + 0x51C) == 0x45B6)
*(u16*)(0x08000000 + 0x51C) = 0x4002;
} else if (gameCode == 0x45443941 || gameCode == 0x50443941) {
//Doom II (USA/Europe)
//Fix black screen crash
if (*(u16*)(0x08000000 + 0x2856) == 0x5281)
*(u16*)(0x08000000 + 0x2856) = 0x46C0;
} else if (gameCode == 0x45474C41) {
//Dragon Ball Z - The Legacy of Goku (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x96E8) == 0x80A8)
*(u16*)(0x08000000 + 0x96E8) = 0x46C0;
//Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x356) == 0x7002)
*(u16*)(0x08000000 + 0x356) = 0;
if (*(u16*)(0x08000000 + 0x35E) == 0x7043)
*(u16*)(0x08000000 + 0x35E) = 0;
if (*(u16*)(0x08000000 + 0x37E) == 0x7001)
*(u16*)(0x08000000 + 0x37E) = 0;
if (*(u16*)(0x08000000 + 0x382) == 0x7041)
*(u16*)(0x08000000 + 0x382) = 0;
if (*(u16*)(0x08000000 + 0xE27E) == 0xB0A2) {
*(u16*)(0x08000000 + 0xE27E) = 0x400;
for (int i = 0; i < (int)sizeof(sDbzLoGUPatch1); i += 2)
*(u16*)(0x08000000 + 0xE280 + i) = *(u16*)&sDbzLoGUPatch1[i];
for (int i = 0; i < (int)sizeof(sDbzLoGUPatch2); i += 2)
*(u16*)(0x08000000 + 0xE32C + i) = *(u16*)&sDbzLoGUPatch2[i];
}
} else if (gameCode == 0x50474C41) {
//Dragon Ball Z - The Legacy of Goku (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x9948) == 0x80B0)
*(u16*)(0x08000000 + 0x9948) = 0x46C0;
//Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x33C) == 0x7119)
*(u16*)(0x08000000 + 0x33C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x340) == 0x7159)
*(u16*)(0x08000000 + 0x340) = 0x46C0;
if (*(u16*)(0x08000000 + 0x356) == 0x705A)
*(u16*)(0x08000000 + 0x356) = 0x46C0;
if (*(u16*)(0x08000000 + 0x35A) == 0x7002)
*(u16*)(0x08000000 + 0x35A) = 0x46C0;
if (*(u16*)(0x08000000 + 0x35E) == 0x7042)
*(u16*)(0x08000000 + 0x35E) = 0x46C0;
if (*(u16*)(0x08000000 + 0x384) == 0x7001)
*(u16*)(0x08000000 + 0x384) = 0x46C0;
if (*(u16*)(0x08000000 + 0x388) == 0x7041)
*(u16*)(0x08000000 + 0x388) = 0x46C0;
if (*(u16*)(0x08000000 + 0x494C) == 0x7002)
*(u16*)(0x08000000 + 0x494C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x4950) == 0x7042)
*(u16*)(0x08000000 + 0x4950) = 0x46C0;
if (*(u16*)(0x08000000 + 0x4978) == 0x7001)
*(u16*)(0x08000000 + 0x4978) = 0x46C0;
if (*(u16*)(0x08000000 + 0x497C) == 0x7041)
*(u16*)(0x08000000 + 0x497C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x988E) == 0x7028)
*(u16*)(0x08000000 + 0x988E) = 0x46C0;
if (*(u16*)(0x08000000 + 0x9992) == 0x7068)
*(u16*)(0x08000000 + 0x9992) = 0x46C0;
} else if (gameCode == 0x45464C41) {
//Dragon Ball Z - The Legacy of Goku II (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x3B8E9E) == 0x1102)
*(u16*)(0x08000000 + 0x3B8E9E) = 0x1001;
if (*(u16*)(0x08000000 + 0x3B8EAE) == 0x0003)
*(u16*)(0x08000000 + 0x3B8EAE) = 0;
} else if (gameCode == 0x4A464C41) {
//Dragon Ball Z - The Legacy of Goku II International (Japan)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x3FC8F6) == 0x1102)
*(u16*)(0x08000000 + 0x3FC8F6) = 0x1001;
if (*(u16*)(0x08000000 + 0x3FC906) == 0x0003)
*(u16*)(0x08000000 + 0x3FC906) = 0;
} else if (gameCode == 0x50464C41) {
//Dragon Ball Z - The Legacy of Goku II (Europe)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x6F42B2) == 0x1102)
*(u16*)(0x08000000 + 0x6F42B2) = 0x1001;
if (*(u16*)(0x08000000 + 0x6F42C2) == 0x0003)
*(u16*)(0x08000000 + 0x6F42C2) = 0;
} else if (gameCode == 0x45464C42) {
//2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
if (*(u16*)(0x08000000 + 0x49840) == 0x80A8)
*(u16*)(0x08000000 + 0x49840) = 0x46C0;
// tonccpy((u16*)0x088000E0, &nop, sizeof(u32));
*((u32*)0x080000E0) = nop;
//LoG1: Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x40356) == 0x7002)
*(u16*)(0x08000000 + 0x40356) = 0;
if (*(u16*)(0x08000000 + 0x4035E) == 0x7043)
*(u16*)(0x08000000 + 0x4035E) = 0;
if (*(u16*)(0x08000000 + 0x4037E) == 0x7001)
*(u16*)(0x08000000 + 0x4037E) = 0;
if (*(u16*)(0x08000000 + 0x40382) == 0x7041)
*(u16*)(0x08000000 + 0x40382) = 0;
//Do we need this?
/*if (*(u16*)(0x08000000 + 0x4E316) == 0xB0A2) {
*(u16*)(0x08000000 + 0x4E316) = 0x400;
for (int i = 0; i < sizeof(sDbzLoGUPatch1); i += 2)
*(u16*)(0x08000000 + 0x4E318 + i) = *(u16*)&sDbzLoGUPatch1[i];
for (int i = 0; i < sizeof(sDbzLoGUPatch2); i += 2)
*(u16*)(0x08000000 + 0x????? + i) = *(u16*)&sDbzLoGUPatch2[i];
}*/
//LoG2: Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0xBB9016) == 0x1102)
*(u16*)(0x08000000 + 0xBB9016) = 0x1001;
if (*(u16*)(0x08000000 + 0xBB9026) == 0x0003)
*(u16*)(0x08000000 + 0xBB9026) = 0;
} else if (gameCode == 0x45424442) {
//Dragon Ball Z - Taiketsu (USA)
//Fix "game cannot be played on this hardware" error
if (*(u16*)(0x08000000 + 0x2BD54) == 0x7818)
*(u16*)(0x08000000 + 0x2BD54) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BD60) == 0x7810)
*(u16*)(0x08000000 + 0x2BD60) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BD80) == 0x703A)
*(u16*)(0x08000000 + 0x2BD80) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BD82) == 0x7839)
*(u16*)(0x08000000 + 0x2BD82) = 0x2100;
if (*(u16*)(0x08000000 + 0x2BD8C) == 0x7030)
*(u16*)(0x08000000 + 0x2BD8C) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BD8E) == 0x7830)
*(u16*)(0x08000000 + 0x2BD8E) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BDAC) == 0x7008)
*(u16*)(0x08000000 + 0x2BDAC) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BDB2) == 0x7008)
*(u16*)(0x08000000 + 0x2BDB2) = 0x1C00;
} else if (gameCode == 0x50424442) {
//Dragon Ball Z - Taiketsu (Europe)
//Fix "game cannot be played on this hardware" error
if (*(u16*)(0x08000000 + 0x3FE08) == 0x7818)
*(u16*)(0x08000000 + 0x3FE08) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE14) == 0x7810)
*(u16*)(0x08000000 + 0x3FE14) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE34) == 0x703A)
*(u16*)(0x08000000 + 0x3FE34) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE36) == 0x7839)
*(u16*)(0x08000000 + 0x3FE36) = 0x2100;
if (*(u16*)(0x08000000 + 0x3FE40) == 0x7030)
*(u16*)(0x08000000 + 0x3FE40) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE42) == 0x7830)
*(u16*)(0x08000000 + 0x3FE42) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE58) == 0x7008)
*(u16*)(0x08000000 + 0x3FE58) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE66) == 0x7008)
*(u16*)(0x08000000 + 0x3FE66) = 0x1C00;
} else if (gameCode == 0x45334742) {
//Dragon Ball Z - Buu's Fury (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on this hardware" error
if (*(u16*)(0x08000000 + 0x8B66) == 0x7032)
*(u16*)(0x08000000 + 0x8B66) = 0;
if (*(u16*)(0x08000000 + 0x8B6A) == 0x7072)
*(u16*)(0x08000000 + 0x8B6A) = 0;
if (*(u16*)(0x08000000 + 0x8B86) == 0x7008)
*(u16*)(0x08000000 + 0x8B86) = 0;
if (*(u16*)(0x08000000 + 0x8B8C) == 0x7031)
*(u16*)(0x08000000 + 0x8B8C) = 0;
if (*(u16*)(0x08000000 + 0x8B90) == 0x7071)
*(u16*)(0x08000000 + 0x8B90) = 0;
} else if (gameCode == 0x45345442) {
//Dragon Ball GT - Transformation (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
} else if (gameCode == 0x45465542) {
//2 Games in 1 - Dragon Ball Z - Buu's Fury & Dragon Ball GT - Transformation (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
*((u32*)0x080300E0) = nop;
*((u32*)0x088000E0) = nop;
// tonccpy((u16*)0x080300E0, &nop, sizeof(u32));
// tonccpy((u16*)0x088000E0, &nop, sizeof(u32));
//DBZ BF: Fix "game will not run on this hardware" error
if (*(u16*)(0x08000000 + 0x38B66) == 0x7032)
*(u16*)(0x08000000 + 0x38B66) = 0;
if (*(u16*)(0x08000000 + 0x38B6A) == 0x7072)
*(u16*)(0x08000000 + 0x38B6A) = 0;
if (*(u16*)(0x08000000 + 0x38B86) == 0x7008)
*(u16*)(0x08000000 + 0x38B86) = 0;
if (*(u16*)(0x08000000 + 0x38B8C) == 0x7031)
*(u16*)(0x08000000 + 0x38B8C) = 0;
if (*(u16*)(0x08000000 + 0x38B90) == 0x7071)
*(u16*)(0x08000000 + 0x38B90) = 0;
} else if (gameCode == 0x45564442) {
//Dragon Ball - Advanced Adventure (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10C240) == 0x8008)
*(u16*)(0x08000000 + 0x10C240) = 0x46C0;
} else if (gameCode == 0x50564442) {
//Dragon Ball - Advanced Adventure (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10CE3C) == 0x8008)
*(u16*)(0x08000000 + 0x10CE3C) = 0x46C0;
} else if (gameCode == 0x4A564442) {
//Dragon Ball - Advanced Adventure (Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10B078) == 0x8008)
*(u16*)(0x08000000 + 0x10B078) = 0x46C0;
} else if (gameCode == 0x454B3842) {
//Kirby and the Amazing Mirror (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x1515A4) == 0x8008)
*(u16*)(0x08000000 + 0x1515A4) = 0x46C0;
} else if (gameCode == 0x504B3842) {
//Kirby and the Amazing Mirror (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x151EE0) == 0x8008)
*(u16*)(0x08000000 + 0x151EE0) = 0x46C0;
} else if (gameCode == 0x4A4B3842) {
//Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (V1.1)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x151564) == 0x8008)
*(u16*)(0x08000000 + 0x151564) = 0x46C0;
} else if (gameCode == 0x45533342) {
//Sonic Advance 3 (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBB67C) == 0x8008)
*(u16*)(0x08000000 + 0xBB67C) = 0x46C0;
} else if (gameCode == 0x50533342) {
//Sonic Advance 3 (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBBA04) == 0x8008)
*(u16*)(0x08000000 + 0xBBA04) = 0x46C0;
} else if (gameCode == 0x4A533342) {
//Sonic Advance 3 (Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBB9F8) == 0x8008)
*(u16*)(0x08000000 + 0xBB9F8) = 0x46C0;
} else if (gameCode == 0x45593241) {
//Top Gun - Combat Zones (USA)
//Fix softlock when attempting to save (original cartridge does not have a save chip)
if (*(u16*)(0x08000000 + 0x88816) == 0x3501)
*(u16*)(0x08000000 + 0x88816) = 0x3401;
savingAllowed = false;
} else if (gameCode == 0x45415741 || gameCode == 0x4A415741) {
//Wario Land 4/Advance (USA/Europe/Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x726) == 0x8008)
*(u16*)(0x08000000 + 0x726) = 0x46C0;
} else if (gameCode == 0x43415741) {
//Wario Land Advance (iQue)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xE92) == 0x8008)
*(u16*)(0x08000000 + 0xE92) = 0x46C0;
} else if (gameCode == 0x45575A52) {
//WarioWare: Twisted! (USA)
//Patch out tilt controls
if (*(u16*)(0x08000000 + 0x1348) == 0x8800)
*(u16*)(0x08000000 + 0x1348) = 0x4700;
if (*(u16*)(0x08000000 + 0x1376) == 0x0400 && *(u16*)(0x08000000 + 0x1374) == 0x0130) {
*(u16*)(0x08000000 + 0x1376) = 0x08E9;
*(u16*)(0x08000000 + 0x1374) = 0x3C6D;
// tonccpy((u8*)0x08E93C6C, &wwTwistedPatch, 0xF0);
twoByteCpy((u16*)0x08E93C6C,(const u16*)wwTwistedPatch,0xF0);
}
} else if (gameCode == 0x4547594B) {
//Yoshi Topsy-Turvy (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x16E4) == 0x8008)
*(u16*)(0x08000000 + 0x16E4) = 0x46C0;
//Patch out tilt controls
if (*(u16*)(0x08000000 + 0x1F2) == 0x0802 && *(u16*)(0x08000000 + 0x1F0) == 0x5169) {
*(u16*)(0x08000000 + 0x1F2) = 0x087B;
*(u16*)(0x08000000 + 0x1F0) = 0x9BE0;
// tonccpy((u8*)0x087B9BE0, &yoshiTopsyTurvyPatch, 0x18C);
twoByteCpy((u16*)0x087B9BE0,(const u16*)yoshiTopsyTurvyPatch,0x18C);
}
if (*(u16*)(0x08000000 + 0x1A0E) == 0x4808)
*(u16*)(0x08000000 + 0x1A0E) = 0xB401;
if (*(u16*)(0x08000000 + 0x1A10) == 0x8800)
*(u16*)(0x08000000 + 0x1A10) = 0x4800;
if (*(u16*)(0x08000000 + 0x1A12) == 0x43C0)
*(u16*)(0x08000000 + 0x1A12) = 0x4700;
if (*(u16*)(0x08000000 + 0x1A14) == 0x0580)
*(u16*)(0x08000000 + 0x1A14) = 0x9D3D;
if (*(u16*)(0x08000000 + 0x1A16) == 0x0D81)
*(u16*)(0x08000000 + 0x1A16) = 0x087B;
}
}

View File

@ -1,5 +0,0 @@
#pragma once
void patchGeneralWhiteScreen();
void patchSpecificGame();

View File

@ -1,20 +0,0 @@
#ifndef FIND_H
#define FIND_H
#include <gba.h>
// #ifdef __cplusplus
// extern "C" {
// #endif
// COMMON
//u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize);
u32* memsearch32(const u32* start, u32 dataSize, const u32* find, u32 findSize, bool forward);
u16* memsearch16(const u16* start, u32 dataSize, const u16* find, u32 findSize, bool forward);
u8* memsearch8(const u8* start, u32 dataSize, const u8* find, u32 findSize, bool forward);
// #ifdef __cplusplus
// }
// #endif
#endif // FIND_H

View File

@ -1,130 +0,0 @@
//#include <string.h> // memcmp
#include <stddef.h> // NULL
#include <gba.h>
//#include <limits.h>
// (memcmp is slower)
//#define memcmp __builtin_memcmp
//#define TABLE_SIZE (UCHAR_MAX + 1) // 256
/*
* Look for @find and return the position of it.
* Brute Force algorithm
*/
u32* memsearch32(const u32* start, u32 dataSize, const u32* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u32);
u32 findLen = findSize/sizeof(u32);
const u32* end = forward ? (start + dataLen) : (start - dataLen);
for (u32* addr = (u32*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u32*)addr;
}
}
return NULL;
}
u16* memsearch16(const u16* start, u32 dataSize, const u16* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u16);
u32 findLen = findSize/sizeof(u16);
const u16* end = forward ? (start + dataLen) : (start - dataLen);
for (u16* addr = (u16*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u16*)addr;
}
}
return NULL;
}
u8* memsearch8(const u8* start, u32 dataSize, const u8* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
const u8* end = forward ? (start + dataLen) : (start - dataLen);
for (u8* addr = (u8*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u8*)addr;
}
}
return NULL;
}
/*
* Boyer-Moore Horspool algorithm
*/
/*u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
u32 table[TABLE_SIZE];
// Preprocessing
for (u32 i = 0; i < TABLE_SIZE; ++i) {
table[i] = findLen;
}
for (u32 i = 0; i < findLen - 1; ++i) {
table[find[i]] = findLen - i - 1;
}
// Searching
u32 j = 0;
while (j <= dataLen - findLen) {
u8 c = start[j + findLen - 1];
if (find[findLen - 1] == c && memcmp(find, start + j, findLen - 1) == 0) {
return (u8*)start + j;
}
j += table[c];
}
return NULL;
}*/
/*
* Quick Search algorithm
*/
/*u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
u32 table[TABLE_SIZE];
// Preprocessing
for (u32 i = 0; i < TABLE_SIZE; ++i) {
table[i] = findLen + 1;
}
for (u32 i = 0; i < findLen; ++i) {
table[find[i]] = findLen - i;
}
// Searching
u32 j = 0;
while (j <= dataLen - findLen) {
if (memcmp(find, start + j, findLen) == 0) {
return (u8*)start + j;
}
j += table[start[j + findLen]];
}
return NULL;
}*/

View File

@ -1,7 +0,0 @@
#ifndef IRQ_HOOK_H
#define IRQ_HOOK_H
extern unsigned char irq_hook_bin[];
extern unsigned int irq_hook_bin_len;
#endif

View File

@ -1,770 +0,0 @@
#include <gba.h>
#include <fat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <errno.h>
#include "Save.h"
#include "WhiteScreenPatch.h"
#include "my_io_scsd.h"
#include "irq_hook.h"
char *stpcpy(char*, char*);
int strcasecmp(char*, char*);
bool overclock_ewram();
void restore_ewram_clocks();
void tryAgain() {
iprintf("Critical failure.\nPress A to restart.");
for (;;) {
scanKeys();
if (keysDown() & KEY_A)
for (;;) {
scanKeys();
if (keysUp() & KEY_A)
((void(*)()) 0x02000000)();
}
VBlankIntrWait();
}
}
enum
{
FILTER_ALL,
FILTER_SELECTABLE,
FILTER_GAME,
FILTER_LEN
};
bool filter_all(struct dirent *dirent);
bool filter_game(struct dirent *dirent);
bool filter_selectable(struct dirent *dirent);
bool (*filters[FILTER_LEN])(struct dirent*) = { &filter_all, &filter_selectable, &filter_game };
struct dirent_brief {
long off;
bool isdir;
char nickname[31];
};
enum
{
SORT_NONE,
SORT_NICKNAME,
SORT_FOLDER_NICKNAME,
SORT_LEN
};
int sort_nickname(void const *l, void const *r) {
return strncasecmp(((struct dirent_brief*) l)->nickname, ((struct dirent_brief*) r)->nickname, 31);
}
int sort_folder_nickname(void const *lv, void const *rv) {
struct dirent_brief *l = lv;
struct dirent_brief *r = rv;
if (l->isdir && !r->isdir)
return -1;
else if (!l->isdir && r->isdir)
return 1;
else
return sort_nickname(l, r);
}
int (*sorts[SORT_LEN])(void const*, void const*) = { NULL, &sort_nickname, &sort_folder_nickname };
struct settings {
int autosave;
int sram_patch;
int waitstate_patch;
int filter;
int sort;
int biosboot;
int soft_reset_patch;
int cold_boot_save;
};
struct settings settings = {
.autosave = 1,
.sram_patch = 1,
.waitstate_patch = 1,
.filter = FILTER_ALL,
.sort = SORT_NONE,
.biosboot = 1,
.soft_reset_patch = 1,
.cold_boot_save = 1
};
union paging_index {
s32 abs;
struct {
u32 row : 4;
s32 page : 28;
};
};
bool filter_all(struct dirent *dirent) {
if (!strcmp(dirent->d_name, "."))
return false;
return true;
}
bool filter_game(struct dirent *dirent) {
if (!strcmp(dirent->d_name, "."))
return false;
if (dirent->d_type == DT_DIR)
return true;
u32 namelen = strlen(dirent->d_name);
if (namelen > 4 && !strcasecmp(dirent->d_name + namelen - 4, ".gba"))
return true;
return false;
}
bool filter_selectable(struct dirent *dirent) {
if (!strcmp(dirent->d_name, "."))
return false;
if (dirent->d_type == DT_DIR)
return true;
u32 namelen = strlen(dirent->d_name);
if (namelen > 4 && !strcasecmp(dirent->d_name + namelen - 4, ".gba"))
return true;
if (namelen > 4 && !strcasecmp(dirent->d_name + namelen - 4, ".frm"))
return true;
if (!settings.autosave && namelen > 4 && !strcasecmp(dirent->d_name + namelen - 4, ".sav"))
return true;
return false;
}
#define GBA_ROM ((vu32*) 0x08000000)
#define GBA_BUS ((vu16*) 0x08000000)
#define GBA_SRAM ((vu8*) 0x0e000000)
#define SC_FLASH_MAGIC_ADDR_1 (*(vu16*) 0x08000b92)
#define SC_FLASH_MAGIC_ADDR_2 (*(vu16*) 0x0800046c)
#define SC_FLASH_MAGIC_1 ((u16) 0xaa)
#define SC_FLASH_MAGIC_2 ((u16) 0x55)
#define SC_FLASH_ERASE ((u16) 0x80)
#define SC_FLASH_ERASE_BLOCK ((u16) 0x30)
#define SC_FLASH_ERASE_CHIP ((u16) 0x10)
#define SC_FLASH_PROGRAM ((u16) 0xA0)
#define SC_FLASH_IDLE ((u16) 0xF0)
#define SC_FLASH_IDENTIFY ((u16) 0x90)
enum
{
SC_RAM_RO = 0x1,
// Bottom 16MB of SDRAM remains read/writable in this mode.
SC_MEDIA = 0x7,
SC_FLASH_RW = 0x4,
SC_RAM_RW = 0x5,
};
void sc_mode(u32 mode)
{
u32 ime = REG_IME;
REG_IME = 0;
*(vu16*)0x9FFFFFE = 0xA55A;
*(vu16*)0x9FFFFFE = 0xA55A;
*(vu16*)0x9FFFFFE = mode;
*(vu16*)0x9FFFFFE = mode;
REG_IME = ime;
}
IWRAM_DATA u8 filebuf[0x4000];
u32 pressed;
bool savingAllowed = true;
void setLastPlayed(char *path) {
/*
FILE *lastPlayed = fopen("/scfw/lastplayed.txt", "rb");
char old_path[PATH_MAX];
fread(old_path, PATH_MAX, 1, lastPlayed);
if (strcmp(path, old_path)) {
freopen("/scfw/lastplayed.txt", "wb", lastPlayed);
fwrite(path, strlen(path), 1, lastPlayed);
}
fclose(lastPlayed);
*/
FILE *lastPlayed = fopen("/scfw/lastplayed.txt", "wb");
fwrite(path, strlen(path), 1, lastPlayed);
fclose(lastPlayed);
}
void loadSram(char *path) {
sc_mode(SC_MEDIA);
FILE *sav = fopen(path, "rb");
if (sav) {
iprintf("Loading SRAM:\n\n");
u32 total_bytes = 0;
u32 bytes = 0;
do {
bytes = fread(filebuf, 1, sizeof filebuf, sav);
sc_mode(SC_RAM_RO);
for (int i = 0; i < bytes; ++i) {
GBA_SRAM[total_bytes + i] = filebuf[i];
if (GBA_SRAM[total_bytes + i] != filebuf[i]) {
iprintf("\x1b[1A\x1b[KSRAM write failed at\n0x%x\n\n", i + total_bytes);
}
}
sc_mode(SC_MEDIA);
total_bytes += bytes;
iprintf("\x1b[1A\x1b[K0x%x/0x10000\n", total_bytes);
} while (bytes);
fclose(sav);
} else {
iprintf("Save file does not exist.\n");
}
}
void saveSram(char *path) {
sc_mode(SC_MEDIA);
iprintf("Saving SRAM to %s\n\n", path);
FILE *sav = fopen(path, "wb");
if (sav) {
for (int i = 0; i < 0x00010000; i += sizeof filebuf) {
sc_mode(SC_RAM_RO);
for (int j = 0; j < sizeof filebuf; ++j)
filebuf[j] = GBA_SRAM[i + j];
sc_mode(SC_MEDIA);
fwrite(filebuf, sizeof filebuf, 1, sav);
iprintf("\x1b[1A\x1b[K0x%x/0x10000\n", i);
}
fclose(sav);
}
}
bool is_empty(s32 *buf, int size) {
bool ones = false;
bool zeroes = false;
for (int i = 0; i < size; ++i) {
if (buf[i] == 0 && !ones) {
zeroes = true;
}
else if (buf[i] == -1 && !zeroes) {
ones = true;
}
else {
return false;
}
}
return true;
}
void resetPatch(u32 romsize) {
iprintf("Soft reset patching...\n");
sc_mode(SC_RAM_RW);
u32 original_branch = *GBA_ROM;
u32 original_entrypoint = ((original_branch & 0x00ffffff) << 2) + 0x08000008;
u32 patched_entrypoint = 0x09ffff00 - irq_hook_bin_len - 4;
if (patched_entrypoint < 0x08000000 + romsize)
while (patched_entrypoint > 0x080000c0) {
if (is_empty((s32*) patched_entrypoint, irq_hook_bin_len + 4))
break;
patched_entrypoint -= 4;
}
if (patched_entrypoint <= 0x080000c0) {
iprintf("Could not soft reset patch\n");
return;
}
u32 patched_branch = 0xea000000 | ((patched_entrypoint - 0x08000008) >> 2);
int ctr = 0;
for (int i = 0; i < romsize >> 2; ++i)
if (GBA_ROM[i] == 0x03007ffc) {
GBA_ROM[i] = 0x03fffff4;
++ctr;
}
if (!ctr) {
iprintf("Could not soft reset patch!\n");
return;
}
*GBA_ROM = patched_branch;
int i;
for (i = 0; i < irq_hook_bin_len >> 2; ++i)
i[(u32*) patched_entrypoint] = i[(u32*) irq_hook_bin];
i[(u32*) patched_entrypoint] = original_entrypoint;
iprintf("Patched!\n");
}
void selectFile(char *path) {
u32 pathlen = strlen(path);
if (pathlen > 4 && !strcasecmp(path + pathlen - 4, ".gba")) {
FILE *rom = fopen(path, "rb");
fseek(rom, 0, SEEK_END);
u32 romsize = ftell(rom);
romSize = romsize;
fseek(rom, 0, SEEK_SET);
u32 total_bytes = 0;
u32 bytes = 0;
iprintf("Loading ROM:\n\n");
do {
bytes = fread(filebuf, 1, sizeof filebuf, rom);
sc_mode(SC_RAM_RW);
DMA_Copy(3, filebuf, &GBA_ROM[total_bytes >> 2], DMA32 | bytes >> 2);
/*
for (u32 i = 0; i < bytes; i += 4) {
GBA_ROM[(i + total_bytes) >> 2] = *(vu32*) &filebuf[i];
if (GBA_ROM[(i + total_bytes) >> 2] != *(vu32*) &filebuf[i]) {
iprintf("\x1b[1A\x1b[KSDRAM write failed at\n0x%x\n\n", i + total_bytes);
}
}
*/
sc_mode(SC_MEDIA);
total_bytes += bytes;
iprintf("\x1b[1A\x1b[K0x%x/0x%x\n", total_bytes, romsize);
} while (bytes && total_bytes < 0x02000000);
fclose(rom);
if (settings.autosave) {
char savname[PATH_MAX];
strcpy(savname, path);
strcpy(savname + pathlen - 4, ".sav");
loadSram(savname);
FILE *lastSaved = fopen("/scfw/lastsaved.txt", "wb");
fwrite(savname, pathlen, 1, lastSaved);
fclose(lastSaved);
}
if (settings.waitstate_patch) {
iprintf("Applying waitstate patches...\n");
sc_mode(SC_RAM_RW);
patchGeneralWhiteScreen();
patchSpecificGame();
iprintf("Waitstate patch done!\n");
}
if (settings.sram_patch) {
iprintf("Applying SRAM patch...\n");
sc_mode(SC_RAM_RW);
const struct save_type* saveType = savingAllowed ? save_findTag() : NULL;
if (saveType != NULL && saveType->patchFunc != NULL){
bool done = saveType->patchFunc(saveType);
if(!done)
printf("Save Type Patch Error\n");
} else {
printf("No need to patch\n");
}
}
if (settings.soft_reset_patch)
resetPatch(romSize);
sc_mode(SC_MEDIA);
iprintf("Let's go.\n");
setLastPlayed(path);
sc_mode(SC_RAM_RO);
REG_IME = 0;
restore_ewram_clocks();
if (settings.biosboot)
__asm volatile("swi 0x26");
else
SoftReset(ROM_RESTART);
} else if (pathlen > 4 && !strcasecmp(path + pathlen - 4, ".frm")) {
u32 ime = REG_IME;
REG_IME = 0;
iprintf("Probing flash ID.\n");
sc_mode(SC_FLASH_RW);
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_IDENTIFY;
u32 flash_id = SC_FLASH_MAGIC_ADDR_1;
flash_id |= *GBA_BUS << 16;
*GBA_BUS = SC_FLASH_IDLE;
iprintf("Flash ID is 0x%x\n", flash_id);
if (((flash_id >> 8) & 0xff) != 0x22) {
iprintf("Unrecognised flash ID.");
goto fw_end;
}
REG_IME = ime;
iprintf("Flash the Supercard firmware?\n"
"It may brick your Supercard!\n"
"Press A to flash.\n"
"Press any other key to cancel.\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!pressed);
if (pressed & KEY_A) {
sc_mode(SC_MEDIA);
iprintf("Opening firmware\n");
FILE *fw = fopen(path, "rb");
fseek(fw, 0, SEEK_END);
u32 fwsize = ftell(fw);
fseek(fw, 0, SEEK_SET);
if (fwsize > 0x80000) {
iprintf("Firmware too large!\n");
goto fw_flash_end;
}
ime = 0;
iprintf("Erasing flash.\n");
sc_mode(SC_FLASH_RW);
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE_CHIP;
while (*GBA_BUS != *GBA_BUS) {
}
*GBA_BUS = SC_FLASH_IDLE;
u32 total_bytes = 0;
u32 bytes = 0;
iprintf("Programming flash.\n\n");
do {
sc_mode(SC_MEDIA);
bytes = fread(filebuf, 1, sizeof filebuf, fw);
if (ferror(fw)) {
iprintf("Error reading file!\n");
goto fw_flash_end;
}
sc_mode(SC_FLASH_RW);
for (u32 i = 0; i < bytes; i += 2) {
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_PROGRAM;
GBA_BUS[(total_bytes + i)>>1] = filebuf[i] | (filebuf[i+1] << 8);
while (*GBA_BUS != *GBA_BUS) {
}
*GBA_BUS = SC_FLASH_IDLE;
}
sc_mode(SC_MEDIA);
total_bytes += bytes;
iprintf("\x1b[1A\x1b[K0x%x/0x%x\n", total_bytes, fwsize);
} while (bytes);
iprintf("Done!\n");
fw_flash_end:
if (fw)
fclose(fw);
}
fw_end:
REG_IME = ime;
iprintf("Press A to continue.\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & KEY_A));
} else if (pathlen > 4 && !strcasecmp(path + pathlen - 4, ".sav")) {
if (settings.autosave) {
iprintf("Disable autosave to manage\nSRAM manually.\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!pressed);
} else {
iprintf("Push L to load file to SRAM\n"
"Push R to save SRAM to file.\n"
"Push B to cancel.\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & (KEY_L | KEY_R | KEY_B)));
if (pressed & KEY_L) {
loadSram(path);
}
else if (pressed & KEY_R) {
saveSram(path);
}
}
} else {
iprintf("Unrecognised file extension!\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & KEY_A));
}
}
void change_settings(char *path) {
for (int cursor = 0;;) {
iprintf("\x1b[2J"
"SCFW Kernel v0.5.2 GBA-mode\n\n");
iprintf("%cAutosave: %i\n", cursor == 0 ? '>' : ' ', settings.autosave);
iprintf("%cSRAM Patch: %i\n", cursor == 1 ? '>' : ' ', settings.sram_patch);
iprintf("%cWaitstate Patch: %i\n", cursor == 2 ? '>' : ' ', settings.waitstate_patch);
iprintf("%cSoft reset Patch: %i\n", cursor == 3 ? '>' : ' ', settings.soft_reset_patch);
iprintf("%cBoot games through BIOS: %i\n", cursor == 4 ? '>' : ' ', settings.biosboot);
iprintf("%cAutosave after cold boot: %i\n", cursor == 5 ? '>' : ' ', settings.cold_boot_save);
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & (KEY_A | KEY_B | KEY_UP | KEY_DOWN)));
if (pressed & KEY_A) {
switch (cursor) {
case 0:
settings.autosave = !settings.autosave;
break;
case 1:
settings.sram_patch = !settings.sram_patch;
break;
case 2:
settings.waitstate_patch = !settings.waitstate_patch;
break;
case 3:
settings.soft_reset_patch = !settings.soft_reset_patch;
break;
case 4:
settings.biosboot = !settings.biosboot;
break;
case 5:
settings.cold_boot_save = !settings.cold_boot_save;
break;
}
}
if (pressed & KEY_B) {
break;
}
if (pressed & KEY_UP) {
--cursor;
if (cursor < 0)
cursor += 6;
}
if (pressed & KEY_DOWN) {
++cursor;
if (cursor >= 7)
cursor -= 6;
}
}
iprintf("Saving settings...\n");
FILE *settings_file = fopen("/scfw/settings.bin", "wb");
if (settings_file) {
fwrite(&settings, 1, sizeof settings, settings_file);
fclose(settings_file);
}
}
bool has_reset_token() {
sc_mode(SC_RAM_RW);
u32 reset_token = *(vu32*) 0x09ffff80;
sc_mode(SC_MEDIA);
return reset_token == 0xa55aa55a;
}
int main() {
irqInit();
irqEnable(IRQ_VBLANK);
scanKeys();
keysDownRepeat();
consoleDemoInit();
iprintf("SCFW Kernel v0.5.2 GBA-mode\n\n");
*(vu16*) 0x04000204 = 0x40c0;
if (overclock_ewram())
iprintf("Overclocked EWRAM\n");
else
iprintf("Could not overclock EWRAM\n");
_my_io_scsd.startup();
if (fatMountSimple("fat", &_my_io_scsd)) {
iprintf("FAT system initialised\n");
} else {
iprintf("FAT initialisation failed!\n");
tryAgain();
}
chdir("fat:/");
{
iprintf("Loading settings...\n");
FILE *settings_file = fopen("/scfw/settings.bin", "rb+");
if (settings_file) {
iprintf("Reading settings\n");
if (fread(&settings, 1, sizeof settings, settings_file) != sizeof settings) {
iprintf("Appending new defaults\n");
freopen("", "wb", settings_file);
fwrite(&settings, 1, sizeof settings, settings_file);
}
fclose(settings_file);
} else {
iprintf("Creating settings file\n");
settings_file = fopen("/scfw/settings.bin", "wb");
if (settings_file) {
fwrite(&settings, 1, sizeof settings, settings_file);
fclose(settings_file);
}
}
iprintf("Settings loaded!\n");
}
if (settings.autosave) {
if (settings.cold_boot_save || has_reset_token()) {
FILE *lastSaved = fopen("/scfw/lastsaved.txt", "rb");
if (lastSaved) {
char path[PATH_MAX];
path[fread(path, 1, PATH_MAX, lastSaved)] = '\0';
saveSram(path);
}
}
else {
iprintf("Skipping autosave due to cold boot.\n");
}
remove("/scfw/lastsaved.txt");
}
for (;;) {
char cwd[PATH_MAX];
getcwd(cwd, PATH_MAX);
u32 cwdlen = strlen(cwd);
DIR *dir = opendir(".");
EWRAM_DATA static struct dirent_brief dirents[0x200];
union paging_index dirents_len;
bool dirents_overflow = false;
dirents_len.abs = 0;
for (;;) {
u32 off = telldir(dir);
struct dirent *dirent = readdir(dir);
if (!dirent)
break;
if (dirents_len.abs >= 0x200) {
dirents_overflow = true;
break;
}
if ((*filters[settings.filter])(dirent)) {
dirents[dirents_len.abs].off = off;
dirents[dirents_len.abs].isdir = dirent->d_type == DT_DIR;
u32 namelen = strlen(dirent->d_name);
if (dirent->d_type == DT_DIR)
if (namelen > 27)
sprintf(dirents[dirents_len.abs].nickname, "%.20s*%s/", dirent->d_name, dirent->d_name + namelen - 6);
else
sprintf(dirents[dirents_len.abs].nickname, "%s/", dirent->d_name);
else
if (namelen > 28)
sprintf(dirents[dirents_len.abs].nickname, "%.20s*%s", dirent->d_name, dirent->d_name + namelen - 7);
else
sprintf(dirents[dirents_len.abs].nickname, "%s", dirent->d_name);
++dirents_len.abs;
}
}
if (!dirents_len.abs) {
iprintf("No directory entries!\n");
tryAgain();
}
if (sorts[settings.sort])
qsort(dirents, dirents_len.abs, sizeof *dirents, sorts[settings.sort]);
for (union paging_index cursor = { .abs = 0 };;) {
iprintf("\x1b[2J");
iprintf("%s\n%d/%d%s\n", cwdlen > 28 ? cwd + cwdlen - 28 : cwd, 1 + cursor.page, (union paging_index){ .abs = 15 + dirents_len.abs }.page, dirents_overflow ? "!" : "");
for (union paging_index i = { .page = cursor.page }; i.abs < dirents_len.abs && i.page == cursor.page; ++i.abs)
iprintf("%c%s\n", i.abs == cursor.abs ? '>' : ' ', dirents[i.abs].nickname);
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & (KEY_A | KEY_B | KEY_START | KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_L | KEY_R)));
if (pressed & KEY_A) {
seekdir(dir, dirents[cursor.abs].off);
struct dirent *dirent = readdir(dir);
if (dirent->d_type == DT_DIR) {
chdir(dirent->d_name);
break;
} else {
char path[PATH_MAX];
char *ptr = stpcpy(path, cwd);
if (ptr[-1] != '/')
ptr = stpcpy(ptr, "/");
ptr = stpcpy(ptr, dirent->d_name);
selectFile(path);
}
}
else if (pressed & KEY_B) {
if (chdir(".."))
change_settings(NULL);
break;
}
else if (pressed & KEY_START) {
FILE *lastPlayed = fopen("/scfw/lastplayed.txt", "rb");
if (lastPlayed) {
char path[PATH_MAX];
path[fread(path, 1, PATH_MAX, lastPlayed)] = '\0';
fclose(lastPlayed);
selectFile(path);
} else {
iprintf("Could not open last played.\n");
do {
scanKeys();
pressed = keysDownRepeat();
VBlankIntrWait();
} while (!(pressed & KEY_A));
}
}
else if (pressed & KEY_DOWN) {
++cursor.row;
if (cursor.abs >= dirents_len.abs)
cursor.row = 0;
}
else if (pressed & KEY_UP) {
--cursor.row;
if (cursor.abs >= dirents_len.abs)
cursor.row = dirents_len.row - 1;
}
else if (pressed & KEY_LEFT) {
--cursor.page;
if (cursor.abs < 0) {
u32 row = cursor.row;
cursor.abs = dirents_len.abs - 1;
if (row < cursor.row)
cursor.row = row;
}
}
else if (pressed & KEY_RIGHT) {
++cursor.page;
if (cursor.page >= (union paging_index){ .abs = dirents_len.abs+15 }.page)
cursor.page = 0;
else if (cursor.abs >= dirents_len.abs) {
cursor.row = dirents_len.row - 1;
}
}
else if (pressed & KEY_L) {
++settings.sort;
if (settings.sort >= SORT_LEN)
settings.sort -= SORT_LEN;
break;
}
else if (pressed & KEY_R) {
++settings.filter;
if (settings.filter >= FILTER_LEN)
settings.filter -= FILTER_LEN;
break;
}
}
closedir(dir);
}
tryAgain();
}

View File

@ -1,47 +0,0 @@
/*
io_m3_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_sc_common.h"
/*-----------------------------------------------------------------
_SC_changeMode (was SC_Unlock)
Added by MightyMax
Modified by Chishm
Modified again by loopy
1=ram(readonly), 5=ram, 3=SD interface?
-----------------------------------------------------------------*/
void _SC_changeMode(u8 mode) {
vu16 *unlockAddress = (vu16*)0x09FFFFFE;
*unlockAddress = 0xA55A ;
*unlockAddress = 0xA55A ;
*unlockAddress = mode ;
*unlockAddress = mode ;
}

View File

@ -1,43 +0,0 @@
/*
io_sc_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IO_SC_COMMON_H
#define IO_SC_COMMON_H
#include <disc_io.h>
// Values for changing mode
#define SC_MODE_FLASH 0x1510
#define SC_MODE_RAM 0x5
#define SC_MODE_MEDIA 0x3
#define SC_MODE_RAM_RO 0x1
extern void _SC_changeMode (u8 mode);
#endif // IO_SC_COMMON_H

View File

@ -1,429 +0,0 @@
/*
io_scsd.c
Hardware Routines for reading a Secure Digital card
using the SC SD
Some code based on scsd_c.c, written by Amadeus
and Jean-Pierre Thomasset as part of DSLinux.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_scsd.h"
#include "my_io_sd_common.h"
#include "my_io_sc_common.h"
#define printf(...)
//---------------------------------------------------------------
// SCSD register addresses
#define REG_SCSD_CMD (*(vu16*)(0x09800000))
/* bit 0: command bit to read */
/* bit 7: command bit to write */
#define REG_SCSD_DATAWRITE (*(vu16*)(0x09000000))
#define REG_SCSD_DATAREAD (*(vu16*)(0x09100000))
#define REG_SCSD_DATAREAD_32 (*(vu32*)(0x09100000))
// abuse misaligned loads to rotate by 16 bits for free
#define REG_SCSD_DATAREAD_32_ROT16 (*(vu32*)(0x09100002))
#define REG_SCSD_LITE_ENABLE (*(vu16*)(0x09440000))
#define REG_SCSD_LOCK (*(vu16*)(0x09FFFFFE))
/* bit 0: 1 */
/* bit 1: enable IO interface (SD,CF) */
/* bit 2: enable R/W SDRAM access */
//---------------------------------------------------------------
// Responses
#define SCSD_STS_BUSY 0x100
#define SCSD_STS_INSERTED 0x300
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 100000 // Time to wait for the SC to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define BUSY_WAIT_TIMEOUT 500000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
#define BYTES_PER_READ 512
//---------------------------------------------------------------
// Variables required for tracking SD state
u32 _SCSD_relativeCardAddress = 0; // Preshifted Relative Card Address
bool isSDHC;
//---------------------------------------------------------------
// Internal SC SD functions
extern bool _SCSD_readData_s (u8 *buf);
extern bool _SCSD_writeData_s (u8 *data, u16* crc);
void _SCSD_unlock (void) {
_SC_changeMode (SC_MODE_MEDIA);
}
void _SCSD_enable_lite (void) {
REG_SCSD_LITE_ENABLE = 0;
}
bool _SCSD_sendCommand (u8 command, u32 argument) {
u8 databuff[6]; //SD卡的命令是6个字节
u8 *tempDataPtr = databuff;
int length = 6;
u16 dataByte;
int curBit;
int i;
*tempDataPtr++ = command | 0x40; //Byte1:最高位为01剩下的6bit是command
*tempDataPtr++ = argument>>24;
*tempDataPtr++ = argument>>16;
*tempDataPtr++ = argument>>8;
*tempDataPtr++ = argument; //剩下的4byte是命令
*tempDataPtr = _SD_CRC7 (databuff, 5); //最后的是进行CRC的校验
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) == 0) && (--i));
if (i == 0) {
return false;
}
dataByte = REG_SCSD_CMD;
tempDataPtr = databuff;
while (length--) {
dataByte = *tempDataPtr++;
for (curBit = 7; curBit >=0; curBit--){//#7bit也就是第8位是用来输出的不断移位输出
REG_SCSD_CMD = dataByte;
dataByte = dataByte << 1;
}
}
return true;
}
// Returns the response from the SD card to a previous command.
bool _SCSD_getResponse (u8* dest, u32 length) {
u32 i;
int dataByte;
int numBits = length * 8;
// Wait for the card to be non-busy
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
if (dest == NULL) {
return true;
}
if (i == 0) {
// Still busy after the timeout has passed
return false;
}
// The first bit is always 0
dataByte = 0;
numBits--;
// Read the remaining bits in the response.
// It's always most significant bit first
while (numBits--) {
dataByte = (dataByte << 1) | (REG_SCSD_CMD & 0x01);
if ((numBits & 0x7) == 0) {
// It's read a whole byte, so store it
*dest++ = (u8)dataByte;
dataByte = 0;
}
}
// Send 16 more clocks, 8 more than the delay required between a response and the next command
for (i = 0; i < 16; i++) {
dataByte = REG_SCSD_CMD;
}
return true;
}
inline bool _SCSD_getResponse_R1 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
inline bool _SCSD_getResponse_R1b (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
inline bool _SCSD_getResponse_R2 (u8* dest) {
return _SCSD_getResponse (dest, 17);
}
inline bool _SCSD_getResponse_R3 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
inline bool _SCSD_getResponse_R6 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
void _SCSD_sendClocks (u32 numClocks) {
do {
REG_SCSD_CMD;
} while (numClocks--);
}
bool _SCSD_cmd_6byte_response_my (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 6);
}
bool _SCSD_cmd_17byte_response_my (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 17);
}
bool _SCSD_initCard (void) {
_SCSD_enable_lite();
// Give the card time to stabilise
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_SCSD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard_SDHC (_SCSD_cmd_6byte_response_my,
_SCSD_cmd_17byte_response_my,
true,
&_SCSD_relativeCardAddress,&isSDHC);
}
/*
__attribute__((section(".iwram"), long_call))
bool _SCSD_readData (void* buffer) {
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
register u32 temp;
int i;
i = BUSY_WAIT_TIMEOUT;
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) && (--i));
if (i == 0) {
return false;
}
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--) {
temp = REG_SCSD_DATAREAD_32_ROT16;
temp = REG_SCSD_DATAREAD_32_ROT16;
*buff_u8++ = (u8)temp;
*buff_u8++ = (u8)(temp >> 8);
}
} else {
while(i--) {
temp = REG_SCSD_DATAREAD_32_ROT16;
temp = REG_SCSD_DATAREAD_32_ROT16;
*buff++ = temp;
}
}
for (i = 0; i < 8; i++) {
temp = REG_SCSD_DATAREAD_32;
}
temp = REG_SCSD_DATAREAD;
return true;
}
*/
//---------------------------------------------------------------
// Functions needed for the external interface
bool _SCSD_startUp_my (void) {
//printf("Starting _SCSD_startUp_my...\n");
_SCSD_unlock();
//printf("Unlocked in _SCSD_startUp_my.\n");
bool initResult = _SCSD_initCard();
//printf("Init card in _SCSD_startUp_my returned %d.\n", initResult);
return initResult;
}
bool _SCSD_isInserted_my (void) {
//printf("Starting _SCSD_isInserted_my...\n");
u8 responseBuffer[6];
if (!_SCSD_sendCommand(SEND_STATUS, 0)) {
//printf("Failed to send command in _SCSD_isInserted_my.\n");
return false;
}
if (!_SCSD_getResponse_R1(responseBuffer)) {
//printf("Failed to get response in _SCSD_isInserted_my.\n");
return false;
}
if (responseBuffer[0] != SEND_STATUS) {
//printf("Incorrect response in _SCSD_isInserted_my: Expected %d, got %d\n", SEND_STATUS, responseBuffer[0]);
return false;
}
//printf("Successful execution of _SCSD_isInserted_my.\n");
return true;
}
bool _SCSD_readSectors_my (u32 sector, u32 numSectors, void* buffer) {
//printf("Starting _SCSD_readSectors_my with sector %u and numSectors %u.\n", sector, numSectors);
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
u32 argument = isSDHC ? sector : sector * BYTES_PER_READ;
if (numSectors == 1) {
//printf("Reading single sector.\n");
if (!_SCSD_sendCommand(READ_SINGLE_BLOCK, argument)) {
//printf("Failed to send READ_SINGLE_BLOCK command.\n");
return false;
}
if (!_SCSD_readData_s(buffer)) {
//printf("Failed to read data for single sector.\n");
return false;
}
} else {
//printf("Reading multiple sectors.\n");
if (!_SCSD_sendCommand(READ_MULTIPLE_BLOCK, argument)) {
//printf("Failed to send READ_MULTIPLE_BLOCK command.\n");
return false;
}
for (i = 0; i < numSectors; i++, dest += BYTES_PER_READ) {
if (!_SCSD_readData_s(dest)) {
//printf("Failed to read data at sector %u.\n", i + sector);
return false;
}
}
//printf("Stopping transmission after multiple sectors.\n");
_SCSD_sendCommand(STOP_TRANSMISSION, 0);
_SCSD_getResponse_R1b(responseBuffer);
}
_SCSD_sendClocks(64);
//printf("Completed _SCSD_readSectors_my.\n");
return true;
}
bool _SCSD_writeSectors_my (u32 sector, u32 numSectors, const void* buffer) {
//printf("Starting _SCSD_writeSectors_my with sector %u and numSectors %u.\n", sector, numSectors);
u16 crc[4];
u8 responseBuffer[6];
u32 offset = isSDHC ? sector : sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
while (numSectors--) {
//printf("Writing sector at offset %u.\n", offset);
_SD_CRC16(data, BYTES_PER_READ, (u8*)crc);
_SCSD_sendCommand(WRITE_BLOCK, offset);
if (!_SCSD_getResponse_R1(responseBuffer)) {
//printf("Failed to get response after WRITE_BLOCK command.\n");
return false;
}
if (!_SCSD_writeData_s(data, crc)) {
//printf("Failed to write data and CRC.\n");
return false;
}
_SCSD_sendClocks(64);
offset += isSDHC ? 1 : BYTES_PER_READ;
data += BYTES_PER_READ;
i = WRITE_TIMEOUT;
do {
_SCSD_sendCommand(SEND_STATUS, _SCSD_relativeCardAddress);
if (!_SCSD_getResponse_R1(responseBuffer) || i-- <= 0) {
//printf("Timeout or error during write confirmation.\n");
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
//printf("Sector at offset %u written successfully.\n", offset - BYTES_PER_READ);
}
//printf("Completed _SCSD_writeSectors_my.\n");
return true;
}
bool _SCSD_clearStatus_my (void) {
//printf("Starting _SCSD_clearStatus_my...\n");
bool initResult = _SCSD_initCard();
//printf("Initialization in _SCSD_clearStatus_my returned %d.\n", initResult);
return initResult;
}
bool _SCSD_shutdown_my (void) {
//printf("Starting _SCSD_shutdown_my...\n");
_SC_changeMode(SC_MODE_RAM_RO);
//printf("Changed mode to SC_MODE_RAM_RO in _SCSD_shutdown_my.\n");
return true;
}
const DISC_INTERFACE _my_io_scsd = {
DEVICE_TYPE_SCSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCSD_startUp_my,
(FN_MEDIUM_ISINSERTED)&_SCSD_isInserted_my,
(FN_MEDIUM_READSECTORS)&_SCSD_readSectors_my,
(FN_MEDIUM_WRITESECTORS)&_SCSD_writeSectors_my,
(FN_MEDIUM_CLEARSTATUS)&_SCSD_clearStatus_my,
(FN_MEDIUM_SHUTDOWN)&_SCSD_shutdown_my
} ;

View File

@ -1,48 +0,0 @@
/*
io_scsd.h
Hardware Routines for reading a Secure Digital card
using the Supercard SD
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-22 - Chishm
* First release of stable code
*/
#ifndef IO_SCSD_H
#define IO_SCSD_H
// 'SCSD'
#define DEVICE_TYPE_SCSD 0x44534353
#include <disc_io.h>
// export interface
extern const DISC_INTERFACE _my_io_scsd ;
#endif // define IO_SCSD_H

View File

@ -1,274 +0,0 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ io_scsd_s.s
@
@ Hardware Routines for reading a Secure Digital card
@ using the SC SD
@
@ Based on code supplied by Romman
@
@ Copyright (c) 2006 Michael "Chishm" Chisholm
@
@ Redistribution and use in source and binary forms, with or without modification,
@ are permitted provided that the following conditions are met:
@
@ 1. Redistributions of source code must retain the above copyright notice,
@ this list of conditions and the following disclaimer.
@ 2. Redistributions in binary form must reproduce the above copyright notice,
@ this list of conditions and the following disclaimer in the documentation and/or
@ other materials provided with the distribution.
@ 3. The name of the author may not be used to endorse or promote products derived
@ from this software without specific prior written permission.
@
@ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
@ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
@ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
@ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
@ 2006-07-22 - Chishm
@ * First release of stable code
@
@ 2006-08-19 - Chishm
@ * Added SuperCard Lite support
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.section .iwram
.align 4
.arm
.equ REG_SCSD_DATAWRITE, 0x09000000
.equ REG_SCSD_DATAREAD, 0x09100000
.equ BYTES_PER_READ, 0x200
.equ SCSD_STS_BUSY, 0x100
.equ BUSY_WAIT_TIMEOUT, 0x10000
.equ FALSE, 0
.equ TRUE, 1
@ bool _SCSD_writeData_s (u8 *data, u16* crc)
.global _SCSD_writeData_s
_SCSD_writeData_s:
stmfd r13!, {r4-r5}
mov r5, #BYTES_PER_READ
mov r2, #REG_SCSD_DATAWRITE
@ Wait for a free data buffer on the SD card
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_busy_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #SCSD_STS_BUSY
beq _SCSD_writeData_busy_wait
ldrh r3, [r2] @ extra clock
mov r3, #0 @ start bit
strh r3,[r2]
@ Check if the data buffer is aligned on a halfword boundary
tst r0, #1
beq _SCSD_writeData_data_loop
@ Used when the source data is unaligned
_SCSD_writeData_data_loop_unaligned:
ldrb r3, [r0], #1
ldrb r4, [r0], #1
orr r3, r3, r4, lsl #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop_unaligned
b _SCSD_writeData_crc
@ Write the data to the card
@ 4 halfwords are transmitted to the Supercard at once, for timing purposes
@ Only the first halfword needs to contain data for standard SuperCards
@ For the SuperCard Lite, the data is split into 4 nibbles, one per halfword
_SCSD_writeData_data_loop:
ldrh r3, [r0], #2
@ This bit added for SCLite. Notice that the shift is not the same as in
@ the original (buggy) code supplied by Romman
add r3, r3, r3, lsl #20
mov r4, r3, lsr #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop
@ Send the data CRC
_SCSD_writeData_crc:
cmp r1, #0
movne r0, r1
movne r1, #0
movne r5, #8
bne _SCSD_writeData_data_loop
mov r3, #0xff @ end bit
strh r3, [r2]
@ Wait for the SD card to signal that it is finished recieving
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_finished_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #0x100
bne _SCSD_writeData_finished_wait
@ Send 8 more clocks, as required by the SD card
ldmia r2, {r3-r4}
@ return true for success
mov r0, #TRUE
_SCSD_writeData_return:
ldmfd r13!,{r4-r5}
bx r14
@ bool _SCSD_readData_s (u8 *data)
.global _SCSD_readData_s
_SCSD_readData_s:
push {r4, lr}
mov r2, #145 << 20
mov r1, #128 << 1
ldr r3, .L101
.L88:
ldrh r4, [r2]
tst r4, r1
beq .L87
subs r3, r3, #1
cmp r3, #0
bne .L88
mov r0, r3
b .L97
.L95:
ldr r2, .L101+4
b .L98
.L90:
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
ldr r1, [r2]
ldr r1, [r2]
strb r1, [r0], # 1
lsr r1, r1, #8
strb r1, [r0], # 1
.L98:
cmp r0, r3
bne .L90
.L92:
mov r3, #145 << 20
ldr r2, [r3]
mov r0, #1
ldr r2, [r3]
ldr r2, [r3]
ldr r2, [r3]
ldr r2, [r3]
ldr r2, [r3]
ldr r2, [r3]
ldr r2, [r3]
ldrh r3, [r3]
b .L97
.L100:
ldr r2, .L101+4
b .L99
.L91:
ldr r1, [r2]
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
swp r1, r4, [r2]
strh r1, [r0], # 2
ldr r1, [r2]
strh r1, [r0], # 2
.L99:
cmp r0, r3
bne .L91
b .L92
.L87:
mov r2, #128 << 2
add r3, r0, r2
lsls r2, r0, #31
bmi .L95
b .L100
.L97:
@ sp needed for prologue
pop {r4, lr}
bx lr
.L102:
.align 2
.L101:
.word 500000
.word 0x0b100002

View File

@ -1,248 +0,0 @@
/*
io_sd_common.c
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_sd_common.h"
#include <gba_console.h>
#define MAX_STARTUP_TRIES 1000 // Arbitrary value, check if the card is ready 20 times before giving up
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define iprintf(...)
/*
Improved CRC7 function provided by cory1492
Calculates the CRC of an SD command, and includes the end bit in the byte
*/
u8 _SD_CRC7_my(u8* data, int cnt) {
int i, a;
u8 crc, temp;
crc = 0;
for (a = 0; a < cnt; a++)
{
temp = data[a];
for (i = 0; i < 8; i++)
{
crc <<= 1;
if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
temp <<= 1;
}
}
crc = (crc << 1) | 1;
return(crc);
}
/*
Calculates the CRC16 for a sector of data. Calculates it
as 4 separate lots, merged into one buffer. This is used
for 4 SD data lines, not for 1 data line alone.
*/
void _SD_CRC16_my (u8* buff, int buffLength, u8* crc16buff) {
u32 a, b, c, d;
int count;
u32 bitPattern = 0x80808080; // r7
u32 crcConst = 0x1021; // r8
u32 dataByte = 0; // r2
a = 0; // r3
b = 0; // r4
c = 0; // r5
d = 0; // r6
buffLength = buffLength * 8;
do {
if (bitPattern & 0x80) dataByte = *buff++;
a = a << 1;
if ( a & 0x10000) a ^= crcConst;
if (dataByte & (bitPattern >> 24)) a ^= crcConst;
b = b << 1;
if (b & 0x10000) b ^= crcConst;
if (dataByte & (bitPattern >> 25)) b ^= crcConst;
c = c << 1;
if (c & 0x10000) c ^= crcConst;
if (dataByte & (bitPattern >> 26)) c ^= crcConst;
d = d << 1;
if (d & 0x10000) d ^= crcConst;
if (dataByte & (bitPattern >> 27)) d ^= crcConst;
bitPattern = (bitPattern >> 4) | (bitPattern << 28);
} while (buffLength-=4);
count = 16; // r8
do {
bitPattern = bitPattern << 4;
if (a & 0x8000) bitPattern |= 8;
if (b & 0x8000) bitPattern |= 4;
if (c & 0x8000) bitPattern |= 2;
if (d & 0x8000) bitPattern |= 1;
a = a << 1;
b = b << 1;
c = c << 1;
d = d << 1;
count--;
if (!(count & 0x01)) {
*crc16buff++ = (u8)(bitPattern & 0xff);
}
} while (count != 0);
return;
}
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
#define CMD8 8
#define CMD58 58
#define R1_ILLEGAL_COMMAND 0x04
bool _SD_InitCard_SDHC (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA,bool *isSDHC)
{
u8 responseBuffer[17] = {0};
int i;
*isSDHC = false;
bool cmd8Response = cmd_17byte_response(responseBuffer, CMD8, 0x1AA);//0xa 是确定的 0xAA是推荐值
iprintf("\n");
//CMD8 也就是 Send Interface Condition Command
//正确的回显是CMD8Ver=0,Reserved=0,EchoBack=1,EchoBack=0XAA
if (cmd8Response && responseBuffer[0] == CMD8 && responseBuffer[1] == 0 && responseBuffer[2] == 0 && responseBuffer[3] == 0x1 && responseBuffer[4] == 0xAA) {
*isSDHC = true;
iprintf("CMD8 Return OK,might be a SDHC\n");
}else{
iprintf("CMD8 ERR not SDHC\n");
iprintf("resp:");
for(int i=0;i<17;i++){
iprintf("[%d]=%X ",i,responseBuffer[i]);
}
}
for (i = 0; i < MAX_STARTUP_TRIES; i++) {
cmd_6byte_response(responseBuffer, APP_CMD, 0);//CMD55
if (responseBuffer[0] != APP_CMD) {
iprintf("Failed to send APP_CMD\n"); //进入到APP模式可以执行ACMD41
return false;
}
u32 arg = SD_OCR_VALUE;
if (*isSDHC) {
arg |= (1<<30); // Set HCS bit,Supports SDHC
arg |= (1<<28); //Max performance
}
if (cmd_6byte_response(responseBuffer, SD_APP_OP_COND, arg) &&//ACMD41
((responseBuffer[1] & (1<<7)) != 0)/*Busy:0b:initing 1b:init completed*/) {
iprintf("ACMD41 accepted init completed\n");
break; // Card is ready
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
if (isSDHC) {
cmd_6byte_response(responseBuffer, CMD58, 0);
iprintf("CMD58 response received\n");
// u32 ocr = (responseBuffer[1] << 24) | (responseBuffer[2] << 16) |
// (responseBuffer[3] << 8) | responseBuffer[4];
if ((responseBuffer[1] & (1<<6)) == 0) {//Card Capacity Status (CCS)
iprintf("CMD58 OCR ERROR!! Not SDHC\n\n");
*isSDHC = false;
}else{
iprintf("OCR OK! Is SDHC\n");
}
// Further processing of OCR can be done here if needed
}
// The card's name, as assigned by the manufacturer
cmd_17byte_response (responseBuffer, ALL_SEND_CID, 0);
// Get a new address
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
cmd_6byte_response (responseBuffer, SEND_RELATIVE_ADDR, 0);
*RCA = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
if ((responseBuffer[3] & 0x1e) != (SD_STATE_STBY << 1)) {
iprintf("RCA set\n");
break;
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
// Some cards won't go to higher speeds unless they think you checked their capabilities
cmd_17byte_response (responseBuffer, SEND_CSD, *RCA);
// Only this card should respond to all future commands
cmd_6byte_response (responseBuffer, SELECT_CARD, *RCA);
if (use4bitBus) {
// Set a 4 bit data bus
cmd_6byte_response (responseBuffer, APP_CMD, *RCA);
cmd_6byte_response (responseBuffer, SET_BUS_WIDTH, 2); // 4-bit mode.
}
// Use 512 byte blocks
cmd_6byte_response (responseBuffer, SET_BLOCKLEN, 512); // 512 byte blocks
// Wait until card is ready for data
i = 0;
do {
if (i >= RESPONSE_TIMEOUT) {
return false;
}
i++;
} while (!cmd_6byte_response (responseBuffer, SEND_STATUS, *RCA) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
return true;
}

View File

@ -1,116 +0,0 @@
/*
io_sd_common.h
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IO_SD_COMMON_H
#define IO_SD_COMMON_H
#include <disc_io.h>
/* SD commands */
#define GO_IDLE_STATE 0
#define ALL_SEND_CID 2
#define SEND_RELATIVE_ADDR 3
#define SELECT_CARD 7
#define SEND_CSD 9
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define APP_CMD 55
#define CMD8 8
#define CMD58 58
/* SD App commands */
#define SET_BUS_WIDTH 6
#define SD_APP_OP_COND 41
/* OCR (Operating Conditions Register) send value */
#define SD_OCR_VALUE 0x00030000 /* 2.8V to 3.0V */
//#define SD_OCR_VALUE 0x003F8000 /* 2.7V to 3.4V */
//#define SD_OCR_VALUE 0x00FC0000
/* SD Data repsonses */
#define SD_CARD_BUSY 0xff
/* SD states */
#define SD_STATE_IDLE 0 // Idle state, after power on or GO_IDLE_STATE command
#define SD_STATE_READY 1 // Ready state, after card replies non-busy to SD_APP_OP_COND
#define SD_STATE_IDENT 2 // Identification state, after ALL_SEND_CID
#define SD_STATE_STBY 3 // Standby state, when card is deselected
#define SD_STATE_TRAN 4 // Transfer state, after card is selected and ready for data transfer
#define SD_STATE_DATA 5 //
#define SD_STATE_RCV 6 // Receive data state
#define SD_STATE_PRG 7 // Programming state
#define SD_STATE_DIS 8 // Disconnect state
#define SD_STATE_INA 9 // Inactive state, after GO_INACTIVE_STATE
#define READY_FOR_DATA 1 // bit 8 in card status
///Mod:
#define R1_ILLEGAL_COMMAND 0x04
/*
Calculate the CRC7 of a command and return it preshifted with
an end bit added
*/
extern u8 _SD_CRC7(u8* data, int size);
/*
Calculate the CRC16 of a block of data, ready for transmission on
four data lines at once
*/
extern void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff);
typedef bool (*_SD_FN_CMD_6BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
typedef bool (*_SD_FN_CMD_17BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
extern bool _SD_InitCard_SDHC (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA,bool *isSDHC);
#endif // define IO_SD_COMMON_H

View File

@ -1,31 +0,0 @@
#include <gba.h>
#define MEMCNT (*(vu32*) 0x04000800)
IWRAM_CODE bool overclock_ewram() {
bool success = false;
int ime = REG_IME;
REG_IME = 0;
EWRAM_DATA static volatile int test_var;
u32 old_memcnt = MEMCNT;
test_var = 0;
if (old_memcnt == 0x0D000020) {
MEMCNT = 0x0E000020;
test_var = -1;
if (test_var == -1)
success = true;
else
MEMCNT = 0x0D000020;
}
else if (old_memcnt == 0x0E000020) {
success = true;
}
REG_IME = ime;
return success;
}
IWRAM_CODE void restore_ewram_clocks() {
MEMCNT = 0x0D000020;
}

View File

@ -1,5 +0,0 @@
Instructions:
Assemble scfw.s
Convert ELF to flat binary with objcopy
Fix GBA logo with gbafix

View File

@ -1,110 +0,0 @@
cart_base:
.org 0x00
b entrypoint
.org 0x04
.fill 0x9c, 0, 0
.org 0xa0
.ascii "DsBooterSCFW"
.org 0xac
.ascii "PASSsc"
.org 0xb2
.byte 0x96
.org 0xb4
.fill 8, 0, 0
.org 0xbc
.byte 0
.org 0xbd
.fill 3, 0, 0
.org 0xc0
entrypoint:
# copy and run this fn from RAM
mov r0, #0x02000000
adr r1, sc_mode_flash_rw
adr r2, sc_mode_flash_rw_end
sc_mode_flash_rw_loop:
ldr r3, [r1], # 4
str r3, [r0], # 4
cmp r1, r2
blt sc_mode_flash_rw_loop
mov lr, pc
mov pc, # 0x02000000
# detect GBA/NDS using mirroring
mov r0, # 0x02000000
mov r2, # 0
str r2, [r0]
add r1, r0, #0x00040000
mov r2, # 1
str r2, [r1]
ldr r2, [r0]
cmp r2, # 0
beq load_nds
# load & execute multiboot gba rom
load_gba:
adrl r0, gba_rom
adrl r1, gba_rom_end
mov r2, # 0x02000000
add lr, r2, # 0x000000c0
load_gba_loop:
ldr r3, [r0], # 4
str r3, [r2], # 4
cmp r0, r1
blt load_gba_loop
bx lr
# load & execute nds rom
load_nds:
adrl r0, nds_rom
ldr r1, [r0, # 0x20]
ldr r2, [r0, # 0x28]
ldr r3, [r0, # 0x2c]
add r1, r1, r0
add r3, r3, r1
load_nds_arm9_loop:
ldr r4, [r1], # 4
str r4, [r2], # 4
cmp r1, r3
blt load_nds_arm9_loop
ldr r1, [r0, # 0x30]
ldr r2, [r0, # 0x38]
ldr r3, [r0, # 0x3c]
add r1, r1, r0
add r3, r3, r1
load_nds_arm7_loop:
ldr r4, [r1], # 4
str r4, [r2], # 4
cmp r1, r3
blt load_nds_arm7_loop
mov r1, # 0x02800000
sub r1, r1, # 0x200
ldr r2, [r0, # 0x24]
str r2, [r1, # 0x24]
ldr lr, [r0, # 0x34]
bx lr
sc_mode_flash_rw:
mov r0, # 0x0a000000
sub r0, r0, #0x02
mov r1, # 0x005a
add r1, # 0xa500
strh r1, [r0]
strh r1, [r0]
mov r1, # 4
strh r1, [r0]
strh r1, [r0]
bx lr
sc_mode_flash_rw_end:
.balign 4, 0xff
gba_rom:
.incbin "../SCFW_Stage2_GBA/SCFW_Stage2_GBA_mb.gba"
gba_rom_end:
.balign 4, 0xff
nds_rom:
.incbin "../SCFW_Stage2_NDS/SCFW_Stage2_NDS.nds"
nds_rom_end:

View File

@ -1,135 +0,0 @@
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
endif
include $(DEVKITARM)/gba_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output, if this ends with _mb a multiboot image is generated
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))_mb
BUILD := build
SOURCES := source
DATA :=
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -v -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O0 -std=c99\
-mcpu=arm7tdmi -mtune=arm7tdmi\
$(ARCH)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := $(ARCH)
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# path to tools - this can be deleted if you set the path to the toolchain in windows
#---------------------------------------------------------------------------------
export PATH := $(DEVKITARM)/bin:$(PATH)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lfat -lgba
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBGBA)
#---------------------------------------------------------------------------------
# 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 OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
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)
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
all : $(BUILD)
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).gba : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
-include $(DEPENDS)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

View File

@ -1,112 +0,0 @@
#include <gba.h>
#include <fat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.H>
#include "my_io_scsd.h"
#define GBA_ROM ((vu32*) 0x08000000)
enum
{
SC_RAM_RO = 0x1,
SC_MEDIA = 0x3,
SC_RAM_RW = 0x5,
};
void sc_mode(u32 mode)
{
u32 ime = REG_IME;
REG_IME = 0;
*(vu16*)0x9FFFFFE = 0xA55A;
*(vu16*)0x9FFFFFE = 0xA55A;
*(vu16*)0x9FFFFFE = mode;
*(vu16*)0x9FFFFFE = mode;
REG_IME = ime;
}
void tryAgain() {
iprintf("Critical failure.\nPress A to restart.");
for (;;) {
scanKeys();
if (keysDown() & KEY_A)
for (;;) {
scanKeys();
if (keysUp() & KEY_A)
((void(*)()) 0x02000000)();
}
VBlankIntrWait();
}
}
EWRAM_BSS u8 filebuf[0x20000];
int main() {
irqInit();
irqEnable(IRQ_VBLANK);
consoleDemoInit();
iprintf("SCFW v0.5.2 GBA-mode\n\n");
_my_io_scsd.startup();
if (fatMountSimple("fat", &_my_io_scsd)) {
iprintf("FAT system initialised\n");
} else {
iprintf("FAT initialisation failed!\n");
tryAgain();
}
FILE *kernel = fopen("fat:/scfw/kernel.gba","rb");
if (kernel) {
iprintf("Kernel file opened successfully\n");
} else {
iprintf("Kernel file open failed\n");
tryAgain();
}
fseek(kernel, 0, SEEK_END);
u32 kernel_size = ftell(kernel);
if (kernel_size > 0x40000) {
iprintf("Kernel too large to load!\n");
tryAgain();
}
iprintf("Loading kernel\n\n");
fseek(kernel, 0, SEEK_SET);
u32 total_bytes = 0;
u32 bytes = 0;
do {
bytes = fread(filebuf, 1, sizeof filebuf, kernel);
sc_mode(SC_RAM_RW);
for (u32 i = 0; i < bytes; i += 4) {
GBA_ROM[(i + total_bytes) >> 2] = *(vu32*) &filebuf[i];
if (GBA_ROM[(i + total_bytes) >> 2] != *(vu32*) &filebuf[i]) {
iprintf("\x1b[1A\x1b[KSDRAM write failed at\n0x%x\n\n", i + total_bytes);
}
}
sc_mode(SC_MEDIA);
total_bytes += bytes;
iprintf("\x1b[1A\x1b[K0x%x/0x%x\n", total_bytes, kernel_size);
} while (bytes);
if (ferror(kernel)) {
iprintf("Error reading kernel.\n");
tryAgain();
}
sc_mode(SC_RAM_RO);
if ((*GBA_ROM & 0xff000000) != 0xea000000) {
iprintf("Unexpected ROM entrypont, kernel not GBA ROM?");
tryAgain();
}
iprintf("Kernel loaded successfully.\n");
iprintf("Let's go.\n");
SoftReset(ROM_RESTART);
iprintf("Unreachable, panic!\n");
tryAgain();
}

View File

@ -1,47 +0,0 @@
/*
io_m3_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_sc_common.h"
/*-----------------------------------------------------------------
_SC_changeMode (was SC_Unlock)
Added by MightyMax
Modified by Chishm
Modified again by loopy
1=ram(readonly), 5=ram, 3=SD interface?
-----------------------------------------------------------------*/
void _SC_changeMode(u8 mode) {
vu16 *unlockAddress = (vu16*)0x09FFFFFE;
*unlockAddress = 0xA55A ;
*unlockAddress = 0xA55A ;
*unlockAddress = mode ;
*unlockAddress = mode ;
}

View File

@ -1,43 +0,0 @@
/*
io_sc_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IO_SC_COMMON_H
#define IO_SC_COMMON_H
#include <disc_io.h>
// Values for changing mode
#define SC_MODE_FLASH 0x1510
#define SC_MODE_RAM 0x5
#define SC_MODE_MEDIA 0x3
#define SC_MODE_RAM_RO 0x1
extern void _SC_changeMode (u8 mode);
#endif // IO_SC_COMMON_H

View File

@ -1,423 +0,0 @@
/*
io_scsd.c
Hardware Routines for reading a Secure Digital card
using the SC SD
Some code based on scsd_c.c, written by Amadeus
and Jean-Pierre Thomasset as part of DSLinux.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_scsd.h"
#include "my_io_sd_common.h"
#include "my_io_sc_common.h"
#define printf(...)
//---------------------------------------------------------------
// SCSD register addresses
#define REG_SCSD_CMD (*(vu16*)(0x09800000))
/* bit 0: command bit to read */
/* bit 7: command bit to write */
#define REG_SCSD_DATAWRITE (*(vu16*)(0x09000000))
#define REG_SCSD_DATAREAD (*(vu16*)(0x09100000))
#define REG_SCSD_DATAREAD_32 (*(vu32*)(0x09100000))
#define REG_SCSD_LITE_ENABLE (*(vu16*)(0x09440000))
#define REG_SCSD_LOCK (*(vu16*)(0x09FFFFFE))
/* bit 0: 1 */
/* bit 1: enable IO interface (SD,CF) */
/* bit 2: enable R/W SDRAM access */
//---------------------------------------------------------------
// Responses
#define SCSD_STS_BUSY 0x100
#define SCSD_STS_INSERTED 0x300
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 100000 // Time to wait for the SC to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define BUSY_WAIT_TIMEOUT 500000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
#define BYTES_PER_READ 512
//---------------------------------------------------------------
// Variables required for tracking SD state
u32 _SCSD_relativeCardAddress = 0; // Preshifted Relative Card Address
bool isSDHC;
//---------------------------------------------------------------
// Internal SC SD functions
extern bool _SCSD_writeData_s (u8 *data, u16* crc);
void _SCSD_unlock (void) {
_SC_changeMode (SC_MODE_MEDIA);
}
void _SCSD_enable_lite (void) {
REG_SCSD_LITE_ENABLE = 0;
}
bool _SCSD_sendCommand (u8 command, u32 argument) {
u8 databuff[6]; //SD卡的命令是6个字节
u8 *tempDataPtr = databuff;
int length = 6;
u16 dataByte;
int curBit;
int i;
*tempDataPtr++ = command | 0x40; //Byte1:最高位为01剩下的6bit是command
*tempDataPtr++ = argument>>24;
*tempDataPtr++ = argument>>16;
*tempDataPtr++ = argument>>8;
*tempDataPtr++ = argument; //剩下的4byte是命令
*tempDataPtr = _SD_CRC7 (databuff, 5); //最后的是进行CRC的校验
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) == 0) && (--i));
if (i == 0) {
return false;
}
dataByte = REG_SCSD_CMD;
tempDataPtr = databuff;
while (length--) {
dataByte = *tempDataPtr++;
for (curBit = 7; curBit >=0; curBit--){//#7bit也就是第8位是用来输出的不断移位输出
REG_SCSD_CMD = dataByte;
dataByte = dataByte << 1;
}
}
return true;
}
// Returns the response from the SD card to a previous command.
bool _SCSD_getResponse (u8* dest, u32 length) {
u32 i;
int dataByte;
int numBits = length * 8;
// Wait for the card to be non-busy
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
if (dest == NULL) {
return true;
}
if (i == 0) {
// Still busy after the timeout has passed
return false;
}
// The first bit is always 0
dataByte = 0;
numBits--;
// Read the remaining bits in the response.
// It's always most significant bit first
while (numBits--) {
dataByte = (dataByte << 1) | (REG_SCSD_CMD & 0x01);
if ((numBits & 0x7) == 0) {
// It's read a whole byte, so store it
*dest++ = (u8)dataByte;
dataByte = 0;
}
}
// Send 16 more clocks, 8 more than the delay required between a response and the next command
for (i = 0; i < 16; i++) {
dataByte = REG_SCSD_CMD;
}
return true;
}
bool _SCSD_getResponse_R1 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
bool _SCSD_getResponse_R1b (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
inline bool _SCSD_getResponse_R2 (u8* dest) {
return _SCSD_getResponse (dest, 17);
}
inline bool _SCSD_getResponse_R3 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
inline bool _SCSD_getResponse_R6 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
void _SCSD_sendClocks (u32 numClocks) {
do {
REG_SCSD_CMD;
} while (numClocks--);
}
bool _SCSD_cmd_6byte_response_my (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 6);
}
bool _SCSD_cmd_17byte_response_my (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 17);
}
bool _SCSD_initCard (void) {
_SCSD_enable_lite();
// Give the card time to stabilise
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_SCSD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard_SDHC (_SCSD_cmd_6byte_response_my,
_SCSD_cmd_17byte_response_my,
true,
&_SCSD_relativeCardAddress,&isSDHC);
}
bool _SCSD_readData (void* buffer) {
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
volatile register u32 temp;
int i;
i = BUSY_WAIT_TIMEOUT;
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) && (--i));
if (i == 0) {
return false;
}
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff_u8++ = (u8)temp;
*buff_u8++ = (u8)(temp >> 8);
}
} else {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff++ = temp;
}
}
for (i = 0; i < 8; i++) {
temp = REG_SCSD_DATAREAD_32;
}
temp = REG_SCSD_DATAREAD;
return true;
}
//---------------------------------------------------------------
// Functions needed for the external interface
bool _SCSD_startUp_my (void) {
//printf("Starting _SCSD_startUp_my...\n");
_SCSD_unlock();
//printf("Unlocked in _SCSD_startUp_my.\n");
bool initResult = _SCSD_initCard();
//printf("Init card in _SCSD_startUp_my returned %d.\n", initResult);
return initResult;
}
bool _SCSD_isInserted_my (void) {
//printf("Starting _SCSD_isInserted_my...\n");
u8 responseBuffer[6];
if (!_SCSD_sendCommand(SEND_STATUS, 0)) {
//printf("Failed to send command in _SCSD_isInserted_my.\n");
return false;
}
if (!_SCSD_getResponse_R1(responseBuffer)) {
//printf("Failed to get response in _SCSD_isInserted_my.\n");
return false;
}
if (responseBuffer[0] != SEND_STATUS) {
//printf("Incorrect response in _SCSD_isInserted_my: Expected %d, got %d\n", SEND_STATUS, responseBuffer[0]);
return false;
}
//printf("Successful execution of _SCSD_isInserted_my.\n");
return true;
}
bool _SCSD_readSectors_my (u32 sector, u32 numSectors, void* buffer) {
//printf("Starting _SCSD_readSectors_my with sector %u and numSectors %u.\n", sector, numSectors);
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
u32 argument = isSDHC ? sector : sector * BYTES_PER_READ;
if (numSectors == 1) {
//printf("Reading single sector.\n");
if (!_SCSD_sendCommand(READ_SINGLE_BLOCK, argument)) {
//printf("Failed to send READ_SINGLE_BLOCK command.\n");
return false;
}
if (!_SCSD_readData(buffer)) {
//printf("Failed to read data for single sector.\n");
return false;
}
} else {
//printf("Reading multiple sectors.\n");
if (!_SCSD_sendCommand(READ_MULTIPLE_BLOCK, argument)) {
//printf("Failed to send READ_MULTIPLE_BLOCK command.\n");
return false;
}
for (i = 0; i < numSectors; i++, dest += BYTES_PER_READ) {
if (!_SCSD_readData(dest)) {
//printf("Failed to read data at sector %u.\n", i + sector);
return false;
}
}
//printf("Stopping transmission after multiple sectors.\n");
_SCSD_sendCommand(STOP_TRANSMISSION, 0);
_SCSD_getResponse_R1b(responseBuffer);
}
_SCSD_sendClocks(64);
//printf("Completed _SCSD_readSectors_my.\n");
return true;
}
bool _SCSD_writeSectors_my (u32 sector, u32 numSectors, const void* buffer) {
//printf("Starting _SCSD_writeSectors_my with sector %u and numSectors %u.\n", sector, numSectors);
u16 crc[4];
u8 responseBuffer[6];
u32 offset = isSDHC ? sector : sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
while (numSectors--) {
//printf("Writing sector at offset %u.\n", offset);
_SD_CRC16(data, BYTES_PER_READ, (u8*)crc);
_SCSD_sendCommand(WRITE_BLOCK, offset);
if (!_SCSD_getResponse_R1(responseBuffer)) {
//printf("Failed to get response after WRITE_BLOCK command.\n");
return false;
}
if (!_SCSD_writeData_s(data, crc)) {
//printf("Failed to write data and CRC.\n");
return false;
}
_SCSD_sendClocks(64);
offset += isSDHC ? 1 : BYTES_PER_READ;
data += BYTES_PER_READ;
i = WRITE_TIMEOUT;
do {
_SCSD_sendCommand(SEND_STATUS, _SCSD_relativeCardAddress);
if (!_SCSD_getResponse_R1(responseBuffer) || i-- <= 0) {
//printf("Timeout or error during write confirmation.\n");
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
//printf("Sector at offset %u written successfully.\n", offset - BYTES_PER_READ);
}
//printf("Completed _SCSD_writeSectors_my.\n");
return true;
}
bool _SCSD_clearStatus_my (void) {
//printf("Starting _SCSD_clearStatus_my...\n");
bool initResult = _SCSD_initCard();
//printf("Initialization in _SCSD_clearStatus_my returned %d.\n", initResult);
return initResult;
}
bool _SCSD_shutdown_my (void) {
//printf("Starting _SCSD_shutdown_my...\n");
_SC_changeMode(SC_MODE_RAM_RO);
//printf("Changed mode to SC_MODE_RAM_RO in _SCSD_shutdown_my.\n");
return true;
}
const DISC_INTERFACE _my_io_scsd = {
DEVICE_TYPE_SCSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCSD_startUp_my,
(FN_MEDIUM_ISINSERTED)&_SCSD_isInserted_my,
(FN_MEDIUM_READSECTORS)&_SCSD_readSectors_my,
(FN_MEDIUM_WRITESECTORS)&_SCSD_writeSectors_my,
(FN_MEDIUM_CLEARSTATUS)&_SCSD_clearStatus_my,
(FN_MEDIUM_SHUTDOWN)&_SCSD_shutdown_my
} ;

View File

@ -1,48 +0,0 @@
/*
io_scsd.h
Hardware Routines for reading a Secure Digital card
using the Supercard SD
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-22 - Chishm
* First release of stable code
*/
#ifndef IO_SCSD_H
#define IO_SCSD_H
// 'SCSD'
#define DEVICE_TYPE_SCSD 0x44534353
#include <disc_io.h>
// export interface
extern const DISC_INTERFACE _my_io_scsd ;
#endif // define IO_SCSD_H

View File

@ -1,139 +0,0 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ io_scsd_s.s
@
@ Hardware Routines for reading a Secure Digital card
@ using the SC SD
@
@ Based on code supplied by Romman
@
@ Copyright (c) 2006 Michael "Chishm" Chisholm
@
@ Redistribution and use in source and binary forms, with or without modification,
@ are permitted provided that the following conditions are met:
@
@ 1. Redistributions of source code must retain the above copyright notice,
@ this list of conditions and the following disclaimer.
@ 2. Redistributions in binary form must reproduce the above copyright notice,
@ this list of conditions and the following disclaimer in the documentation and/or
@ other materials provided with the distribution.
@ 3. The name of the author may not be used to endorse or promote products derived
@ from this software without specific prior written permission.
@
@ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
@ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
@ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
@ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
@ 2006-07-22 - Chishm
@ * First release of stable code
@
@ 2006-08-19 - Chishm
@ * Added SuperCard Lite support
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.align 4
.arm
.equ REG_SCSD_DATAWRITE, 0x09000000
.equ BYTES_PER_READ, 0x200
.equ SCSD_STS_BUSY, 0x100
.equ BUSY_WAIT_TIMEOUT, 0x10000
.equ FALSE, 0
.equ TRUE, 1
@ bool _SCSD_writeData_s (u8 *data, u16* crc)
.global _SCSD_writeData_s
_SCSD_writeData_s:
stmfd r13!, {r4-r5}
mov r5, #BYTES_PER_READ
mov r2, #REG_SCSD_DATAWRITE
@ Wait for a free data buffer on the SD card
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_busy_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #SCSD_STS_BUSY
beq _SCSD_writeData_busy_wait
ldrh r3, [r2] @ extra clock
mov r3, #0 @ start bit
strh r3,[r2]
@ Check if the data buffer is aligned on a halfword boundary
tst r0, #1
beq _SCSD_writeData_data_loop
@ Used when the source data is unaligned
_SCSD_writeData_data_loop_unaligned:
ldrb r3, [r0], #1
ldrb r4, [r0], #1
orr r3, r3, r4, lsl #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop_unaligned
b _SCSD_writeData_crc
@ Write the data to the card
@ 4 halfwords are transmitted to the Supercard at once, for timing purposes
@ Only the first halfword needs to contain data for standard SuperCards
@ For the SuperCard Lite, the data is split into 4 nibbles, one per halfword
_SCSD_writeData_data_loop:
ldrh r3, [r0], #2
@ This bit added for SCLite. Notice that the shift is not the same as in
@ the original (buggy) code supplied by Romman
add r3, r3, r3, lsl #20
mov r4, r3, lsr #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop
@ Send the data CRC
_SCSD_writeData_crc:
cmp r1, #0
movne r0, r1
movne r1, #0
movne r5, #8
bne _SCSD_writeData_data_loop
mov r3, #0xff @ end bit
strh r3, [r2]
@ Wait for the SD card to signal that it is finished recieving
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_finished_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #0x100
bne _SCSD_writeData_finished_wait
@ Send 8 more clocks, as required by the SD card
ldmia r2, {r3-r4}
@ return true for success
mov r0, #TRUE
_SCSD_writeData_return:
ldmfd r13!,{r4-r5}
bx r14

View File

@ -1,248 +0,0 @@
/*
io_sd_common.c
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "my_io_sd_common.h"
#include <gba_console.h>
#define MAX_STARTUP_TRIES 1000 // Arbitrary value, check if the card is ready 20 times before giving up
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define iprintf(...)
/*
Improved CRC7 function provided by cory1492
Calculates the CRC of an SD command, and includes the end bit in the byte
*/
u8 _SD_CRC7_my(u8* data, int cnt) {
int i, a;
u8 crc, temp;
crc = 0;
for (a = 0; a < cnt; a++)
{
temp = data[a];
for (i = 0; i < 8; i++)
{
crc <<= 1;
if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
temp <<= 1;
}
}
crc = (crc << 1) | 1;
return(crc);
}
/*
Calculates the CRC16 for a sector of data. Calculates it
as 4 separate lots, merged into one buffer. This is used
for 4 SD data lines, not for 1 data line alone.
*/
void _SD_CRC16_my (u8* buff, int buffLength, u8* crc16buff) {
u32 a, b, c, d;
int count;
u32 bitPattern = 0x80808080; // r7
u32 crcConst = 0x1021; // r8
u32 dataByte = 0; // r2
a = 0; // r3
b = 0; // r4
c = 0; // r5
d = 0; // r6
buffLength = buffLength * 8;
do {
if (bitPattern & 0x80) dataByte = *buff++;
a = a << 1;
if ( a & 0x10000) a ^= crcConst;
if (dataByte & (bitPattern >> 24)) a ^= crcConst;
b = b << 1;
if (b & 0x10000) b ^= crcConst;
if (dataByte & (bitPattern >> 25)) b ^= crcConst;
c = c << 1;
if (c & 0x10000) c ^= crcConst;
if (dataByte & (bitPattern >> 26)) c ^= crcConst;
d = d << 1;
if (d & 0x10000) d ^= crcConst;
if (dataByte & (bitPattern >> 27)) d ^= crcConst;
bitPattern = (bitPattern >> 4) | (bitPattern << 28);
} while (buffLength-=4);
count = 16; // r8
do {
bitPattern = bitPattern << 4;
if (a & 0x8000) bitPattern |= 8;
if (b & 0x8000) bitPattern |= 4;
if (c & 0x8000) bitPattern |= 2;
if (d & 0x8000) bitPattern |= 1;
a = a << 1;
b = b << 1;
c = c << 1;
d = d << 1;
count--;
if (!(count & 0x01)) {
*crc16buff++ = (u8)(bitPattern & 0xff);
}
} while (count != 0);
return;
}
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
#define CMD8 8
#define CMD58 58
#define R1_ILLEGAL_COMMAND 0x04
bool _SD_InitCard_SDHC (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA,bool *isSDHC)
{
u8 responseBuffer[17] = {0};
int i;
*isSDHC = false;
bool cmd8Response = cmd_17byte_response(responseBuffer, CMD8, 0x1AA);//0xa 是确定的 0xAA是推荐值
iprintf("\n");
//CMD8 也就是 Send Interface Condition Command
//正确的回显是CMD8Ver=0,Reserved=0,EchoBack=1,EchoBack=0XAA
if (cmd8Response && responseBuffer[0] == CMD8 && responseBuffer[1] == 0 && responseBuffer[2] == 0 && responseBuffer[3] == 0x1 && responseBuffer[4] == 0xAA) {
*isSDHC = true;
iprintf("CMD8 Return OK,might be a SDHC\n");
}else{
iprintf("CMD8 ERR not SDHC\n");
iprintf("resp:");
for(int i=0;i<17;i++){
iprintf("[%d]=%X ",i,responseBuffer[i]);
}
}
for (i = 0; i < MAX_STARTUP_TRIES; i++) {
cmd_6byte_response(responseBuffer, APP_CMD, 0);//CMD55
if (responseBuffer[0] != APP_CMD) {
iprintf("Failed to send APP_CMD\n"); //进入到APP模式可以执行ACMD41
return false;
}
u32 arg = SD_OCR_VALUE;
if (*isSDHC) {
arg |= (1<<30); // Set HCS bit,Supports SDHC
arg |= (1<<28); //Max performance
}
if (cmd_6byte_response(responseBuffer, SD_APP_OP_COND, arg) &&//ACMD41
((responseBuffer[1] & (1<<7)) != 0)/*Busy:0b:initing 1b:init completed*/) {
iprintf("ACMD41 accepted init completed\n");
break; // Card is ready
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
if (isSDHC) {
cmd_6byte_response(responseBuffer, CMD58, 0);
iprintf("CMD58 response received\n");
// u32 ocr = (responseBuffer[1] << 24) | (responseBuffer[2] << 16) |
// (responseBuffer[3] << 8) | responseBuffer[4];
if ((responseBuffer[1] & (1<<6)) == 0) {//Card Capacity Status (CCS)
iprintf("CMD58 OCR ERROR!! Not SDHC\n\n");
*isSDHC = false;
}else{
iprintf("OCR OK! Is SDHC\n");
}
// Further processing of OCR can be done here if needed
}
// The card's name, as assigned by the manufacturer
cmd_17byte_response (responseBuffer, ALL_SEND_CID, 0);
// Get a new address
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
cmd_6byte_response (responseBuffer, SEND_RELATIVE_ADDR, 0);
*RCA = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
if ((responseBuffer[3] & 0x1e) != (SD_STATE_STBY << 1)) {
iprintf("RCA set\n");
break;
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
// Some cards won't go to higher speeds unless they think you checked their capabilities
cmd_17byte_response (responseBuffer, SEND_CSD, *RCA);
// Only this card should respond to all future commands
cmd_6byte_response (responseBuffer, SELECT_CARD, *RCA);
if (use4bitBus) {
// Set a 4 bit data bus
cmd_6byte_response (responseBuffer, APP_CMD, *RCA);
cmd_6byte_response (responseBuffer, SET_BUS_WIDTH, 2); // 4-bit mode.
}
// Use 512 byte blocks
cmd_6byte_response (responseBuffer, SET_BLOCKLEN, 512); // 512 byte blocks
// Wait until card is ready for data
i = 0;
do {
if (i >= RESPONSE_TIMEOUT) {
return false;
}
i++;
} while (!cmd_6byte_response (responseBuffer, SEND_STATUS, *RCA) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
return true;
}

View File

@ -1,116 +0,0 @@
/*
io_sd_common.h
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IO_SD_COMMON_H
#define IO_SD_COMMON_H
#include <disc_io.h>
/* SD commands */
#define GO_IDLE_STATE 0
#define ALL_SEND_CID 2
#define SEND_RELATIVE_ADDR 3
#define SELECT_CARD 7
#define SEND_CSD 9
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define APP_CMD 55
#define CMD8 8
#define CMD58 58
/* SD App commands */
#define SET_BUS_WIDTH 6
#define SD_APP_OP_COND 41
/* OCR (Operating Conditions Register) send value */
#define SD_OCR_VALUE 0x00030000 /* 2.8V to 3.0V */
//#define SD_OCR_VALUE 0x003F8000 /* 2.7V to 3.4V */
//#define SD_OCR_VALUE 0x00FC0000
/* SD Data repsonses */
#define SD_CARD_BUSY 0xff
/* SD states */
#define SD_STATE_IDLE 0 // Idle state, after power on or GO_IDLE_STATE command
#define SD_STATE_READY 1 // Ready state, after card replies non-busy to SD_APP_OP_COND
#define SD_STATE_IDENT 2 // Identification state, after ALL_SEND_CID
#define SD_STATE_STBY 3 // Standby state, when card is deselected
#define SD_STATE_TRAN 4 // Transfer state, after card is selected and ready for data transfer
#define SD_STATE_DATA 5 //
#define SD_STATE_RCV 6 // Receive data state
#define SD_STATE_PRG 7 // Programming state
#define SD_STATE_DIS 8 // Disconnect state
#define SD_STATE_INA 9 // Inactive state, after GO_INACTIVE_STATE
#define READY_FOR_DATA 1 // bit 8 in card status
///Mod:
#define R1_ILLEGAL_COMMAND 0x04
/*
Calculate the CRC7 of a command and return it preshifted with
an end bit added
*/
extern u8 _SD_CRC7(u8* data, int size);
/*
Calculate the CRC16 of a block of data, ready for transmission on
four data lines at once
*/
extern void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff);
typedef bool (*_SD_FN_CMD_6BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
typedef bool (*_SD_FN_CMD_17BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
extern bool _SD_InitCard_SDHC (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA,bool *isSDHC);
#endif // define IO_SD_COMMON_H

View File

@ -1 +0,0 @@
Dummy for now, just http://www.cryptosystem.org/archives/2007/01/simple-gba-mode-switcher/

Binary file not shown.

View File

@ -1,7 +1,6 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
@ -9,65 +8,69 @@ endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# 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
# MAXMOD_SOUNDBANK contains a directory of music and sound effect files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
SOURCES := source
INCLUDES := include build
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
ARCH := -mthumb-interwork
CFLAGS := -g -Wall -O0\
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
CFLAGS := -g -Wall -O2 \
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer \
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
CFLAGS += $(INCLUDE) -DARM7
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map
LIBS := -lnds7
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS := -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 OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export ARM7ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(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)/*.*)))
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)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
@ -82,44 +85,41 @@ else
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) \
$(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
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds
@rm -fr $(BUILD) *.elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).nds : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(ARM7ELF) : $(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
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif

66
arm7/source/main.c Normal file
View File

@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------
default ARM7 core
Copyright (C) 2005 - 2010
Michael Noland (joat)
Jason Rogers (dovoto)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds.h>
volatile bool exitflag = false;
void VblankHandler(void) { }
void VcountHandler() { inputGetAndSend(); }
void powerButtonCB() { exitflag = true; }
int main() {
readUserSettings();
ledBlink(0);
irqInit();
// Start the RTC tracking IRQ
initClockIRQ();
fifoInit();
touchInit();
SetYtrigger(80);
installSystemFIFO();
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable(IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);
// Keep the ARM7 mostly idle
while (!exitflag) {
if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R)))exitflag = true;
swiWaitForVBlank();
}
return 0;
}

View File

@ -1,58 +1,47 @@
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/gba_rules
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output, if this ends with _mb a multiboot image is generated
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files embedded using bin2o
# GRAPHICS is a list of directories containing image files to be converted with grit
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))_mb
BUILD := build
SOURCES := source
DATA :=
INCLUDES :=
BUILD := build
SOURCES := source
INCLUDES := include
DATA := ../data
GRAPHICS := fonts
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -v -mthumb -mthumb-interwork
ARCH := -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s
CFLAGS := -g -Wall -Os -std=c99\
-mcpu=arm7tdmi -mtune=arm7tdmi\
$(ARCH)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := $(ARCH)
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# path to tools - this can be deleted if you set the path to the toolchain in windows
#---------------------------------------------------------------------------------
export PATH := $(DEVKITARM)/bin:$(PATH)
CFLAGS := -g -Wall -Os \
$(ARCH) $(INCLUDE) -DARM9 -D_NO_BOOTSTUB_
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lfat -lgba
LIBS := -lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBGBA)
LIBDIRS := $(LIBNDS) $(PORTLIBS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
@ -61,75 +50,89 @@ LIBDIRS := $(LIBGBA)
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
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)/*.*)))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export OFILES := $(BMPFILES:.bmp=.o) $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(BMPFILES:.bmp=.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(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
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
all : $(BUILD)
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba
@rm -fr $(BUILD) $(TARGET).elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).gba : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
-include $(DEPENDS)
$(ARM9ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# This rule creates assembly source files using grit
# grit takes an image file and a .grit describing how the file is to be processed
# add additional rules like this for each image extension
# you use in the graphics folders
#---------------------------------------------------------------------------------
%.s %.h: %.bmp %.grit
#---------------------------------------------------------------------------------
grit $< -fts -o$*
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------

BIN
arm9/fonts/font.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

25
arm9/fonts/font.grit Normal file
View File

@ -0,0 +1,25 @@
#-------------------------------------------------------
# graphics in tile format
#-------------------------------------------------------
-gt
#-------------------------------------------------------
# output first 16 colors of the palette
#-------------------------------------------------------
-pw16
#-------------------------------------------------------
# no tile reduction
#-------------------------------------------------------
-mR!
#-------------------------------------------------------
# no map output
#-------------------------------------------------------
-m!
#-------------------------------------------------------
# graphics bit depth is 4 (16 color)
#-------------------------------------------------------
-gB4

BIN
arm9/include/scfw.bin Normal file

Binary file not shown.

6
arm9/source/scfw.s Normal file
View File

@ -0,0 +1,6 @@
.arm
.global scfw_bin, scfw_binEnd
scfw_bin: .incbin "../include/scfw.bin"
scfw_binEnd:

416
arm9/source/sckill.cpp Normal file
View File

@ -0,0 +1,416 @@
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#include "font.h"
#include "tonccpy.h"
#define SC_MODE_REG *(vu16*)0x09FFFFFE
#define SC_MODE_MAGIC (u16)0xA55A
#define SC_MODE_FLASH_RW (u16)0x4
#define SC_MODE_FLASH_RW_LITE (u16)0x1510
#define SC_FLASH_MAGIC_ADDR_1 (*(vu16*) 0x08000b92)
#define SC_FLASH_MAGIC_ADDR_2 (*(vu16*) 0x0800046c)
#define SC_FLASH_MAGIC_1 ((u16) 0xaa)
#define SC_FLASH_MAGIC_2 ((u16) 0x55)
#define SC_FLASH_ERASE ((u16) 0x80)
#define SC_FLASH_ERASE_BLOCK ((u16) 0x30)
#define SC_FLASH_ERASE_CHIP ((u16) 0x10)
#define SC_FLASH_PROGRAM ((u16) 0xA0)
#define SC_FLASH_IDLE ((u16) 0xF0)
#define SC_FLASH_IDENTIFY ((u16) 0x90)
#define FlashBase 0x08000000
extern u8 scfw_bin[];
extern u8 scfw_binEnd[];
static u8* scfw_buffer;
static PrintConsole tpConsole;
static PrintConsole btConsole;
static int bg;
static int bgSub;
const char* textBuffer = "X------------------------------X\nX------------------------------X";
volatile u32 cachedFlashID;
volatile u32 statData = 0x00000000;
volatile bool UpdateProgressText = false;
volatile bool PrintWithStat = true;
volatile bool ClearOnUpdate = true;
volatile bool SCLiteMode = false;
void vblankHandler (void) {
if (UpdateProgressText) {
if (!ClearOnUpdate) { ClearOnUpdate = true; } else { consoleClear(); }
printf(textBuffer);
if (!PrintWithStat) { PrintWithStat = true; } else { iprintf("%lx \n", statData); }
UpdateProgressText = false;
}
}
void Block_Erase(u32 blockAdd) {
vu16 v1,v2;
u32 Address;
u32 loop;
u32 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);
}
}
// Modified version of WriteNorFlash from EZFlash 3in1 card lib
void WriteNorFlash_SCLite(u32 address, u8 *buffer, u32 size) {
vu16 v1,v2;
u32 loopwrite;
vu16* buf = (vu16*)buffer;
u32 mapaddress;
v1 = 0;
v2 = 1;
u32 off = 0; // Original offset code for alternate 3in1 revisions removed. They are not used for SC Lite.
mapaddress = address;
for(loopwrite = 0; loopwrite < (size >> 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);
if (!UpdateProgressText) {
textBuffer = "\n\n\n\n\n\n\n\n\n\n\n Programmed ";
statData = (0x08000000 + loopwrite);
UpdateProgressText = true;
}
}
}
u32 sc_flash_id() {
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_IDENTIFY;
// should equal 0x000422b9
u32 res = SC_FLASH_MAGIC_ADDR_1;
res |= *GBA_BUS << 16;
*GBA_BUS = SC_FLASH_IDLE;
return res;
}
void sc_flash_rw_enable() {
bool buf = REG_IME;
REG_IME = 0;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_FLASH_RW;
SC_MODE_REG = SC_MODE_FLASH_RW;
REG_IME = buf;
}
void sc_flash_rw_enable_lite() {
bool buf = REG_IME;
REG_IME = 0;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_FLASH_RW_LITE;
SC_MODE_REG = SC_MODE_FLASH_RW_LITE;
REG_IME = buf;
}
void sc_flash_erase_chip() {
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE_CHIP;
while (*GBA_BUS != *GBA_BUS)swiWaitForVBlank();
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
void sc_flash_erase_block(vu16 *addr) {
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
*addr = SC_FLASH_ERASE_BLOCK;
while (*GBA_BUS != *GBA_BUS)swiWaitForVBlank();
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
void sc_flash_program(vu16 *addr, u16 val) {
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_PROGRAM;
*addr = val;
while (*GBA_BUS != *GBA_BUS)swiWaitForVBlank();
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
void CustomConsoleInit() {
videoSetMode(MODE_0_2D);
videoSetModeSub(MODE_0_2D);
vramSetBankA (VRAM_A_MAIN_BG);
vramSetBankC (VRAM_C_SUB_BG);
bg = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0);
bgSub = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0);
consoleInit(&btConsole, 3, BgType_Text4bpp, BgSize_T_256x256, 20, 0, false, false);
consoleInit(&tpConsole, 3, BgType_Text4bpp, BgSize_T_256x256, 20, 0, true, false);
ConsoleFont font;
font.gfx = (u16*)fontTiles;
font.pal = (u16*)fontPal;
font.numChars = 95;
font.numColors = fontPalLen / 2;
font.bpp = 4;
font.asciiOffset = 32;
font.convertSingleColor = true;
consoleSetFont(&btConsole, &font);
consoleSetFont(&tpConsole, &font);
consoleSelect(&tpConsole);
}
bool Prompt() {
while(1) {
swiWaitForVBlank();
scanKeys();
if ((keysDown() & KEY_UP) || (keysDown() & KEY_DOWN) || (keysDown() & KEY_LEFT) || (keysDown() & KEY_RIGHT)) {
if (SCLiteMode) { SCLiteMode = false; } else { SCLiteMode = true; }
consoleSelect(&tpConsole);
if (SCLiteMode) {
textBuffer = "\n\n [SCLITE MODE]\n\n\n\n\n\n\n\n\n Flash ID ";
} else {
textBuffer = "\n\n\n\n\n\n\n\n\n\n\n Flash ID ";
}
statData = cachedFlashID;
UpdateProgressText = true;
while(UpdateProgressText)swiWaitForVBlank();
statData = 0;
consoleSelect(&btConsole);
} else {
switch (keysDown()) {
case KEY_A: return true;
case KEY_B: return false;
}
}
}
}
bool DoFlash() {
sc_flash_rw_enable();
printf("\n Death 2 supercard :3\n");
printf(" Erasing whole chip\n");
sc_flash_erase_chip();
printf(" Erased whole chip\n");
for (int i = 0; i < 60; i++)swiWaitForVBlank();
for (u32 off = 0; off < (u32)(scfw_binEnd - scfw_bin); off += 2) {
u16 val = 0;
val |= scfw_bin[off];
val |= (scfw_bin[off+1] << 8);
sc_flash_program((vu16*)(0x08000000 + off), val);
if (!UpdateProgressText && !(off & 0x00ff)) {
textBuffer = "\n\n\n\n\n\n\n\n\n\n\n Programmed ";
statData = (0x08000000 + off);
UpdateProgressText = true;
}
}
while(UpdateProgressText)swiWaitForVBlank();
printf("\n\n\n\n\n Ded!\n");
return false;
}
bool DoFlash_Lite() {
sc_flash_rw_enable_lite();
for(u32 offset = 0; offset < 0x80000; offset += 0x40000) {
if (!UpdateProgressText) {
textBuffer = "\n Death 2 supercard lite :3\n\n\n Erasing whole chip\n\n\n Erased ";
statData = (0x08000000 + offset);
UpdateProgressText = true;
}
Block_Erase(offset);
}
printf("\n\n\n Erased whole chip\n");
for (int i = 0; i < 60; i++)swiWaitForVBlank();
WriteNorFlash_SCLite(0, scfw_buffer, 0x80000);
while(UpdateProgressText)swiWaitForVBlank();
for (int i = 0; i < 60; i++)swiWaitForVBlank();
printf("\n\n\n\n\n Ded!\n");
return true;
}
int main(void) {
CustomConsoleInit();
irqSet(IRQ_VBLANK, vblankHandler);
sysSetCartOwner(true);
cachedFlashID = sc_flash_id();
textBuffer = "\n\n\n\n\n\n\n\n\n\n\n Flash ID ";
statData = cachedFlashID;
UpdateProgressText = true;
while(UpdateProgressText)swiWaitForVBlank();
statData = 0;
consoleSelect(&btConsole);
scfw_buffer = (u8*)malloc(0x80000);
toncset(scfw_buffer, 0xFF, 0x80000);
tonccpy(scfw_buffer, scfw_bin, (scfw_binEnd - scfw_bin));
printf("\n Press [A] to kill supercard.\n");
printf(" Press [B] to spare supercard.\n");
if (!Prompt())return 0;
consoleClear();
if (SCLiteMode) { DoFlash_Lite(); } else { DoFlash(); }
while(1) {
swiWaitForVBlank();
scanKeys();
switch (keysDown()) {
default: swiWaitForVBlank(); break;
case KEY_A: return 0;
case KEY_B: return 0;
case KEY_START: return 0;
}
}
return 0;
}

136
arm9/source/tonccpy.c Normal file
View File

@ -0,0 +1,136 @@
#include "tonccpy.h"
//# tonccpy.c
//! VRAM-safe cpy.
/*! This version mimics memcpy in functionality, with
the benefit of working for VRAM as well. It is also
slightly faster than the original memcpy, but faster
implementations can be made.
\param dst Destination pointer.
\param src Source pointer.
\param size Fill-length in bytes.
\note The pointers and size need not be word-aligned.
*/
void tonccpy(void *dst, const void *src, uint size)
{
if(size==0 || dst==0 || src==0)
return;
uint count;
u16 *dst16; // hword destination
u8 *src8; // byte source
// Ideal case: copy by 4x words. Leaves tail for later.
if( ((u32)src|(u32)dst)%4==0 && size>=4)
{
u32 *src32= (u32*)src, *dst32= (u32*)dst;
count= size/4;
uint tmp= count&3;
count /= 4;
// Duff's Device, good friend!
switch(tmp) {
do { *dst32++ = *src32++;
case 3: *dst32++ = *src32++;
case 2: *dst32++ = *src32++;
case 1: *dst32++ = *src32++;
case 0: ; } while(count--);
}
// Check for tail
size &= 3;
if(size == 0)
return;
src8= (u8*)src32;
dst16= (u16*)dst32;
}
else // Unaligned.
{
uint dstOfs= (u32)dst&1;
src8= (u8*)src;
dst16= (u16*)(dst-dstOfs);
// Head: 1 byte.
if(dstOfs != 0)
{
*dst16= (*dst16 & 0xFF) | *src8++<<8;
dst16++;
if(--size==0)
return;
}
}
// Unaligned main: copy by 2x byte.
count= size/2;
while(count--)
{
*dst16++ = src8[0] | src8[1]<<8;
src8 += 2;
}
// Tail: 1 byte.
if(size&1)
*dst16= (*dst16 &~ 0xFF) | *src8;
}
//# toncset.c
//! VRAM-safe memset, internal routine.
/*! This version mimics memset in functionality, with
the benefit of working for VRAM as well. It is also
slightly faster than the original memset.
\param dst Destination pointer.
\param fill Word to fill with.
\param size Fill-length in bytes.
\note The \a dst pointer and \a size need not be
word-aligned. In the case of unaligned fills, \a fill
will be masked off to match the situation.
*/
void __toncset(void *dst, u32 fill, uint size)
{
if(size==0 || dst==0)
return;
uint left= (u32)dst&3;
u32 *dst32= (u32*)(dst-left);
u32 count, mask;
// Unaligned head.
if(left != 0)
{
// Adjust for very small stint.
if(left+size<4)
{
mask= BIT_MASK(size*8)<<(left*8);
*dst32= (*dst32 &~ mask) | (fill & mask);
return;
}
mask= BIT_MASK(left*8);
*dst32= (*dst32 & mask) | (fill&~mask);
dst32++;
size -= 4-left;
}
// Main stint.
count= size/4;
uint tmp= count&3;
count /= 4;
switch(tmp) {
do { *dst32++ = fill;
case 3: *dst32++ = fill;
case 2: *dst32++ = fill;
case 1: *dst32++ = fill;
case 0: ; } while(count--);
}
// Tail
size &= 3;
if(size)
{
mask= BIT_MASK(size*8);
*dst32= (*dst32 &~ mask) | (fill & mask);
}
}

43
arm9/source/tonccpy.h Normal file
View File

@ -0,0 +1,43 @@
//# Stuff you may not have yet.
#ifndef TONCCPY_H
#define TONCCPY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <nds/ndstypes.h>
typedef unsigned int uint;
#define BIT_MASK(len) ( (1<<(len))-1 )
static inline u32 quad8(u16 x) { x |= x<<8; return x | x<<16; }
//# Declarations and inlines.
void tonccpy(void *dst, const void *src, uint size);
void __toncset(void *dst, u32 fill, uint size);
static inline void toncset(void *dst, u8 src, uint size);
static inline void toncset16(void *dst, u16 src, uint size);
static inline void toncset32(void *dst, u32 src, uint size);
//! VRAM-safe memset, byte version. Size in bytes.
static inline void toncset(void *dst, u8 src, uint size)
{ __toncset(dst, quad8(src), size); }
//! VRAM-safe memset, halfword version. Size in hwords.
static inline void toncset16(void *dst, u16 src, uint size)
{ __toncset(dst, src|src<<16, size*2); }
//! VRAM-safe memset, word version. Size in words.
static inline void toncset32(void *dst, u32 src, uint size)
{ __toncset(dst, src, size*4); }
#ifdef __cplusplus
}
#endif
#endif

BIN
banner.bin Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,85 +0,0 @@
@ GBA ROM entrypoint at 0x08000000 is patched to patched_entrypoint.
@ patched_entrypoint installs irq_stub at 0x03ffffe0
@ and points the bios irq handler to it at 0x03fffffc
@ before jumping to the original entrypoint.
@ If this handler is already installed, it instead loads
@ code to iwram to reset the Supercard's state and then
@ boots the firmware there
.arm
patched_entrypoint:
mov r0, #0x04000000
ldr r1, [r0, # -4]
sub r0, # 0x20
cmp r0, r1
beq do_reset
install_hook:
adr r1, hook
ldm r1, {r4-r7}
stm r0, {r4-r7}
str r0, [r0, # 0x1c]
ldr pc, original_entrypoint
@ extremely optimised ARM code fits in 16 free bytes at 0x03ffffe0
@ branch to original user IRQ handler if face buttons held and dpad not
@ else branch to entrypoint for reset
hook:
ldrb r1, [r0, # 0x130]
cmp r1, # 0x00f0
ldrne pc, [pc, # 4]
mov pc, # 0x08000000
do_reset:
mov r0, # 0x9f
msr cpsr, r0
@ disable sound, dma, and interrupts
mov r0, # 0x04000000
strh r0, [r0, # 0x84]
strh r0, [r0, # 0xba]
strh r0, [r0, # 0xc6]
strh r0, [r0, # 0xd2]
strh r0, [r0, # 0xde]
strb r0, [r0, # 0x208]
@ copy to stack and execute
adr r1, do_reset_iwram
adr r2, do_reset_iwram_end
do_reset_loop:
ldr r3, [r2, #-4]!
str r3, [sp, #-4]!
cmp r1, r2
blt do_reset_loop
mov pc, sp
do_reset_iwram:
mov r0, # 0x0a000000
mov r1, # 0x005a
add r1, # 0xa500
orr r1, r1, LSL # 16
mov r2, # 5
mov r3, # 4
@ Write soft reset token 0xa55aa55a to 0x09ffff80
strh r1, [r0, # -2]
strh r1, [r0, # -2]
strh r2, [r0, # -2]
strh r2, [r0, # -2]
nop
nop
str r1, [r0, # -0x80]
@ Enable firmware and reset
strh r1, [r0, # -2]
strh r1, [r0, # -2]
strh r3, [r0, # -2]
strh r3, [r0, # -2]
@ In ARM mode, SWI indexes must be shifted left 16 bits.
swi 0x260000
do_reset_iwram_end:
original_entrypoint:
@ patcher inserts ARM code address here

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
extern unsigned char scfw_bin[];
extern unsigned int scfw_bin_len;

View File

@ -1,137 +0,0 @@
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#include "scfw.bin.h"
#define SC_MODE_REG (*(vu16*) 0x09fffffe)
#define SC_MODE_MAGIC ((u16) 0xa55a)
#define SC_MODE_FLASH_RW ((u16) 4)
#define SC_FLASH_MAGIC_ADDR_1 (*(vu16*) 0x08000b92)
#define SC_FLASH_MAGIC_ADDR_2 (*(vu16*) 0x0800046c)
#define SC_FLASH_MAGIC_1 ((u16) 0xaa)
#define SC_FLASH_MAGIC_2 ((u16) 0x55)
#define SC_FLASH_ERASE ((u16) 0x80)
#define SC_FLASH_ERASE_BLOCK ((u16) 0x30)
#define SC_FLASH_ERASE_CHIP ((u16) 0x10)
#define SC_FLASH_PROGRAM ((u16) 0xA0)
#define SC_FLASH_IDLE ((u16) 0xF0)
#define SC_FLASH_IDENTIFY ((u16) 0x90)
u32 sc_flash_id()
{
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_IDENTIFY;
// should equal 0x000422b9
u32 res = SC_FLASH_MAGIC_ADDR_1;
res |= *GBA_BUS << 16;
*GBA_BUS = SC_FLASH_IDLE;
return res;
}
void sc_flash_rw_enable()
{
bool buf = REG_IME;
REG_IME = 0;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_MAGIC;
SC_MODE_REG = SC_MODE_FLASH_RW;
SC_MODE_REG = SC_MODE_FLASH_RW;
REG_IME = buf;
}
void sc_flash_erase_chip()
{
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE_CHIP;
while (*GBA_BUS != *GBA_BUS) {
}
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
void sc_flash_erase_block(vu16 *addr)
{
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_ERASE;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
*addr = SC_FLASH_ERASE_BLOCK;
while (*GBA_BUS != *GBA_BUS) {
}
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
void sc_flash_program(vu16 *addr, u16 val)
{
bool buf = REG_IME;
REG_IME = 0;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_MAGIC_1;
SC_FLASH_MAGIC_ADDR_2 = SC_FLASH_MAGIC_2;
SC_FLASH_MAGIC_ADDR_1 = SC_FLASH_PROGRAM;
*addr = val;
while (*GBA_BUS != *GBA_BUS) {
}
*GBA_BUS = SC_FLASH_IDLE;
REG_IME = buf;
}
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
consoleDemoInit();
sysSetCartOwner(true);
iprintf(" Death 2 supercard :3\n");
sc_flash_rw_enable();
iprintf(" Flash ID %lx\n", sc_flash_id());
iprintf(" Erasing whole chip\n");
sc_flash_erase_chip();
iprintf(" Erased whole chip\n");
for (u32 off = 0; off < scfw_bin_len; off += 2)
{
u16 val = 0;
val |= scfw_bin[off];
val |= scfw_bin[off+1] << 8;
sc_flash_program((vu16*) (0x08000000 + off), val);
if (!(off & 0x00ff))
iprintf(" Programmed %lx\n", 0x08000000 + off);
}
iprintf(" Ded!\n");
while(1) {
}
return 0;
}