Initial commit

This commit is contained in:
Gericom
2025-10-11 13:23:06 +02:00
commit cecac10408
9 changed files with 665 additions and 0 deletions

72
source/card.c Normal file
View 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
View 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*)&REG_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
View 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
View 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;
}