Skip to content

Commit

Permalink
sg3d: Initial implementation for the Stargate 3DS
Browse files Browse the repository at this point in the history
Fork of ace3ds_sd.

Key differences:
- No XOR at end of write flush command
- Scrambler does not start during write buffer transfer
  • Loading branch information
lifehackerhansol committed Jun 6, 2024
1 parent cac4988 commit b9e62d0
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 0 deletions.
132 changes: 132 additions & 0 deletions source/sg3d/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#---------------------------------------------------------------------------------
.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 ../../common_source
DATA := data
INCLUDES := include ../../common_source


#---------------------------------------------------------------------------------
# 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
#---------------------------------------------------------------------------------------
54 changes: 54 additions & 0 deletions source/sg3d/source/dldi_header.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Zlib
//
// Copyright (C) 2006-2016 Michael Chisholm (Chishm)
// Copyright (C) 2006-2016 Dave Murphy (WinterMute)

#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 @ Log [base-2] of the size of this driver in bytes.
.byte FIX_GOT | FIX_BSS | FIX_GLUE @ Sections to fix
.byte 0x00 @ Space allocated in the application, leave empty.

@ Text identifier - can be anything up to 47 chars + terminating null -- 48 bytes

.align 4
.asciz "Stargate 3DS"

@ 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 "SG3D"
.word FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS
.word startup @ Function pointers to standard device driver functions
.word is_inserted
.word read_sectors
.word write_sectors
.word clear_status
.word shutdown

_start:

.align
.pool
.end
58 changes: 58 additions & 0 deletions source/sg3d/source/io_sg3d.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Stargate 3DS
Card IO routines
Copyright (C) 2023 lifehackerhansol
SPDX-License-Identifier: Zlib
*/

#include <nds/ndstypes.h>
#include "io_sg3d.h"
#include "libtwl_card.h"

static inline void SG3D_ReadCardData(u64 command, u32 flags, void *buffer, u32 length)
{
card_romSetCmd(command);
card_romStartXfer(flags, false);
if ((u32)buffer & 3)
card_romCpuReadUnaligned((u8 *)buffer, length);
else
card_romCpuRead(buffer, length);
}

static inline void SG3D_WriteCardData(u64 command, u32 flags, const void *buffer, u32 length)
{
card_romSetCmd(command);
card_romStartXfer(flags, false);
if ((u32)buffer & 3)
card_romCpuWriteUnaligned((u8 *)buffer, length);
else
card_romCpuWrite(buffer, length);
}

static inline u32 SG3D_SendCommand(const u64 command)
{
card_romSetCmd(command);
card_romStartXfer(SG3D_CTRL_READ_4B, false);
card_romWaitDataReady();
return card_romGetData();
}

void SG3D_SDReadSector(u32 sector, void *buffer)
{
// wait until data is ready
// request should return 0 when ready to access
while(SG3D_SendCommand(SG3D_CMD_SD_READ_REQUEST(sector)));

SG3D_ReadCardData(SG3D_CMD_SD_READ_DATA, SG3D_CTRL_READ_512B, buffer, 128);
}

void SG3D_SDWriteSector(u32 sector, const void *buffer)
{
SG3D_WriteCardData(SG3D_CMD_SD_WRITE_START(sector), SG3D_CTRL_WRITE_512B, buffer, 128);

// Wait until write finishes
// status should return 0 when done
while(SG3D_SendCommand(SG3D_CMD_SD_WRITE_STAT(sector)));
}
46 changes: 46 additions & 0 deletions source/sg3d/source/io_sg3d.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Stargate 3DS
Card IO routines
Copyright (C) 2023 lifehackerhansol
SPDX-License-Identifier: Zlib
*/

#pragma once

#include <nds/ndstypes.h>

#ifndef NULL
#define NULL 0
#endif

// Stargate 3DS defines
// Stargate 3DS MCCNT1 flags
#define SG3D_CTRL_BASE (MCCNT1_ENABLE | MCCNT1_RESET_OFF | MCCNT1_CMD_SCRAMBLE | MCCNT1_LATENCY2(0) | MCCNT1_LATENCY1(0))
#define SG3D_CTRL_READ_4B (SG3D_CTRL_BASE | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE | MCCNT1_LEN_4)
#define SG3D_CTRL_READ_512B (SG3D_CTRL_BASE | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE | MCCNT1_LEN_512)
#define SG3D_CTRL_WRITE_512B (SG3D_CTRL_BASE | MCCNT1_DIR_WRITE | MCCNT1_LEN_512)

// Stargate 3DS MCCMDs
#define SG3D_CMD_SD_READ_DATA (0xBAull << 56)

static inline u64 SG3D_CMD_SD_READ_REQUEST(u32 sector)
{
return (0xB9ull << 56) | ((u64)sector << 24);
}

static inline u64 SG3D_CMD_SD_WRITE_START(u32 sector)
{
return (0xBBull << 56) | ((u64)sector << 24);
}

static inline u64 SG3D_CMD_SD_WRITE_STAT(u32 sector)
{
u64 command = (0xBCull << 56) | ((u64)sector << 24);
return command;
}

// user API
void SG3D_SDReadSector(u32 sector, void* buffer);
void SG3D_SDWriteSector(u32 sector, const void* buffer);
57 changes: 57 additions & 0 deletions source/sg3d/source/iointerface.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: CC0-1.0
//
// SPDX-FileContributor: Antonio Niño Díaz, 2023
// SPDX-FileContributor: lifehackerhansol, 2023

#include <nds/ndstypes.h>

#include "io_sg3d.h"
#include "libtwl_card.h"

// Initialize the driver. Returns true on success.
bool startup(void)
{
return true;
}

// Returns true if a card is present and initialized.
bool is_inserted(void)
{
return true;
}

// Reads 512 byte sectors into a buffer that may be unaligned. Returns true on
// success.
bool read_sectors(uint32_t sector, uint32_t num_sectors, void *buffer)
{
for (int i = 0; i < num_sectors; i++)
{
SG3D_SDReadSector((sector + i), buffer);
buffer = (u8 *)buffer + 0x200;
}
return true;
}

// Writes 512 byte sectors from a buffer that may be unaligned. Returns true on
// success.
bool write_sectors(uint32_t sector, uint32_t num_sectors, const void *buffer)
{
for (int i = 0; i < num_sectors; i++)
{
SG3D_SDWriteSector((sector + i), buffer);
buffer = (u8 *)buffer + 0x200;
}
return true;
}

// Clear error flags from the card. Returns true on success.
bool clear_status(void)
{
return true;
}

// Shutdowns the card. This may never be called.
bool shutdown(void)
{
return true;
}

0 comments on commit b9e62d0

Please sign in to comment.