You've already forked dspico-dldi
mirror of
https://github.com/LNH-team/dspico-dldi.git
synced 2026-01-09 16:28:03 -08:00
Initial commit
This commit is contained in:
35
.github/workflows/nightly.yml
vendored
Normal file
35
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Build DSpico DLDI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["develop"]
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
pull_request:
|
||||
branches: ["develop"]
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dspico_dldi:
|
||||
runs-on: ubuntu-latest
|
||||
container: skylyrac/blocksds:slim-v1.13.1
|
||||
name: Build DSpico DLDI
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Run build script
|
||||
run: |
|
||||
make
|
||||
- name: Publish build to GH Actions
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: DSpico.dldi
|
||||
name: DSpico.dldi
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.dldi
|
||||
*.elf
|
||||
build/
|
||||
17
LICENSE.txt
Normal file
17
LICENSE.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Copyright (c) 2025 LNH team
|
||||
|
||||
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.
|
||||
202
Makefile
Normal file
202
Makefile
Normal file
@@ -0,0 +1,202 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
# SPDX-FileContributor: Antonio Niño Díaz, 2023
|
||||
|
||||
export BLOCKSDS ?= /opt/blocksds/core
|
||||
export BLOCKSDSEXT ?= /opt/blocksds/external
|
||||
|
||||
export WONDERFUL_TOOLCHAIN ?= /opt/wonderful
|
||||
ARM_NONE_EABI_PATH ?= $(WONDERFUL_TOOLCHAIN)/toolchain/gcc-arm-none-eabi/bin/
|
||||
|
||||
# User config
|
||||
# ===========
|
||||
|
||||
NAME := DSpico
|
||||
|
||||
# Source code paths
|
||||
# -----------------
|
||||
|
||||
SOURCEDIRS := source
|
||||
INCLUDEDIRS :=
|
||||
BINDIRS :=
|
||||
|
||||
# Defines passed to all files
|
||||
# ---------------------------
|
||||
|
||||
DEFINES :=
|
||||
|
||||
# Libraries
|
||||
# ---------
|
||||
|
||||
ifeq ($(DLDI_ARM9),1)
|
||||
LIBS := -lnds9
|
||||
else
|
||||
LIBS := -lnds7
|
||||
endif
|
||||
LIBDIRS := $(BLOCKSDS)/libs/libnds
|
||||
|
||||
# Build artifacts
|
||||
# -----------------
|
||||
|
||||
BUILDDIR := build/$(NAME)
|
||||
ELF := build/$(NAME).elf
|
||||
DUMP := build/$(NAME).dump
|
||||
MAP := build/$(NAME).map
|
||||
DLDI := $(NAME).dldi
|
||||
|
||||
# Tools
|
||||
# -----
|
||||
|
||||
PREFIX := $(ARM_NONE_EABI_PATH)arm-none-eabi-
|
||||
CC := $(PREFIX)gcc
|
||||
CXX := $(PREFIX)g++
|
||||
LD := $(PREFIX)gcc
|
||||
OBJDUMP := $(PREFIX)objdump
|
||||
OBJCOPY := $(PREFIX)objcopy
|
||||
MKDIR := mkdir
|
||||
RM := rm -rf
|
||||
|
||||
# Verbose flag
|
||||
# ------------
|
||||
|
||||
ifeq ($(VERBOSE),1)
|
||||
V :=
|
||||
else
|
||||
V := @
|
||||
endif
|
||||
|
||||
# Source files
|
||||
# ------------
|
||||
|
||||
ifneq ($(BINDIRS),)
|
||||
SOURCES_BIN := $(shell find -L $(BINDIRS) -name "*.bin")
|
||||
INCLUDEDIRS += $(addprefix $(BUILDDIR)/,$(BINDIRS))
|
||||
endif
|
||||
|
||||
SOURCES_S := $(shell find -L $(SOURCEDIRS) -name "*.s")
|
||||
SOURCES_C := $(shell find -L $(SOURCEDIRS) -name "*.c")
|
||||
SOURCES_CPP := $(shell find -L $(SOURCEDIRS) -name "*.cpp")
|
||||
|
||||
# Compiler and linker flags
|
||||
# -------------------------
|
||||
|
||||
ifeq ($(DLDI_ARM9),1)
|
||||
ARCH := -mthumb -mcpu=arm946e-s+nofp
|
||||
SPECS := $(BLOCKSDS)/sys/crts/dldi_arm9.specs
|
||||
else
|
||||
ARCH := -mthumb -mcpu=arm7tdmi
|
||||
SPECS := $(BLOCKSDS)/sys/crts/dldi_arm7.specs
|
||||
endif
|
||||
|
||||
WARNFLAGS := -Wall
|
||||
|
||||
ifeq ($(SOURCES_CPP),)
|
||||
LIBS += -lc
|
||||
else
|
||||
LIBS += -lstdc++ -lc
|
||||
endif
|
||||
|
||||
INCLUDEFLAGS := $(foreach path,$(INCLUDEDIRS),-I$(path)) \
|
||||
$(foreach path,$(LIBDIRS),-I$(path)/include)
|
||||
|
||||
LIBDIRSFLAGS := $(foreach path,$(LIBDIRS),-L$(path)/lib)
|
||||
|
||||
ASFLAGS += -x assembler-with-cpp $(DEFINES) $(INCLUDEFLAGS) \
|
||||
$(ARCH) -ffunction-sections -fdata-sections \
|
||||
-specs=$(SPECS)
|
||||
|
||||
CFLAGS += -std=gnu17 $(WARNFLAGS) $(DEFINES) $(INCLUDEFLAGS) \
|
||||
$(ARCH) -O2 -ffunction-sections -fdata-sections \
|
||||
-specs=$(SPECS)
|
||||
|
||||
CXXFLAGS += -std=gnu++17 $(WARNFLAGS) $(DEFINES) $(INCLUDEFLAGS) \
|
||||
$(ARCH) -O2 -ffunction-sections -fdata-sections \
|
||||
-fno-exceptions -fno-rtti \
|
||||
-specs=$(SPECS)
|
||||
|
||||
LDFLAGS += $(ARCH) $(LIBDIRSFLAGS) -Wl,-Map,$(MAP) $(DEFINES) \
|
||||
-Wl,--start-group $(LIBS) -Wl,--end-group -specs=$(SPECS)
|
||||
|
||||
# Intermediate build files
|
||||
# ------------------------
|
||||
|
||||
OBJS_ASSETS := $(addsuffix .o,$(addprefix $(BUILDDIR)/,$(SOURCES_BIN)))
|
||||
|
||||
HEADERS_ASSETS := $(patsubst %.bin,%_bin.h,$(addprefix $(BUILDDIR)/,$(SOURCES_BIN)))
|
||||
|
||||
OBJS_SOURCES := $(addsuffix .o,$(addprefix $(BUILDDIR)/,$(SOURCES_S))) \
|
||||
$(addsuffix .o,$(addprefix $(BUILDDIR)/,$(SOURCES_C))) \
|
||||
$(addsuffix .o,$(addprefix $(BUILDDIR)/,$(SOURCES_CPP)))
|
||||
|
||||
OBJS := $(OBJS_ASSETS) $(OBJS_SOURCES)
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
# Targets
|
||||
# -------
|
||||
|
||||
.PHONY: all clean dump
|
||||
|
||||
all: $(DLDI)
|
||||
|
||||
$(ELF): $(OBJS)
|
||||
@echo " LD $@"
|
||||
$(V)$(LD) -o $@ $(OBJS) $(LDFLAGS)
|
||||
|
||||
$(DLDI): $(ELF)
|
||||
@echo " OBJCOPY $@"
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
|
||||
$(DUMP): $(ELF)
|
||||
@echo " OBJDUMP $@"
|
||||
$(V)$(OBJDUMP) -h -C -S $< > $@
|
||||
|
||||
dump: $(DUMP)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
$(V)$(RM) $(DLDI) $(BUILDDIR)
|
||||
|
||||
# Rules
|
||||
# -----
|
||||
|
||||
$(BUILDDIR)/%.s.o : %.s
|
||||
@echo " AS $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(CC) $(ASFLAGS) -MMD -MP -c -o $@ $<
|
||||
|
||||
$(BUILDDIR)/%.c.o : %.c
|
||||
@echo " CC $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(CC) $(CFLAGS) -MMD -MP -c -o $@ $<
|
||||
|
||||
$(BUILDDIR)/%.arm.c.o : %.arm.c
|
||||
@echo " CC $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(CC) $(CFLAGS) -MMD -MP -marm -mlong-calls -c -o $@ $<
|
||||
|
||||
$(BUILDDIR)/%.cpp.o : %.cpp
|
||||
@echo " CXX $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(CXX) $(CXXFLAGS) -MMD -MP -c -o $@ $<
|
||||
|
||||
$(BUILDDIR)/%.arm.cpp.o : %.arm.cpp
|
||||
@echo " CXX $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(CXX) $(CXXFLAGS) -MMD -MP -marm -mlong-calls -c -o $@ $<
|
||||
|
||||
$(BUILDDIR)/%.bin.o $(BUILDDIR)/%_bin.h : %.bin
|
||||
@echo " BIN2C $<"
|
||||
@$(MKDIR) -p $(@D)
|
||||
$(V)$(BLOCKSDS)/tools/bin2c/bin2c $< $(@D)
|
||||
$(V)$(CC) $(CFLAGS) -MMD -MP -c -o $(BUILDDIR)/$*.bin.o $(BUILDDIR)/$*_bin.c
|
||||
|
||||
# All assets must be built before the source code
|
||||
# -----------------------------------------------
|
||||
|
||||
$(SOURCES_S) $(SOURCES_C) $(SOURCES_CPP): $(HEADERS_ASSETS)
|
||||
|
||||
# Include dependency files if they exist
|
||||
# --------------------------------------
|
||||
|
||||
-include $(DEPS)
|
||||
22
README.md
Normal file
22
README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# DSpico DLDI
|
||||
|
||||
Source code for the DSpico DLDI driver.
|
||||
|
||||
## Setup & Configuration
|
||||
|
||||
We recommend using WSL (Windows Subsystem for Linux), or MSYS2 to compile this repository.
|
||||
The steps provided will assume you already have one of those environments set up.
|
||||
|
||||
1. Install [BlocksDS](https://blocksds.skylyrac.net/docs/setup/options/)
|
||||
|
||||
## Compiling
|
||||
|
||||
1. Run `make`
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Zlib license. For details, see `LICENSE.txt`.
|
||||
|
||||
## Contributors
|
||||
- [@Gericom](https://github.com/Gericom)
|
||||
- [@lifehackerhansol](https://github.com/lifehackerhansol)
|
||||
72
source/card.c
Normal file
72
source/card.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <nds/ndstypes.h>
|
||||
#include "card.h"
|
||||
|
||||
void card_romCpuRead(u32* dst, u32 words)
|
||||
{
|
||||
u32* target = dst + words;
|
||||
do
|
||||
{
|
||||
// Read data if available
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
u32 data = card_romGetData();
|
||||
if (dst < target)
|
||||
*dst++ = data;
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuReadUnaligned(u8* dst, u32 words)
|
||||
{
|
||||
u8* target = dst + (words << 2);
|
||||
do
|
||||
{
|
||||
// Read data if available
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
u32 data = card_romGetData();
|
||||
if (dst < target)
|
||||
{
|
||||
*dst++ = data & 0xFF;
|
||||
*dst++ = (data >> 8) & 0xFF;
|
||||
*dst++ = (data >> 16) & 0xFF;
|
||||
*dst++ = (data >> 24) & 0xFF;
|
||||
}
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuWrite(const u32* src, u32 words)
|
||||
{
|
||||
u32 data = 0;
|
||||
const u32* target = src + words;
|
||||
do
|
||||
{
|
||||
// Write data if ready
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
if (src < target)
|
||||
data = *src++;
|
||||
card_romSetData(data);
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuWriteUnaligned(const u8* src, u32 words)
|
||||
{
|
||||
u32 data = 0;
|
||||
const u8* target = src + (words << 2);
|
||||
do
|
||||
{
|
||||
// Write data if ready
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
if (src < target)
|
||||
{
|
||||
data = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
src += 4;
|
||||
}
|
||||
card_romSetData(data);
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
124
source/card.h
Normal file
124
source/card.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#define REG_MCCNT0 (*(vu16*)0x040001A0)
|
||||
#define REG_MCD0 (*(vu16*)0x040001A2)
|
||||
#define REG_MCCNT1 (*(vu32*)0x040001A4)
|
||||
#define REG_MCCMD0 (*(vu32*)0x040001A8)
|
||||
#define REG_MCCMD1 (*(vu32*)0x040001AC)
|
||||
#define REG_MCSCR0 (*(vu32*)0x040001B0)
|
||||
#define REG_MCSCR1 (*(vu32*)0x040001B4)
|
||||
#define REG_MCSCR2 (*(vu32*)0x040001B8)
|
||||
#define REG_MCD1 (*(vu32*)0x04100010)
|
||||
|
||||
// REG_MCCNT0
|
||||
|
||||
#define MCCNT0_SPI_RATE_4_19_MHZ 0
|
||||
#define MCCNT0_SPI_RATE_2_09_MHZ 1
|
||||
#define MCCNT0_SPI_RATE_1_05_MHZ 2
|
||||
#define MCCNT0_SPI_RATE_524_KHZ 3
|
||||
|
||||
#define MCCNT0_SPI_HOLD_CS (1 << 6)
|
||||
#define MCCNT0_SPI_BUSY (1 << 7)
|
||||
|
||||
#define MCCNT0_MODE_MASK (1 << 13)
|
||||
#define MCCNT0_MODE_ROM (0 << 13)
|
||||
#define MCCNT0_MODE_SPI (1 << 13)
|
||||
|
||||
#define MCCNT0_ROM_XFER_IRQ (1 << 14)
|
||||
#define MCCNT0_ENABLE (1 << 15)
|
||||
|
||||
// REG_MCCNT1
|
||||
|
||||
#define MCCNT1_LATENCY1_SHIFT 0
|
||||
#define MCCNT1_LATENCY1_MASK 0x1FFF
|
||||
#define MCCNT1_LATENCY1(x) (x)
|
||||
|
||||
#define MCCNT1_READ_DATA_DESCRAMBLE (1 << 13)
|
||||
#define MCCNT1_CLOCK_SCRAMBLER (1 << 14)
|
||||
#define MCCNT1_APPLY_SCRAMBLE_SEED (1 << 15)
|
||||
|
||||
#define MCCNT1_LATENCY2_SHIFT 16
|
||||
#define MCCNT1_LATENCY2_MASK 0x3F0000
|
||||
#define MCCNT1_LATENCY2(x) (((x) << MCCNT1_LATENCY2_SHIFT) & MCCNT1_LATENCY2_MASK)
|
||||
|
||||
#define MCCNT1_CMD_SCRAMBLE (1 << 22)
|
||||
|
||||
#define MCCNT1_DATA_READY (1 << 23)
|
||||
|
||||
#define MCCNT1_LEN_0 (0 << 24)
|
||||
#define MCCNT1_LEN_512 (1 << 24)
|
||||
#define MCCNT1_LEN_1024 (2 << 24)
|
||||
#define MCCNT1_LEN_2048 (3 << 24)
|
||||
#define MCCNT1_LEN_4096 (4 << 24)
|
||||
#define MCCNT1_LEN_8192 (5 << 24)
|
||||
#define MCCNT1_LEN_16384 (6 << 24)
|
||||
#define MCCNT1_LEN_4 (7 << 24)
|
||||
|
||||
#define MCCNT1_CLK_6_7_MHZ (0 << 27)
|
||||
#define MCCNT1_CLK_4_2_MHZ (1 << 27)
|
||||
|
||||
#define MCCNT1_LATENCY_CLK (1 << 28)
|
||||
|
||||
#define MCCNT1_RESET_ON (0 << 29)
|
||||
#define MCCNT1_RESET_OFF (1 << 29)
|
||||
|
||||
#define MCCNT1_DIR_READ (0 << 30)
|
||||
#define MCCNT1_DIR_WRITE (1 << 30)
|
||||
|
||||
#define MCCNT1_ENABLE (1 << 31)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
static inline void card_romSetCmd(u64 cmd)
|
||||
{
|
||||
*(vu64*)®_MCCMD0 = __builtin_bswap64(cmd);
|
||||
}
|
||||
|
||||
static inline bool card_romIsDataReady(void)
|
||||
{
|
||||
return REG_MCCNT1 & MCCNT1_DATA_READY;
|
||||
}
|
||||
|
||||
static inline void card_romWaitDataReady(void)
|
||||
{
|
||||
while(!card_romIsDataReady());
|
||||
}
|
||||
|
||||
static inline u32 card_romGetData(void)
|
||||
{
|
||||
return REG_MCD1;
|
||||
}
|
||||
|
||||
static inline void card_romSetData(u32 data)
|
||||
{
|
||||
REG_MCD1 = data;
|
||||
}
|
||||
|
||||
static inline bool card_romIsBusy(void)
|
||||
{
|
||||
return REG_MCCNT1 & MCCNT1_ENABLE;
|
||||
}
|
||||
|
||||
static inline void card_romWaitBusy(void)
|
||||
{
|
||||
while(card_romIsBusy());
|
||||
}
|
||||
|
||||
static inline void card_romStartXfer(u32 settings, bool irq)
|
||||
{
|
||||
REG_MCCNT0 = (REG_MCCNT0 & ~MCCNT0_MODE_MASK) | MCCNT0_MODE_ROM | (irq ? MCCNT0_ROM_XFER_IRQ : 0) | MCCNT0_ENABLE;
|
||||
REG_MCCNT1 = MCCNT1_ENABLE | settings;
|
||||
}
|
||||
|
||||
void card_romCpuRead(u32* dst, u32 len);
|
||||
void card_romCpuReadUnaligned(u8* dst, u32 words);
|
||||
|
||||
void card_romCpuWrite(const u32* src, u32 words);
|
||||
void card_romCpuWriteUnaligned(const u8* src, u32 words);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
61
source/dldi_header.s
Normal file
61
source/dldi_header.s
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Zlib
|
||||
//
|
||||
// Copyright (C) 2006-2016 Michael Chisholm (Chishm)
|
||||
// Copyright (C) 2006-2016 Dave Murphy (WinterMute)
|
||||
|
||||
#include <nds/arm9/dldi_asm.h>
|
||||
|
||||
.syntax unified
|
||||
.section ".crt0","ax"
|
||||
.global _start
|
||||
.align 4
|
||||
.arm
|
||||
|
||||
@ Driver patch file standard header -- 16 bytes
|
||||
|
||||
.word 0xBF8DA5ED @ DLDI identifier - magic number
|
||||
.asciz " Chishm" @ DLDI identifier - magic string (8 bytes with null terminator)
|
||||
.byte 0x01 @ DLDI identifier - DLDI version number
|
||||
.byte __dldi_header_driver_size @ Log [base-2] of the size of this driver in bytes.
|
||||
@ Calculated automatically in the link script.
|
||||
.byte __dldi_header_fix_flags @ Sections to fix.
|
||||
@ Calculated automatically in the link script.
|
||||
.byte 0x00 @ Space allocated in the .nds file; leave empty.
|
||||
|
||||
@ Text identifier - can be anything up to 47 chars + terminating null -- 48 bytes
|
||||
|
||||
.align 4
|
||||
.asciz "DSpico DLDI"
|
||||
|
||||
@ 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 "PICO" @ ioType (Normally "DLDI")
|
||||
#ifdef ARM9
|
||||
.word FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS
|
||||
#else
|
||||
.word FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS | FEATURE_ARM7_CAPABLE
|
||||
#endif
|
||||
.word dldi_startup @ Function pointers to standard device driver functions
|
||||
.word dldi_isInserted
|
||||
.word dldi_readSectors
|
||||
.word dldi_writeSectors
|
||||
.word dldi_clearStatus
|
||||
.word dldi_shutdown
|
||||
|
||||
_start:
|
||||
|
||||
.align
|
||||
.pool
|
||||
.end
|
||||
129
source/iointerface.c
Normal file
129
source/iointerface.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include <nds/ndstypes.h>
|
||||
#include "card.h"
|
||||
|
||||
#define DSPICO_CMD_REQUEST_SD_READ(sector) (0xE300000000000000ull | (sector))
|
||||
#define DSPICO_CMD_POLL_SD_READY 0xE400000000000000ull
|
||||
#define DSPICO_CMD_GET_SD_DATA 0xE500000000000000ull
|
||||
#define DSPICO_CMD_WRITE_SD_DATA(sector, isFirst, isLast)\
|
||||
(0xF6E10D9800000000ull | ((isFirst ? 1ULL : 0ULL) << 33) | ((isLast ? 1ULL : 0ULL) << 32) | (sector))
|
||||
|
||||
__attribute__((noinline)) static void requestSdRead(u32 sector)
|
||||
{
|
||||
card_romSetCmd(DSPICO_CMD_REQUEST_SD_READ(sector));
|
||||
card_romStartXfer(MCCNT1_DIR_READ | MCCNT1_RESET_OFF | MCCNT1_CLK_6_7_MHZ | MCCNT1_LEN_0 | MCCNT1_CMD_SCRAMBLE |
|
||||
MCCNT1_LATENCY2(0) | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE | MCCNT1_LATENCY1(0), false);
|
||||
card_romWaitBusy();
|
||||
}
|
||||
|
||||
__attribute__((noinline)) static u32 pollSdDataReady(void)
|
||||
{
|
||||
u32 result;
|
||||
card_romSetCmd(DSPICO_CMD_POLL_SD_READY);
|
||||
card_romStartXfer(MCCNT1_DIR_READ | MCCNT1_RESET_OFF | MCCNT1_CLK_6_7_MHZ | MCCNT1_LEN_4 | MCCNT1_CMD_SCRAMBLE |
|
||||
MCCNT1_LATENCY2(4) | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE | MCCNT1_LATENCY1(0), false);
|
||||
card_romCpuRead(&result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
__attribute__((noinline)) static void getSdData(u8* dst)
|
||||
{
|
||||
card_romSetCmd(DSPICO_CMD_GET_SD_DATA);
|
||||
card_romStartXfer(MCCNT1_DIR_READ | MCCNT1_RESET_OFF | MCCNT1_CLK_6_7_MHZ | MCCNT1_LEN_512 | MCCNT1_CMD_SCRAMBLE |
|
||||
MCCNT1_LATENCY2(4) | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_LATENCY1(0), false);
|
||||
if ((u32)dst & 3)
|
||||
{
|
||||
card_romCpuReadUnaligned(dst, 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
card_romCpuRead((u32*)dst, 128);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeSdData(u32 sector, const u8* src, bool isFirst, bool isLast)
|
||||
{
|
||||
card_romSetCmd(DSPICO_CMD_WRITE_SD_DATA(sector, isFirst, isLast));
|
||||
card_romStartXfer(MCCNT1_DIR_WRITE | MCCNT1_RESET_OFF | MCCNT1_CLK_6_7_MHZ | MCCNT1_LEN_512 | MCCNT1_CMD_SCRAMBLE |
|
||||
MCCNT1_LATENCY2(8) | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE | MCCNT1_LATENCY1(0), false);
|
||||
if ((u32)src & 3)
|
||||
{
|
||||
card_romCpuWriteUnaligned(src, 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
card_romCpuWrite((const u32*)src, 128);
|
||||
}
|
||||
}
|
||||
|
||||
bool dldi_startup(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dldi_isInserted(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dldi_clearStatus(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dldi_readSectors(u32 sector, u32 numSectors, void* buffer)
|
||||
{
|
||||
u8* ptr = (u8*)buffer;
|
||||
|
||||
requestSdRead(sector);
|
||||
|
||||
do
|
||||
{
|
||||
while (!pollSdDataReady());
|
||||
getSdData(ptr);
|
||||
ptr += 512;
|
||||
} while (--numSectors);
|
||||
|
||||
// Important! This makes sure that SdCard has returned
|
||||
// to State::Idle. Otherwise the next transfer may fail.
|
||||
while (!pollSdDataReady());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dldi_writeSectors(u32 sector, u32 numSectors, void* buffer)
|
||||
{
|
||||
if (numSectors > 0)
|
||||
{
|
||||
const u8* ptr = (const u8*)buffer;
|
||||
if (numSectors == 1)
|
||||
{
|
||||
writeSdData(sector, ptr, true, true); // send 0 = last
|
||||
}
|
||||
else
|
||||
{
|
||||
writeSdData(sector, ptr, true, false); // send 0
|
||||
sector++;
|
||||
ptr += 512;
|
||||
|
||||
for (u32 i = 1; i < numSectors - 1; i++)
|
||||
{
|
||||
writeSdData(sector, ptr, false, false); // send i
|
||||
sector++;
|
||||
ptr += 512;
|
||||
while (!pollSdDataReady()); // wait i - 1
|
||||
}
|
||||
|
||||
writeSdData(sector, ptr, false, true); // send last
|
||||
while (!pollSdDataReady()); // wait last - 1
|
||||
}
|
||||
|
||||
while (!pollSdDataReady()); // wait last
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dldi_shutdown(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user