mirror of
https://github.com/ApacheThunder/SCKILL.git
synced 2025-06-18 11:05:50 -04:00
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:
parent
93fb8d7574
commit
87c9d70a04
57
Makefile
Normal file
57
Makefile
Normal 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
|
28
README.md
28
README.md
@ -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/
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void patchGeneralWhiteScreen();
|
||||
|
||||
void patchSpecificGame();
|
@ -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
|
@ -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;
|
||||
}*/
|
@ -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
|
@ -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();
|
||||
}
|
@ -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 ;
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
} ;
|
||||
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
//正确的回显是:CMD8,Ver=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;
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
Instructions:
|
||||
|
||||
Assemble scfw.s
|
||||
Convert ELF to flat binary with objcopy
|
||||
Fix GBA logo with gbafix
|
@ -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:
|
||||
|
@ -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
|
||||
#---------------------------------------------------------------------------------
|
@ -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();
|
||||
}
|
@ -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 ;
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
} ;
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
//正确的回显是:CMD8,Ver=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;
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -1 +0,0 @@
|
||||
Dummy for now, just http://www.cryptosystem.org/archives/2007/01/simple-gba-mode-switcher/
|
Binary file not shown.
@ -1,7 +1,6 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
@ -9,39 +8,35 @@ 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
|
||||
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)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project (order is important)
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lnds9
|
||||
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map
|
||||
|
||||
LIBS := -lnds7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
@ -49,6 +44,7 @@ LIBS := -lnds9
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
@ -56,18 +52,25 @@ LIBDIRS := $(LIBNDS)
|
||||
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)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPSDIR)/*.d
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
66
arm7/source/main.c
Normal file
66
arm7/source/main.c
Normal 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;
|
||||
}
|
||||
|
@ -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 :=
|
||||
INCLUDES := include
|
||||
DATA := ../data
|
||||
GRAPHICS := fonts
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -v -mthumb -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -Os -std=c99\
|
||||
-mcpu=arm7tdmi -mtune=arm7tdmi\
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
ARCH := -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s
|
||||
|
||||
CFLAGS := -g -Wall -Os \
|
||||
$(ARCH) $(INCLUDE) -DARM9 -D_NO_BOOTSTUB_
|
||||
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)
|
||||
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,18 +50,18 @@ LIBDIRS := $(LIBGBA)
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export ARM9ELF := $(CURDIR)/$(TARGET).elf
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(GRAPHICS),$(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)))
|
||||
BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@ -89,18 +78,17 @@ else
|
||||
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) \
|
||||
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
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)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# build a list of library paths
|
||||
#---------------------------------------------------------------------------------
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean
|
||||
@ -108,28 +96,43 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
#---------------------------------------------------------------------------------
|
||||
$(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
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
25
arm9/fonts/font.grit
Normal 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
BIN
arm9/include/scfw.bin
Normal file
Binary file not shown.
6
arm9/source/scfw.s
Normal file
6
arm9/source/scfw.s
Normal 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
416
arm9/source/sckill.cpp
Normal 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
136
arm9/source/tonccpy.c
Normal 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
43
arm9/source/tonccpy.h
Normal 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
BIN
banner.bin
Normal file
Binary file not shown.
BIN
devkitPro.7z
BIN
devkitPro.7z
Binary file not shown.
@ -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
@ -1,2 +0,0 @@
|
||||
extern unsigned char scfw_bin[];
|
||||
extern unsigned int scfw_bin_len;
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user