mirror of
https://github.com/ApacheThunder/ezfo-disc_io.git
synced 2025-06-18 19:15:33 -04:00
Initial port to libnds compatible DLDI
* DMA code limited to GBA compile flag as it will not operate safely in DS mode due to arm9 cache system. * tonccpy used in place of dmaCopy for NDS mode. * Altered detection routine in startup function. Should be more reliable (for DS mode at least. Maybe it worked better for GBA homebrew but I found this to be unreliable for DS mode stuff) * setRomPage value for Kernel mode alrted to be 0x8002 as rerferenced in the EZFlash Kernel source code. 0x8000....not sure what the difference is with that one. Maybe 0x8000 is actually bootloader mode? * Disabling of SD and setting back to PSRam mode will no only occur if DLDI is compiled for GBA as the constant mode switching is not nessecery.
This commit is contained in:
parent
6fff3d7ac3
commit
21bf488362
133
Makefile
Normal file
133
Makefile
Normal file
@ -0,0 +1,133 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
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
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
# SPECS is the directory containing the important build and link files
|
||||
#---------------------------------------------------------------------------------
|
||||
export TARGET := $(shell basename $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -O2\
|
||||
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||
-ffast-math -ffreestanding \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM7 -fPIC
|
||||
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -nostartfiles -nostdlib -T dldi.ld -g $(ARCH) -Wl,-Map,$(TARGET).map,--gc-sections -ffunction-sections -fdata-sections
|
||||
|
||||
LIBS :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).dldi $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).dldi : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.dldi: %.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
|
||||
fileio.c
|
||||
|
||||
Example libfat & ezfo-disc_io Gameboy Advance file handling
|
||||
|
||||
*/
|
||||
|
||||
#include <gba.h>
|
||||
#include <fat.h>
|
||||
|
||||
#include <stdio.h> // iprintf, fopen, fwrite, fclose
|
||||
#include <unistd.h> // chdir
|
||||
|
||||
// EZ Flash Omega disc interface
|
||||
#include "io_ezfo.h"
|
||||
|
||||
// EZ Flash Omega mounts an SD card
|
||||
#define EZFO_DEVNAME "sd"
|
||||
|
||||
#define DEMO_FILENAME "fileio_demo.txt"
|
||||
|
||||
#define EVER
|
||||
|
||||
/**
|
||||
* Locks device into loop
|
||||
*/
|
||||
static void waitForever() {
|
||||
for ( EVER ) {
|
||||
VBlankIntrWait();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts EZ Flash Omega SD
|
||||
* or uses whatever fatsystem libgba might be available
|
||||
*/
|
||||
static bool initFatSystem() {
|
||||
const char * devname;
|
||||
|
||||
// Attempt to mount EZFO and change working directory into device
|
||||
if ( fatMountSimple( EZFO_DEVNAME, &_io_ezfo ) && chdir( EZFO_DEVNAME ":/" ) == 0 ) {
|
||||
devname = EZFO_DEVNAME;
|
||||
} else if ( fatInitDefault() ) {
|
||||
devname = "fat";
|
||||
} else {
|
||||
devname = NULL;
|
||||
}
|
||||
|
||||
if ( !devname ) {
|
||||
iprintf( "[FAIL] Failed to mount or init a FAT device.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
iprintf( "[ OK ] Mounted dev %s.\n", devname );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry
|
||||
*/
|
||||
int main() {
|
||||
FILE * file;
|
||||
u32 value; // Number in the example file
|
||||
|
||||
irqInit();
|
||||
irqEnable( IRQ_VBLANK ); // Enable IRQ_VBLANK for VBlankIntrWait
|
||||
|
||||
// libgba console
|
||||
consoleDemoInit();
|
||||
|
||||
iprintf( "Welcome to GBA file IO demo!\n\n" );
|
||||
|
||||
if ( !initFatSystem() ) {
|
||||
waitForever();
|
||||
}
|
||||
|
||||
file = fopen( DEMO_FILENAME, "r" );
|
||||
if ( file ) {
|
||||
fscanf( file, "%ld", &value );
|
||||
fclose( file );
|
||||
|
||||
iprintf( "[ OK ] Opened " DEMO_FILENAME " (%ld).\n", value );
|
||||
|
||||
value++; // Increment reads
|
||||
} else {
|
||||
iprintf( "[FAIL] " DEMO_FILENAME " does not exist.\n" );
|
||||
|
||||
value = 1; // First read
|
||||
}
|
||||
|
||||
file = fopen( DEMO_FILENAME, "w" );
|
||||
if ( !file ) {
|
||||
iprintf( "[FAIL] " DEMO_FILENAME " could not be created.\n" );
|
||||
waitForever();
|
||||
}
|
||||
|
||||
if ( fprintf( file, "%ld", value ) ) {
|
||||
iprintf( "[ OK ] Wrote %ld.\n", value );
|
||||
} else {
|
||||
iprintf( "[FAIL] Write failure.\n" );
|
||||
}
|
||||
fclose( file );
|
||||
|
||||
iprintf( "[ OK ] File saved.\n" );
|
||||
waitForever();
|
||||
}
|
53
source/dldi_header.s
Normal file
53
source/dldi_header.s
Normal file
@ -0,0 +1,53 @@
|
||||
#include <nds/arm9/dldi_asm.h>
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
.section ".crt0","ax"
|
||||
@---------------------------------------------------------------------------------
|
||||
.global _start
|
||||
.align 4
|
||||
.arm
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Driver patch file standard header -- 16 bytes
|
||||
.word 0xBF8DA5ED @ Magic number to identify this region
|
||||
.asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator)
|
||||
.byte 0x01 @ Version number
|
||||
.byte DLDI_SIZE_4KB
|
||||
.byte FIX_GOT | FIX_BSS | FIX_GLUE @ Sections to fix
|
||||
.byte 0x00 @ Space allocated in the application, not important here.
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Text identifier - can be anything up to 47 chars + terminating null -- 48 bytes
|
||||
.align 4
|
||||
.asciz "EZ Flash Omega (slot-2)"
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Offsets to important sections within the data -- 32 bytes
|
||||
.align 6
|
||||
.word __text_start @ data start
|
||||
.word __data_end @ data end
|
||||
.word __glue_start @ Interworking glue start -- Needs address fixing
|
||||
.word __glue_end @ Interworking glue end
|
||||
.word __got_start @ GOT start -- Needs address fixing
|
||||
.word __got_end @ GOT end
|
||||
.word __bss_start @ bss start -- Needs setting to zero
|
||||
.word __bss_end @ bss end
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ IO_INTERFACE data -- 32 bytes
|
||||
.ascii "EZFO" @ ioType
|
||||
.word FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA
|
||||
.word _EZFO_startUp @
|
||||
.word _EZFO_isInserted @
|
||||
.word _EZFO_readSectors @ Function pointers to standard device driver functions
|
||||
.word _EZFO_writeSectors @
|
||||
.word _EZFO_clearStatus @
|
||||
.word _EZFO_shutdown @
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
.align
|
||||
.pool
|
||||
.end
|
||||
@---------------------------------------------------------------------------------
|
211
source/io_ezfo.c
Normal file
211
source/io_ezfo.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
|
||||
io_ezfo.c
|
||||
|
||||
Hardware Routines for reading the EZ Flash Omega filesystem
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NDS
|
||||
#if defined ARM9 || defined ARM7
|
||||
#define NDS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NDS
|
||||
#include <nds/ndstypes.h>
|
||||
#include <nds/system.h>
|
||||
#include <nds/dma.h>
|
||||
#include "tonccpy.h"
|
||||
#else
|
||||
#include "gba_dma.h"
|
||||
#include "gba_types.h"
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define BYTES_PER_READ 512
|
||||
|
||||
|
||||
#define SET_info_offset 0x7B0000
|
||||
#define FlashBase_S71 0x08000000
|
||||
#define FlashBase_S98 0x09000000
|
||||
|
||||
#define OMEGA_ROM_UNKNOWN 0x0000
|
||||
#define OMEGA_ROM_PSRAM 0x9780
|
||||
#define OMEGA_ROM_NOR 0xFFFF
|
||||
|
||||
#define OMEGA_ROM_PAGE_UNKNOWN 0xFFFF
|
||||
#define OMEGA_ROM_PAGE_PSRAM 0x0200
|
||||
// #define OMEGA_ROM_PAGE_KERNEL 0x8000
|
||||
#define OMEGA_ROM_PAGE_KERNEL 0x8002 // 0x8000 is not what EZ Flash kernel actually sets.... This is the real value from source code. Was 0x8000 a typo?
|
||||
|
||||
#define OMEGA_SD_BIT_ENABLE (0x1 << 0)
|
||||
#define OMEGA_SD_BIT_READ_STATE (0x1 << 1)
|
||||
|
||||
#define OMEGA_SD_CTL_ENABLE OMEGA_SD_BIT_ENABLE
|
||||
#define OMEGA_SD_CTL_READ_STATE (OMEGA_SD_BIT_ENABLE | OMEGA_SD_BIT_READ_STATE)
|
||||
#define OMEGA_SD_CTL_DISABLE 0x0
|
||||
|
||||
/**
|
||||
*
|
||||
* Miscellaneous utility functions
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void _Spin( u32 _cycles ) {
|
||||
while (_cycles--)asm ("nop");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Omega device functions
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void _Omega_SetROMPage( const u16 _page ) {
|
||||
*(vu16*)0x9fe0000 = 0xd200;
|
||||
*(vu16*)0x8000000 = 0x1500;
|
||||
*(vu16*)0x8020000 = 0xd200;
|
||||
*(vu16*)0x8040000 = 0x1500;
|
||||
*(vu16*)0x9880000 = _page;
|
||||
*(vu16*)0x9fc0000 = 0x1500;
|
||||
}
|
||||
|
||||
static inline void _Omega_SetSDControl( const u16 _control ) {
|
||||
*(vu16*)0x9fe0000 = 0xd200;
|
||||
*(vu16*)0x8000000 = 0x1500;
|
||||
*(vu16*)0x8020000 = 0xd200;
|
||||
*(vu16*)0x8040000 = 0x1500;
|
||||
*(vu16*)0x9400000 = _control;
|
||||
*(vu16*)0x9fc0000 = 0x1500;
|
||||
}
|
||||
|
||||
static inline u16 Read_S98NOR_ID() {
|
||||
*((vu16*)(FlashBase_S98)) = 0xF0;
|
||||
*((vu16*)(FlashBase_S98+0x555*2)) = 0xAA;
|
||||
*((vu16*)(FlashBase_S98+0x2AA*2)) = 0x55;
|
||||
*((vu16*)(FlashBase_S98+0x555*2)) = 0x90;
|
||||
return *((vu16*)(FlashBase_S98+0xE*2));
|
||||
}
|
||||
|
||||
static inline u32 _Omega_WaitSDResponse() {
|
||||
vu16 response;
|
||||
u32 waitSpin = 0;
|
||||
while ( waitSpin < 0x100000 ) {
|
||||
response = *(vu16* )0x9E00000;
|
||||
if ( response != 0xEEE1 )return 0;
|
||||
waitSpin += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Disc interface functions
|
||||
*
|
||||
*/
|
||||
|
||||
bool _EZFO_startUp() {
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_KERNEL);
|
||||
_Spin(5000);
|
||||
if (Read_S98NOR_ID() == 0x223D) {
|
||||
#ifdef NDS
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_ENABLE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _EZFO_isInserted() { return true; }
|
||||
|
||||
bool _EZFO_readSectors(u32 _address, u32 _count, void* _buffer) {
|
||||
#ifndef NDS
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_KERNEL); // Change to OS mode
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_ENABLE);
|
||||
#endif
|
||||
|
||||
u32 readsRemain = 2;
|
||||
for (u16 ii = 0; ii < _count; ii += 4) {
|
||||
const u16 blocks = (_count - ii > 4) ? 4 : (_count - ii);
|
||||
|
||||
while (readsRemain) {
|
||||
*(vu16*)0x9fe0000 = 0xd200;
|
||||
*(vu16*)0x8000000 = 0x1500;
|
||||
*(vu16*)0x8020000 = 0xd200;
|
||||
*(vu16*)0x8040000 = 0x1500;
|
||||
*(vu16*)0x9600000 = ((_address + ii) & 0x0000FFFF);
|
||||
*(vu16*)0x9620000 = ((_address + ii) & 0xFFFF0000) >> 16;
|
||||
*(vu16*)0x9640000 = blocks;
|
||||
*(vu16*)0x9fc0000 = 0x1500;
|
||||
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_READ_STATE);
|
||||
const u32 response = _Omega_WaitSDResponse();
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_ENABLE);
|
||||
if (response && --readsRemain) {
|
||||
_Spin(5000);
|
||||
} else {
|
||||
#ifndef NDS
|
||||
dmaCopy((void*)0x9E00000, (void*)(_buffer + ii * 512), (blocks * BYTES_PER_READ));
|
||||
#else
|
||||
tonccpy((void*)(_buffer + ii * 512), (void*)0x9E00000, (blocks * BYTES_PER_READ));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef NDS
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_DISABLE);
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_PSRAM); // Return to original mode
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _EZFO_writeSectors(u32 _address, u32 _count, void* _buffer ) {
|
||||
#ifndef NDS
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_KERNEL); // Change to OS mode
|
||||
#endif
|
||||
|
||||
#ifdef _IO_USE_DMA
|
||||
DC_FlushRange(_buffer, (_count * BYTES_PER_READ));
|
||||
#endif
|
||||
|
||||
// _Omega_SetSDControl(OMEGA_SD_CTL_READ_STATE);
|
||||
for (u16 ii = 0; ii < _count; ii++) {
|
||||
const u16 blocks = (_count - ii > 4) ? 4 : (_count - ii);
|
||||
#ifndef NDS
|
||||
dmaCopy((_buffer + ii * 512), (void*)0x9E00000, (blocks * BYTES_PER_READ));
|
||||
#else
|
||||
tonccpy((void*)0x9E00000, (_buffer + ii * 512), (blocks * BYTES_PER_READ));
|
||||
#endif
|
||||
*(vu16*)0x9fe0000 = 0xd200;
|
||||
*(vu16*)0x8000000 = 0x1500;
|
||||
*(vu16*)0x8020000 = 0xd200;
|
||||
*(vu16*)0x8040000 = 0x1500;
|
||||
*(vu16*)0x9600000 = ((_address + ii) & 0x0000FFFF);
|
||||
*(vu16*)0x9620000 = ((_address + ii) & 0xFFFF0000) >> 16;
|
||||
*(vu16*)0x9640000 = (0x8000 + blocks);
|
||||
*(vu16*)0x9fc0000 = 0x1500;
|
||||
|
||||
_Omega_WaitSDResponse();
|
||||
}
|
||||
_Spin(3000);
|
||||
#ifndef NDS
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_DISABLE);
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_PSRAM); // Return to original mode
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _EZFO_clearStatus() { return true; }
|
||||
|
||||
bool _EZFO_shutdown() {
|
||||
_Omega_SetSDControl(OMEGA_SD_CTL_DISABLE);
|
||||
_Omega_SetROMPage(OMEGA_ROM_PAGE_PSRAM); // Return to original mode
|
||||
return true;
|
||||
}
|
||||
|
136
source/tonccpy.c
Normal file
136
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
source/tonccpy.h
Normal file
43
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
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
|
||||
io_ezfo.c
|
||||
|
||||
Hardware Routines for reading the EZ Flash Omega filesystem
|
||||
|
||||
*/
|
||||
|
||||
#include "io_ezfo.h"
|
||||
|
||||
#include <gba_dma.h>
|
||||
|
||||
#define OMEGA_ROM_UNKNOWN ( 0x0000 )
|
||||
#define OMEGA_ROM_PSRAM ( 0x9780 )
|
||||
#define OMEGA_ROM_NOR ( 0xFFFF )
|
||||
|
||||
#define OMEGA_ROM_PAGE_UNKNOWN ( 0xFFFF )
|
||||
#define OMEGA_ROM_PAGE_PSRAM ( 0x0200 )
|
||||
#define OMEGA_ROM_PAGE_KERNEL ( 0x8000 )
|
||||
|
||||
#define OMEGA_SD_BIT_ENABLE ( 0x1 << 0 )
|
||||
#define OMEGA_SD_BIT_READ_STATE ( 0x1 << 1 )
|
||||
|
||||
#define OMEGA_SD_CTL_ENABLE ( OMEGA_SD_BIT_ENABLE )
|
||||
#define OMEGA_SD_CTL_READ_STATE ( OMEGA_SD_BIT_ENABLE | OMEGA_SD_BIT_READ_STATE )
|
||||
#define OMEGA_SD_CTL_DISABLE ( 0x0 )
|
||||
|
||||
/**
|
||||
*
|
||||
* Miscellaneous utility functions
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void _Spin( u32 _cycles ) {
|
||||
while ( _cycles-- ) {
|
||||
asm (
|
||||
"nop"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Omega device functions
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void _Omega_SetROMPage( const u16 _page ) {
|
||||
*( vu16 * )0x9fe0000 = 0xd200;
|
||||
*( vu16 * )0x8000000 = 0x1500;
|
||||
*( vu16 * )0x8020000 = 0xd200;
|
||||
*( vu16 * )0x8040000 = 0x1500;
|
||||
*( vu16 * )0x9880000 = _page;
|
||||
*( vu16 * )0x9fc0000 = 0x1500;
|
||||
}
|
||||
|
||||
static inline void _Omega_SetSDControl( const u16 _control ) {
|
||||
*( vu16 * )0x9fe0000 = 0xd200;
|
||||
*( vu16 * )0x8000000 = 0x1500;
|
||||
*( vu16 * )0x8020000 = 0xd200;
|
||||
*( vu16 * )0x8040000 = 0x1500;
|
||||
*( vu16 * )0x9400000 = _control;
|
||||
*( vu16 * )0x9fc0000 = 0x1500;
|
||||
}
|
||||
|
||||
static inline u32 _Omega_WaitSDResponse() {
|
||||
vu16 respose;
|
||||
u32 waitSpin = 0;
|
||||
while ( waitSpin < 0x100000 ) {
|
||||
respose = *( vu16 * )0x9E00000;
|
||||
if ( respose != 0xEEE1 ) {
|
||||
return 0;
|
||||
}
|
||||
waitSpin += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Disc interface functions
|
||||
*
|
||||
*/
|
||||
|
||||
bool _EZFO_startUp() {
|
||||
return *( vu16 * )0x9fe0000 == OMEGA_ROM_PSRAM;
|
||||
}
|
||||
|
||||
bool _EZFO_isInserted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EWRAM_CODE _EZFO_readSectors( u32 _address, u32 _count, void * _buffer ) {
|
||||
_Omega_SetROMPage( 0x8000 ); // Change to OS mode
|
||||
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_ENABLE );
|
||||
|
||||
u32 readsRemain = 2;
|
||||
for ( u16 ii = 0; ii < _count; ii += 4 ) {
|
||||
const u16 blocks = ( _count - ii > 4 ) ? 4 : ( _count - ii );
|
||||
|
||||
while ( readsRemain ) {
|
||||
*( vu16 * )0x9fe0000 = 0xd200;
|
||||
*( vu16 * )0x8000000 = 0x1500;
|
||||
*( vu16 * )0x8020000 = 0xd200;
|
||||
*( vu16 * )0x8040000 = 0x1500;
|
||||
*( vu16 * )0x9600000 = ( ( _address + ii ) & 0x0000FFFF);
|
||||
*( vu16 * )0x9620000 = ( ( _address + ii ) & 0xFFFF0000) >> 16;
|
||||
*( vu16 * )0x9640000 = blocks;
|
||||
*( vu16 * )0x9fc0000 = 0x1500;
|
||||
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_READ_STATE );
|
||||
const u32 response = _Omega_WaitSDResponse();
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_ENABLE );
|
||||
if ( response && --readsRemain ) {
|
||||
_Spin( 5000 );
|
||||
} else {
|
||||
dmaCopy( ( void * )0x9E00000, ( void * )( _buffer + ii * 512 ), blocks * 512 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_DISABLE );
|
||||
|
||||
_Omega_SetROMPage( 0x200 ); // Return to original mode
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EWRAM_CODE _EZFO_writeSectors( u32 _address, u32 _count, const void * _buffer ) {
|
||||
_Omega_SetROMPage( 0x8000 ); // Change to OS mode
|
||||
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_READ_STATE );
|
||||
for ( u16 ii = 0; ii < _count; ii++ ) {
|
||||
const u16 blocks = ( _count - ii > 4 ) ? 4 : ( _count - ii );
|
||||
|
||||
dmaCopy( _buffer + ii * 512, ( void * )0x9E00000, blocks * 512 );
|
||||
*( vu16 * )0x9fe0000 = 0xd200;
|
||||
*( vu16 * )0x8000000 = 0x1500;
|
||||
*( vu16 * )0x8020000 = 0xd200;
|
||||
*( vu16 * )0x8040000 = 0x1500;
|
||||
*( vu16 * )0x9600000 = ( ( _address + ii ) & 0x0000FFFF );
|
||||
*( vu16 * )0x9620000 = ( ( _address +ii ) & 0xFFFF0000 ) >> 16;
|
||||
*( vu16 * )0x9640000 = 0x8000 + blocks;
|
||||
*( vu16 * )0x9fc0000 = 0x1500;
|
||||
|
||||
_Omega_WaitSDResponse();
|
||||
}
|
||||
|
||||
_Spin( 3000 );
|
||||
|
||||
_Omega_SetSDControl( OMEGA_SD_CTL_DISABLE );
|
||||
|
||||
_Omega_SetROMPage( 0x200 ); // Return to original mode
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _EZFO_clearStatus() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _EZFO_shutdown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
const DISC_INTERFACE _io_ezfo = {
|
||||
DEVICE_TYPE_EZFO,
|
||||
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
|
||||
( FN_MEDIUM_STARTUP )&_EZFO_startUp,
|
||||
( FN_MEDIUM_ISINSERTED )&_EZFO_isInserted,
|
||||
( FN_MEDIUM_READSECTORS )&_EZFO_readSectors,
|
||||
( FN_MEDIUM_WRITESECTORS )&_EZFO_writeSectors,
|
||||
( FN_MEDIUM_CLEARSTATUS )&_EZFO_clearStatus,
|
||||
( FN_MEDIUM_SHUTDOWN )&_EZFO_shutdown
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
|
||||
io_ezfo.h
|
||||
|
||||
Hardware Routines for reading the EZ Flash Omega filesystem
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __IO_EZFO_H__
|
||||
#define __IO_EZFO_H__
|
||||
|
||||
// 'EZFO'
|
||||
#define DEVICE_TYPE_EZFO 0x4F465A45
|
||||
|
||||
#include <disc_io.h>
|
||||
|
||||
// Export interface
|
||||
extern const DISC_INTERFACE _io_ezfo;
|
||||
|
||||
#endif // define __IO_EZFO_H__
|
Loading…
Reference in New Issue
Block a user