├── .gitignore ├── CMakeLists.txt ├── COPYING ├── Catnip.cmake ├── README.md ├── docs ├── common.doxyfile ├── ds9.doxyfile ├── groups.h ├── layout.xml └── pages.h ├── include ├── calico.h └── calico │ ├── arm │ ├── cache.h │ ├── common.h │ ├── cp15.h │ ├── mpu.h │ └── psr.h │ ├── asm.inc │ ├── dev │ ├── ar6k.h │ ├── ar6k │ │ ├── base.h │ │ ├── bmi.h │ │ ├── dev.h │ │ ├── htc.h │ │ └── wmi.h │ ├── blk.h │ ├── disc_io.h │ ├── dldi.h │ ├── dldi_defs.h │ ├── fugu.h │ ├── mwl.h │ ├── mwl │ │ ├── calib.h │ │ ├── dev.h │ │ ├── mlme.h │ │ ├── regs.h │ │ └── types.h │ ├── netbuf.h │ ├── sdio.h │ ├── sdmmc.h │ ├── tmio.h │ ├── tmio_regs.h │ ├── wlan.h │ └── wpa.h │ ├── gba │ ├── bios.h │ ├── dma.h │ ├── io.h │ ├── irq.h │ ├── keypad.h │ ├── lcd.h │ ├── mm.h │ └── timer.h │ ├── nds │ ├── arm7 │ │ ├── aes.h │ │ ├── codec.h │ │ ├── debug.h │ │ ├── gpio.h │ │ ├── i2c.h │ │ ├── mcu.h │ │ ├── mic.h │ │ ├── ntrwifi.h │ │ ├── nvram.h │ │ ├── pmic.h │ │ ├── rtc.h │ │ ├── sound.h │ │ ├── spi.h │ │ ├── tsc.h │ │ ├── twlblk.h │ │ └── twlwifi.h │ ├── arm9 │ │ ├── arm7_debug.h │ │ ├── mic.h │ │ ├── ovl.h │ │ ├── sound.h │ │ └── vram.h │ ├── bios.h │ ├── dma.h │ ├── env.h │ ├── gbacart.h │ ├── io.h │ ├── irq.h │ ├── keypad.h │ ├── lcd.h │ ├── mic.h │ ├── mm.h │ ├── mm_env.h │ ├── ndma.h │ ├── nitrorom.h │ ├── ntrcard.h │ ├── pm.h │ ├── pxi.h │ ├── scfg.h │ ├── smutex.h │ ├── sound.h │ ├── system.h │ ├── timer.h │ ├── tlnc.h │ ├── touch.h │ └── wlmgr.h │ ├── system │ ├── condvar.h │ ├── dietprint.h │ ├── irq.h │ ├── mailbox.h │ ├── mutex.h │ ├── sysclock.h │ ├── thread.h │ └── tick.h │ └── types.h ├── share ├── ds7.ld ├── ds7.specs ├── ds9-legacy.ld ├── ds9-legacy.specs ├── ds9.ld ├── ds9.specs ├── gba-cart.ld ├── gba-cart.specs ├── gba-mb.ld ├── gba-mb.specs └── nds-icon.bmp └── source ├── arm ├── arm-aes.32.s ├── arm-cache.32.s ├── arm-context.32.s ├── arm-copy-fill.32.s ├── arm-readtp.32.s ├── arm-shims-mpu.32.c └── arm-shims.32.c ├── dev ├── ar6k │ ├── ar6k_bmi.c │ ├── ar6k_dev.c │ ├── ar6k_htc.c │ ├── ar6k_wmi.c │ └── common.h ├── dldi_stub.s ├── fugu.32.c ├── mwl │ ├── common.h │ ├── mwl_calib.16.c │ ├── mwl_dev_base.16.c │ ├── mwl_dev_bbp_rf.c │ ├── mwl_dev_irq.32.c │ ├── mwl_dev_misc.c │ ├── mwl_dev_task.c │ ├── mwl_mgmt_frame.16.c │ ├── mwl_mlme.c │ ├── mwl_rx.c │ └── mwl_tx.c ├── sdio.c ├── sdmmc.c ├── tmio.c ├── wlan.c └── wpa.c ├── gba ├── bios.s ├── crt0.s ├── crt0_mb.s ├── dma_fill_buf.c ├── irq_handler.32.s ├── rom_header.s └── rom_header_mb.s ├── nds ├── arm7 │ ├── ar6k.twl.32.c │ ├── blk.c │ ├── blk.twl.32.c │ ├── bootstub_arm7.s │ ├── codec.twl.c │ ├── debug.c │ ├── env.c │ ├── gpio.twl.c │ ├── i2c.twl.c │ ├── mcu.twl.c │ ├── mic.32.c │ ├── nvram.c │ ├── pm_arm7.c │ ├── pmic.c │ ├── rtc.c │ ├── scfg.twl.c │ ├── sdio.twl.32.c │ ├── sdmmc.twl.32.c │ ├── sound │ │ ├── common.h │ │ ├── sound.c │ │ └── sound_pxi.c │ ├── spi.c │ ├── tmio.twl.32.c │ ├── touch.c │ ├── tsc.c │ ├── wifi.ntr.c │ ├── wifi.twl.32.c │ ├── wlmgr.c │ ├── wpa.twl.32.c │ ├── wpa_aes.twl.s │ └── wpa_hmac_sha1.twl.32.c ├── arm9 │ ├── arm7_debug.c │ ├── blk.c │ ├── bootstub_arm9.s │ ├── excpt_handler.32.s │ ├── mic.c │ ├── mpu_setup.crt0.s │ ├── nitrorom.c │ ├── ovl.c │ ├── pm_arm9.c │ ├── sound.c │ ├── sys_startup.c │ ├── touch.c │ └── wlmgr.c ├── bios.s ├── bios.twl.s ├── crt0.h ├── gbacart.c ├── irq_handler.32.s ├── keypad.c ├── netbuf.c ├── nitrorom.c ├── ntrcard.c ├── pm.c ├── pxi.c ├── pxi │ ├── blkdev.h │ ├── mic.h │ ├── pm.h │ ├── reset.h │ ├── sound.h │ └── wlmgr.h ├── smutex.32.c ├── startup.crt0.c ├── tlnc.twl.c ├── transfer.h └── utils.crt0.s └── system ├── dietprint.c ├── irq.c ├── mailbox.c ├── mutex.c ├── newlib_syscalls.c ├── thread-priv.h ├── thread_cold.c ├── thread_hot.32.c └── tick.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | docs/out/ 3 | .*/ 4 | *~ 5 | *.bak 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Zope Public License (ZPL) Version 2.1 2 | 3 | A copyright notice accompanies this license document that identifies 4 | the copyright holders. 5 | 6 | This license has been certified as open source. It has also been 7 | designated as GPL compatible by the Free Software Foundation (FSF). 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are 11 | met: 12 | 13 | 1. Redistributions in source code must retain the accompanying 14 | copyright notice, this list of conditions, and the following 15 | disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the accompanying 18 | copyright notice, this list of conditions, and the following 19 | disclaimer in the documentation and/or other materials provided 20 | with the distribution. 21 | 22 | 3. Names of the copyright holders must not be used to endorse or 23 | promote products derived from this software without prior written 24 | permission from the copyright holders. 25 | 26 | 4. The right to distribute this software or to use it for any purpose 27 | does not give you the right to use Servicemarks (sm) or Trademarks 28 | (tm) of the copyright holders. Use of them is covered by separate 29 | agreement with the copyright holders. 30 | 31 | 5. If any files are modified, you must cause the modified files to 32 | carry prominent notices stating that you changed the files and the 33 | date of any change. 34 | 35 | Disclaimer 36 | 37 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 38 | EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 40 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE 41 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 42 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 43 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 44 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 45 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 46 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 47 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | -------------------------------------------------------------------------------- /Catnip.cmake: -------------------------------------------------------------------------------- 1 | 2 | catnip_package(calico DEFAULT ds7_release ds9_release) 3 | 4 | catnip_add_preset(gba_release TOOLSET GBA BUILD_TYPE Release) 5 | 6 | catnip_add_preset(ds7_release TOOLSET NDS PROCESSOR armv4t BUILD_TYPE MinSizeRel) 7 | catnip_add_preset(ds9_release TOOLSET NDS PROCESSOR armv5te BUILD_TYPE Release) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # calico 2 | 3 | Calico is a system support library currently focused on the Nintendo DS(i). It provides operating system-like facilities for homebrew applications, and serves as a new foundation for libnds (and DS homebrew in general). Its main features include: 4 | 5 | - Multitasking system, providing threads (inspired by Horizon). Scheduling is preemptive and based on multiple priority levels, similar to real-time operating systems. 6 | - Synchronization primitives: mutex, condition variable, mailbox. 7 | - Interrupt and timed event handling. 8 | - Low-level support bits for integration with devkitARM (crt0, linker scripts, syscall implementations). 9 | - Message passing between the two processors (ARM9 and ARM7). 10 | - New device drivers for ARM7 peripherals, with programming interfaces accessible from the ARM9: 11 | - Power management, including sleep mode and application lifecycle management 12 | - Touch screen (both DS mode and DSi mode) 13 | - Real-time clock 14 | - Audio and microphone 15 | - Storage devices, including DLDI and DSi SD/eMMC 16 | - Wireless communications (Mitsumi/NDS and Atheros/DSi) 17 | -------------------------------------------------------------------------------- /docs/ds9.doxyfile: -------------------------------------------------------------------------------- 1 | @INCLUDE = common.doxyfile 2 | 3 | OUTPUT_DIRECTORY = out/ds9 4 | 5 | PREDEFINED += __NDS__ ARM9 __ARM_ARCH=5 6 | 7 | EXCLUDE = \ 8 | ../include/calico/nds/arm7 \ 9 | ../include/calico/gba/bios.h \ 10 | ../include/calico/gba/io.h \ 11 | ../include/calico/gba/irq.h \ 12 | ../include/calico/gba/mm.h \ 13 | ../include/calico/dev/ar6k \ 14 | ../include/calico/dev/mwl \ 15 | ../include/calico/dev/ar6k.h \ 16 | ../include/calico/dev/mwl.h \ 17 | ../include/calico/dev/fugu.h \ 18 | ../include/calico/dev/sdio.h \ 19 | ../include/calico/dev/sdmmc.h \ 20 | ../include/calico/dev/tmio_regs.h \ 21 | ../include/calico/dev/tmio.h \ 22 | ../include/calico/dev/wpa.h 23 | -------------------------------------------------------------------------------- /docs/pages.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | /*! @page license License 6 | @brief Licensing information about calico 7 | @include{doc} "../COPYING" 8 | */ 9 | -------------------------------------------------------------------------------- /include/calico.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | // Common types and definitions 6 | #if !__ASSEMBLER__ 7 | #include "calico/types.h" 8 | #else 9 | #include "calico/asm.inc" 10 | #endif 11 | 12 | // Basic arm definitions 13 | #include "calico/arm/psr.h" 14 | 15 | // arm9 (armv5) platforms: CP15 definitions 16 | #if __ARM_ARCH >= 5 17 | #include "calico/arm/cp15.h" 18 | #endif 19 | 20 | // System bus frequency definition 21 | #include "calico/system/sysclock.h" 22 | 23 | // Memory map & IO register definitions 24 | #if defined(__GBA__) 25 | #include "calico/gba/mm.h" 26 | #include "calico/gba/io.h" 27 | #elif defined(__NDS__) 28 | #include "calico/nds/mm.h" 29 | #include "calico/nds/mm_env.h" 30 | #include "calico/nds/io.h" 31 | #include "calico/dev/dldi_defs.h" 32 | #else 33 | #error "Unknown/unsupported platform" 34 | #endif 35 | 36 | #if !__ASSEMBLER__ 37 | 38 | #include "calico/arm/common.h" 39 | #if __ARM_ARCH >= 5 40 | #include "calico/arm/cache.h" 41 | #include "calico/arm/mpu.h" 42 | #endif 43 | 44 | #include "calico/system/irq.h" 45 | #include "calico/system/tick.h" 46 | #include "calico/system/thread.h" 47 | #include "calico/system/mutex.h" 48 | #include "calico/system/condvar.h" 49 | #include "calico/system/mailbox.h" 50 | #include "calico/system/dietprint.h" 51 | 52 | #include "calico/dev/fugu.h" 53 | 54 | #if defined(__GBA__) 55 | #include "calico/gba/bios.h" 56 | #include "calico/gba/keypad.h" 57 | #include "calico/gba/timer.h" 58 | #include "calico/gba/dma.h" 59 | #include "calico/gba/lcd.h" 60 | #endif 61 | 62 | #if defined(__NDS__) 63 | #include "calico/nds/system.h" 64 | #include "calico/nds/scfg.h" 65 | #include "calico/nds/bios.h" 66 | #include "calico/nds/timer.h" 67 | #include "calico/nds/dma.h" 68 | #include "calico/nds/ndma.h" 69 | #include "calico/nds/env.h" 70 | #include "calico/nds/tlnc.h" 71 | #include "calico/nds/pxi.h" 72 | #include "calico/nds/smutex.h" 73 | #include "calico/nds/keypad.h" 74 | #include "calico/nds/touch.h" 75 | #include "calico/nds/lcd.h" 76 | #include "calico/nds/pm.h" 77 | 78 | #include "calico/dev/blk.h" 79 | #include "calico/dev/disc_io.h" 80 | #include "calico/dev/dldi.h" 81 | #include "calico/dev/netbuf.h" 82 | #include "calico/dev/wlan.h" 83 | #include "calico/nds/wlmgr.h" 84 | 85 | #include "calico/nds/gbacart.h" 86 | #include "calico/nds/ntrcard.h" 87 | #include "calico/nds/nitrorom.h" 88 | 89 | #ifdef ARM7 90 | #include "calico/nds/arm7/debug.h" 91 | 92 | #include "calico/nds/arm7/gpio.h" 93 | #include "calico/nds/arm7/rtc.h" 94 | #include "calico/nds/arm7/spi.h" 95 | #include "calico/nds/arm7/pmic.h" 96 | #include "calico/nds/arm7/nvram.h" 97 | #include "calico/nds/arm7/tsc.h" 98 | #include "calico/nds/arm7/sound.h" 99 | #include "calico/nds/arm7/mic.h" 100 | #include "calico/nds/arm7/ntrwifi.h" 101 | 102 | #include "calico/nds/arm7/i2c.h" 103 | #include "calico/nds/arm7/mcu.h" 104 | #include "calico/nds/arm7/codec.h" 105 | 106 | #include "calico/nds/arm7/aes.h" 107 | #include "calico/nds/arm7/twlblk.h" 108 | #include "calico/nds/arm7/twlwifi.h" 109 | 110 | #include "calico/dev/tmio.h" 111 | #include "calico/dev/sdmmc.h" 112 | #include "calico/dev/sdio.h" 113 | #include "calico/dev/ar6k.h" 114 | #include "calico/dev/mwl.h" 115 | #endif 116 | 117 | #ifdef ARM9 118 | #include "calico/nds/arm9/arm7_debug.h" 119 | #include "calico/nds/arm9/sound.h" 120 | #include "calico/nds/arm9/mic.h" 121 | 122 | #include "calico/nds/arm9/vram.h" 123 | 124 | #include "calico/nds/arm9/ovl.h" 125 | #endif 126 | 127 | #endif 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /include/calico/arm/cache.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if __ARM_ARCH < 5 5 | #error "This header is for ARMv5+ only" 6 | #endif 7 | 8 | #include "../types.h" 9 | #include "cp15.h" 10 | 11 | /*! @addtogroup cache 12 | @{ 13 | 14 | @note Cache operations by address range are **always** performed on cache line boundaries. 15 | This means that the start of the given range is rounded down (`addr &~ 0x1f`), while 16 | the end of the range is rounded up (`(addr + size + 0x1f) &~ 0x1f`). 17 | */ 18 | 19 | MK_EXTERN_C_START 20 | 21 | /*! @brief Drains the CPU's write buffer, making changes observable to other devices (e.g. ARM7 or DMA). 22 | @note It is usually not necessary to use this barrier because the data cache management functions 23 | (such as @ref armDCacheFlush) already include it. 24 | In addition, uncacheable MPU regions do not usually have the write buffer enabled anyway. 25 | @note In later versions of the ARM architecture (v6+), this is known as a Data Synchronization Barrier (DSB), 26 | and it is also in charge of preventing memory access reordering. 27 | */ 28 | void armDrainWriteBuffer(void); 29 | 30 | //! @brief Flushes (cleans and invalidates) the entire data cache 31 | void armDCacheFlushAll(void); 32 | 33 | /*! @brief Flushes (cleans and invalidates) the data cache lines pertaining to the specified address range 34 | @param addr Start address (any pointer type) 35 | @param size Size of the address range 36 | @note Use this function when sharing a main RAM memory buffer with the ARM7, or with DMA/devices. 37 | @note Consider using @ref armDCacheFlushAll when `size` is large. 38 | As an example, the 3DS ARM9 kernel uses 16 KiB as the threshold. 39 | */ 40 | void armDCacheFlush(const volatile void* addr, size_t size); 41 | 42 | /*! @brief Invalidates the data cache lines pertaining to the specified address range 43 | @param addr Start address (any pointer type) 44 | @param size Size of the address range 45 | @warning Data cache invalidation is rarely useful, and **will** lead to data corruption when used incorrectly. 46 | Prefer using @ref armDCacheFlush, unless the address range is guaranteed to be aligned to cache line boundaries 47 | and it is explicitly permitted to discard unflushed writes within the range. 48 | */ 49 | void armDCacheInvalidate(const volatile void* addr, size_t size); 50 | 51 | //! @brief Invalidates the entire instruction cache 52 | void armICacheInvalidateAll(void); 53 | 54 | /*! @brief Invalidates the instruction cache lines pertaining to the specified address range 55 | @param addr Start address (any pointer type) 56 | @param size Size of the address range 57 | @note Use this function when dynamically loading/generating code (do not forget to use @ref armDCacheFlush too). 58 | @note Consider using @ref armICacheInvalidateAll unless `size` is known to be small. 59 | */ 60 | void armICacheInvalidate(const volatile void* addr, size_t size); 61 | 62 | MK_EXTERN_C_END 63 | 64 | //! @} 65 | -------------------------------------------------------------------------------- /include/calico/arm/psr.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | /*! @addtogroup arm 6 | @{ 7 | */ 8 | /*! @name PSR state flags 9 | @{ 10 | */ 11 | 12 | #define ARM_PSR_MODE_USR 0x10 //!< User execution mode 13 | #define ARM_PSR_MODE_FIQ 0x11 //!< FIQ execution mode 14 | #define ARM_PSR_MODE_IRQ 0x12 //!< IRQ execution mode 15 | #define ARM_PSR_MODE_SVC 0x13 //!< Supervisor execution mode 16 | #define ARM_PSR_MODE_ABT 0x17 //!< Data/prefetch abort execution mode 17 | #define ARM_PSR_MODE_UND 0x1b //!< Undefined instruction execution mode 18 | #define ARM_PSR_MODE_SYS 0x1f //!< System execution mode 19 | #define ARM_PSR_MODE_MASK 0x1f //!< Execution mode mask 20 | 21 | #define ARM_PSR_T (1<<5) //!< THUMB execution mode flag 22 | #define ARM_PSR_F (1<<6) //!< FIQ masked flag 23 | #define ARM_PSR_I (1<<7) //!< IRQ masked flag 24 | #define ARM_PSR_Q (1<<27) //!< Q (saturated) condition flag 25 | #define ARM_PSR_V (1<<28) //!< V (signed overflow) condition flag 26 | #define ARM_PSR_C (1<<29) //!< C (carry/unsigned overflow) condition flag 27 | #define ARM_PSR_Z (1<<30) //!< Z (zero) condition flag 28 | #define ARM_PSR_N (1<<31) //!< N (negative) condition flag 29 | 30 | //! @} 31 | 32 | //! @} 33 | -------------------------------------------------------------------------------- /include/calico/asm.inc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | #if __ARM_ARCH_4T__ 6 | .arch armv4t 7 | #elif __ARM_ARCH_5TE__ 8 | .arch armv5te 9 | #else 10 | #error "Unsupported architecture" 11 | #endif 12 | 13 | .fpu softvfp 14 | 15 | .cfi_sections .debug_frame 16 | 17 | .macro SECT_TEXT name, align=2, section=text 18 | .section .\section\().\name, "ax", %progbits 19 | .align \align 20 | .endm 21 | 22 | .macro SECT_RODATA name, align=2, section=rodata 23 | .section .\section\().\name, "a" 24 | .align \align 25 | .endm 26 | 27 | .macro SECT_DATA name, align=2, section=data 28 | .section .\section\().\name, "aw" 29 | .align \align 30 | .endm 31 | 32 | .macro SECT_BSS name, align=2, section=bss 33 | .section .\section\().\name, "aw", %nobits 34 | .align \align 35 | .endm 36 | 37 | .macro FUNC_START32 name, section=text, linkage=global 38 | SECT_TEXT \name, 2, \section 39 | .\linkage \name 40 | .arm 41 | .type \name, %function 42 | \name: 43 | .cfi_startproc 44 | .size \name, 3135f-\name 45 | .endm 46 | 47 | .macro FUNC_START16 name, section=text, linkage=global 48 | SECT_TEXT \name, 1, \section 49 | .\linkage \name 50 | .thumb_func 51 | .type \name, %function 52 | \name: 53 | .cfi_startproc 54 | .size \name, 3135f-\name 55 | .endm 56 | 57 | .macro FUNC_END 58 | .pool 59 | 3135: 60 | .cfi_endproc 61 | .endm 62 | 63 | .macro REFERENCE symbol 64 | .section .rodata.ref.\symbol, "a" 65 | .align 2 66 | .word \symbol 67 | .endm 68 | -------------------------------------------------------------------------------- /include/calico/dev/ar6k.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "ar6k/base.h" 5 | #include "ar6k/bmi.h" 6 | #include "ar6k/htc.h" 7 | #include "ar6k/wmi.h" 8 | #include "ar6k/dev.h" 9 | -------------------------------------------------------------------------------- /include/calico/dev/ar6k/base.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../../types.h" 5 | #include "../netbuf.h" 6 | #include "../wlan.h" 7 | 8 | MK_EXTERN_C_START 9 | 10 | // Forward declaration 11 | typedef struct Ar6kDev Ar6kDev; 12 | 13 | MK_EXTERN_C_END 14 | -------------------------------------------------------------------------------- /include/calico/dev/ar6k/bmi.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "base.h" 5 | 6 | MK_EXTERN_C_START 7 | 8 | typedef enum Ar6kBmiCommand { 9 | Ar6kBmiCmd_NoCommand = 0, 10 | Ar6kBmiCmd_Done = 1, 11 | Ar6kBmiCmd_ReadMemory = 2, 12 | Ar6kBmiCmd_WriteMemory = 3, 13 | Ar6kBmiCmd_Execute = 4, 14 | Ar6kBmiCmd_SetAppStart = 5, 15 | Ar6kBmiCmd_ReadSocRegister = 6, 16 | Ar6kBmiCmd_WriteSocRegister = 7, 17 | Ar6kBmiCmd_GetTargetInfo = 8, 18 | Ar6kBmiCmd_RomPatchInstall = 9, 19 | Ar6kBmiCmd_RomPatchUninstall = 10, 20 | Ar6kBmiCmd_RomPatchActivate = 11, 21 | Ar6kBmiCmd_RomPatchDeactivate = 12, 22 | Ar6kBmiCmd_LzStreamStart = 13, 23 | Ar6kBmiCmd_LzData = 14, 24 | Ar6kBmiCmd_NvramProcess = 15, 25 | } Ar6kBmiCommand; 26 | 27 | typedef struct Ar6kBmiTargetInfo { 28 | u32 target_ver; 29 | u32 target_type; 30 | } Ar6kBmiTargetInfo; 31 | 32 | bool ar6kBmiBufferSend(Ar6kDev* dev, const void* buf, size_t len); 33 | bool ar6kBmiBufferRecv(Ar6kDev* dev, void* buf, size_t len); 34 | 35 | bool ar6kBmiDone(Ar6kDev* dev); 36 | bool ar6kBmiReadMemory(Ar6kDev* dev, u32 addr, void* buf, size_t len); 37 | bool ar6kBmiWriteMemory(Ar6kDev* dev, u32 addr, const void* buf, size_t len); 38 | bool ar6kBmiReadSocReg(Ar6kDev* dev, u32 addr, u32* out); 39 | bool ar6kBmiWriteSocReg(Ar6kDev* dev, u32 addr, u32 value); 40 | bool ar6kBmiGetTargetInfo(Ar6kDev* dev, Ar6kBmiTargetInfo* info); 41 | 42 | MK_INLINE bool ar6kBmiWriteMemoryWord(Ar6kDev* dev, u32 addr, u32 value) 43 | { 44 | return ar6kBmiWriteMemory(dev, addr, &value, sizeof(u32)); 45 | } 46 | 47 | MK_EXTERN_C_END 48 | -------------------------------------------------------------------------------- /include/calico/dev/ar6k/dev.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../../types.h" 5 | #include "../../system/mailbox.h" 6 | #include "../sdio.h" 7 | #include "base.h" 8 | #include "htc.h" 9 | #include "wmi.h" 10 | 11 | #define AR6K_WORK_BUF_SIZE (sizeof(NetBuf) + AR6K_HTC_MAX_PACKET_SZ) 12 | 13 | MK_EXTERN_C_START 14 | 15 | typedef struct Ar6kEndpoint { 16 | u16 service_id; 17 | u16 max_msg_size; 18 | } Ar6kEndpoint; 19 | 20 | typedef struct Ar6kIrqEnableRegs { 21 | u8 int_status_enable; 22 | u8 cpu_int_status_enable; 23 | u8 error_status_enable; 24 | u8 counter_int_status_enable; 25 | } Ar6kIrqEnableRegs; 26 | 27 | struct Ar6kDev { 28 | SdioCard* sdio; 29 | u32 chip_id; 30 | u32 hia_addr; 31 | 32 | // Interrupt handling 33 | Mailbox irq_mbox; 34 | u32 irq_flag; 35 | Ar6kIrqEnableRegs irq_regs; 36 | 37 | // HTC 38 | void* workbuf; 39 | u32 lookahead; 40 | u16 credit_size; 41 | u16 credit_avail; 42 | u16 max_msg_credits; 43 | Ar6kEndpoint endpoints[Ar6kHtcEndpointId_Count-1]; 44 | 45 | // WMI 46 | bool wmi_ready; 47 | u8 macaddr[6]; 48 | Ar6kHtcEndpointId wmi_ctrl_epid; 49 | Ar6kHtcEndpointId wmi_data_epids[4]; 50 | u32 wmi_channel_mask; 51 | 52 | // Callbacks 53 | void (* cb_onBssInfo)(Ar6kDev* dev, Ar6kWmiBssInfoHdr* bssInfo, NetBuf* pPacket); 54 | void (* cb_onScanComplete)(Ar6kDev* dev, int status); 55 | void (* cb_onAssoc)(Ar6kDev* dev, Ar6kWmiEvtConnected* info); 56 | void (* cb_onDisassoc)(Ar6kDev* dev, Ar6kWmiEvtDisconnected* info); 57 | void (* cb_rx)(Ar6kDev* dev, NetBuf* pPacket); 58 | }; 59 | 60 | bool ar6kDevInit(Ar6kDev* dev, SdioCard* sdio, void* workbuf); 61 | int ar6kDevThreadMain(Ar6kDev* dev); 62 | void ar6kDevThreadCancel(Ar6kDev* dev); 63 | 64 | bool ar6kDevReadRegDiag(Ar6kDev* dev, u32 addr, u32* out); 65 | bool ar6kDevWriteRegDiag(Ar6kDev* dev, u32 addr, u32 value); 66 | 67 | MK_EXTERN_C_END 68 | -------------------------------------------------------------------------------- /include/calico/dev/blk.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | /*! @addtogroup blkdev 7 | Provides a common device-independent interface to all available storage devices. 8 | @{ 9 | */ 10 | 11 | //! Block device sector size (in bytes) 12 | #define BLK_SECTOR_SZ 512 13 | //! Block device sector size (in words) 14 | #define BLK_SECTOR_SZ_WORDS (BLK_SECTOR_SZ/sizeof(u32)) 15 | 16 | MK_EXTERN_C_START 17 | 18 | //! List of available block devices 19 | typedef enum BlkDevice { 20 | 21 | #if defined(__NDS__) 22 | 23 | BlkDevice_Dldi = 0, //!< DLDI device 24 | BlkDevice_TwlSdCard = 1, //!< DSi SD card device 25 | BlkDevice_TwlNand = 2, //!< DSi system memory (raw sector access) 26 | BlkDevice_TwlNandAes = 3, //!< DSi system memory (transparent encryption) 27 | 28 | #else 29 | #error "Unsupported platform" 30 | #endif 31 | 32 | } BlkDevice; 33 | 34 | //! @private 35 | typedef void (*BlkDevCallbackFn)(BlkDevice dev, bool insert); 36 | 37 | //! Initializes the block device subsystem 38 | void blkInit(void); 39 | 40 | //! @private 41 | void blkSetDevCallback(BlkDevCallbackFn fn); 42 | 43 | //! Returns true if block device @p dev is present (and inserted if applicable) 44 | bool blkDevIsPresent(BlkDevice dev); 45 | 46 | //! Initializes block device @p dev, returning true on success 47 | bool blkDevInit(BlkDevice dev); 48 | 49 | //! Retrieves the size in sectors of block device @p dev 50 | u32 blkDevGetSectorCount(BlkDevice dev); 51 | 52 | /*! @brief Reads sectors from block device @p dev 53 | @param[out] buffer Output buffer (alignment note, see below) 54 | @param[in] first_sector Index of the first sector to read 55 | @param[in] num_sectors Number of sectors to read 56 | @return true on success, false on failure 57 | @warning On the ARM9, the output buffer must be cache line (32-byte) aligned and in main RAM. 58 | On the ARM7, the output buffer must be 32-bit aligned. 59 | */ 60 | bool blkDevReadSectors(BlkDevice dev, void* buffer, u32 first_sector, u32 num_sectors); 61 | 62 | /*! @brief Writes sectors to block device @p dev 63 | @param[in] buffer Input buffer (**must be 32-bit aligned**) 64 | @param[in] first_sector Index of the first sector to write 65 | @param[in] num_sectors Number of sectors to write 66 | @return true on success, false on failure 67 | */ 68 | bool blkDevWriteSectors(BlkDevice dev, const void* buffer, u32 first_sector, u32 num_sectors); 69 | 70 | MK_EXTERN_C_END 71 | 72 | //! @} 73 | -------------------------------------------------------------------------------- /include/calico/dev/disc_io.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "dldi_defs.h" 6 | 7 | /*! @addtogroup blkdev 8 | @{ 9 | */ 10 | 11 | /*! @name Generic disc interface 12 | @{ 13 | */ 14 | 15 | #define FEATURE_MEDIUM_CANREAD DLDI_FEATURE_CAN_READ 16 | #define FEATURE_MEDIUM_CANWRITE DLDI_FEATURE_CAN_WRITE 17 | #define FEATURE_SLOT_GBA DLDI_FEATURE_SLOT_GBA 18 | #define FEATURE_SLOT_NDS DLDI_FEATURE_SLOT_NDS 19 | 20 | MK_EXTERN_C_START 21 | 22 | //! @brief Sector offset integer type 23 | typedef u32 sec_t; 24 | 25 | typedef bool (* FN_MEDIUM_STARTUP)(void); 26 | typedef bool (* FN_MEDIUM_ISINSERTED)(void); 27 | typedef bool (* FN_MEDIUM_READSECTORS)(sec_t first_sector, sec_t num_sectors, void* buffer); 28 | typedef bool (* FN_MEDIUM_WRITESECTORS)(sec_t first_sector, sec_t num_sectors, const void* buffer); 29 | typedef bool (* FN_MEDIUM_CLEARSTATUS)(void); 30 | typedef bool (* FN_MEDIUM_SHUTDOWN)(void); 31 | 32 | //! @brief Generic disc interface struct 33 | typedef struct DISC_INTERFACE_STRUCT { 34 | u32 ioType; 35 | u32 features; 36 | 37 | FN_MEDIUM_STARTUP startup; 38 | FN_MEDIUM_ISINSERTED isInserted; 39 | FN_MEDIUM_READSECTORS readSectors; 40 | FN_MEDIUM_WRITESECTORS writeSectors; 41 | FN_MEDIUM_CLEARSTATUS clearStatus; 42 | FN_MEDIUM_SHUTDOWN shutdown; 43 | } DISC_INTERFACE; 44 | 45 | MK_EXTERN_C_END 46 | 47 | //! @} 48 | 49 | //! @} 50 | -------------------------------------------------------------------------------- /include/calico/dev/dldi.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "dldi_defs.h" 5 | #include "disc_io.h" 6 | 7 | /*! @addtogroup blkdev 8 | @{ 9 | */ 10 | 11 | MK_EXTERN_C_START 12 | 13 | //! @brief DLDI driver header 14 | typedef struct DldiHeader { 15 | u32 magic_num; 16 | char magic_str[DLDI_MAGIC_STRING_LEN]; 17 | u8 version_num; 18 | u8 driver_sz_log2; 19 | u8 fix_flags; 20 | u8 alloc_sz_log2; 21 | 22 | char iface_name[DLDI_FRIENDLY_NAME_LEN]; 23 | 24 | uptr dldi_start; 25 | uptr dldi_end; 26 | uptr glue_start; 27 | uptr glue_end; 28 | uptr got_start; 29 | uptr got_end; 30 | uptr bss_start; 31 | uptr bss_end; 32 | 33 | DISC_INTERFACE disc; 34 | } DldiHeader; 35 | 36 | #if defined(__NDS__) && defined(ARM9) 37 | //! @private 38 | bool dldiDumpInternal(void* buffer); 39 | #endif 40 | 41 | MK_EXTERN_C_END 42 | 43 | //! @} 44 | -------------------------------------------------------------------------------- /include/calico/dev/dldi_defs.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | /*! @addtogroup blkdev 6 | @{ 7 | */ 8 | 9 | /*! @name DLDI constants 10 | @{ 11 | */ 12 | 13 | #define DLDI_MAGIC_VAL 0xbf8da5ed 14 | #define DLDI_MAGIC_STRING " Chishm" 15 | 16 | #define DLDI_MAGIC_STRING_LEN 8 17 | #define DLDI_FRIENDLY_NAME_LEN 48 18 | 19 | #define DLDI_FIX_ALL (1U<<0) 20 | #define DLDI_FIX_GLUE (1U<<1) 21 | #define DLDI_FIX_GOT (1U<<2) 22 | #define DLDI_FIX_BSS (1U<<3) 23 | 24 | #define DLDI_FEATURE_CAN_READ (1U<<0) 25 | #define DLDI_FEATURE_CAN_WRITE (1U<<1) 26 | #define DLDI_FEATURE_SLOT_GBA (1U<<4) 27 | #define DLDI_FEATURE_SLOT_NDS (1U<<5) 28 | 29 | #define DLDI_SIZE_MAX DLDI_SIZE_16KB 30 | #define DLDI_SIZE_16KB 14 31 | #define DLDI_SIZE_8KB 13 32 | #define DLDI_SIZE_4KB 12 33 | #define DLDI_SIZE_2KB 11 34 | #define DLDI_SIZE_1KB 10 35 | 36 | #define DLDI_MAX_ALLOC_SZ (1U<state, initial_state, sizeof(ctx->state)); 30 | ctx->key[0] = key; 31 | ctx->key[1] = key>>1; 32 | ctx->key[2] = key<<1; 33 | } 34 | 35 | MK_INLINE void fuguNtrKeySchedule(FuguNtr* ctx, bool full_key, bool do_tweak) 36 | { 37 | if (do_tweak) { 38 | ctx->key[1] <<= 1; 39 | ctx->key[2] >>= 1; 40 | } 41 | fuguEncrypt(&ctx->state, &ctx->key[1]); 42 | fuguEncrypt(&ctx->state, &ctx->key[0]); 43 | fuguKeySchedule(&ctx->state, ctx->key, full_key ? 3 : 2); 44 | } 45 | 46 | MK_EXTERN_C_END 47 | -------------------------------------------------------------------------------- /include/calico/dev/mwl.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "mwl/types.h" 5 | #include "mwl/regs.h" 6 | #include "mwl/calib.h" 7 | #include "mwl/dev.h" 8 | #include "mwl/mlme.h" 9 | -------------------------------------------------------------------------------- /include/calico/dev/mwl/calib.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../../types.h" 5 | 6 | #define MWL_CALIB_NVRAM_OFFSET 0x02a 7 | #define MWL_CALIB_NVRAM_MAX_SZ (0x200-MWL_CALIB_NVRAM_OFFSET) 8 | 9 | MK_EXTERN_C_START 10 | 11 | typedef struct MwlCalibData { 12 | u16 crc16; 13 | u16 total_len; 14 | u8 unk_0x02e; 15 | u8 version; 16 | u8 unk_0x030[6]; 17 | u16 mac_addr[3]; 18 | u16 enabled_ch_mask; 19 | u16 op_flags; 20 | //---- 0x040 ---- 21 | u8 rf_type; // 2=DS; 3=DS Lite and up 22 | u8 rf_entry_bits; // 8 or 24 23 | u8 rf_num_entries; 24 | u8 rf_num_regs; 25 | u16 mac_reg_init[0x10]; 26 | u8 bb_reg_init[0x69]; 27 | u8 pad_0x0cd; 28 | //---- 0x0ce ---- 29 | u8 rf_entries[]; // rf_num_entries*rf_entry_bits/8 30 | 31 | // Afterwards: 32 | // union { 33 | // MwlChanCalibV2 v2; // at 0x0f2 (after 12 24-bit entries) 34 | // MwlChanCalibV3 v3; // at 0x0f7 (after 41 8-bit entries) 35 | // }; 36 | } MwlCalibData; 37 | 38 | typedef struct MwlChanRegV2 { 39 | u8 reg_0x05[3]; 40 | u8 reg_0x06[3]; 41 | } MwlChanRegV2; 42 | 43 | typedef struct MwlChanCalibV2 { 44 | MwlChanRegV2 rf_regs[14]; 45 | u8 bb_0x1e_values[14]; 46 | u8 rf_0x09_bits[14]; 47 | } MwlChanCalibV2; 48 | 49 | typedef struct MwlChanRegV3 { 50 | u8 index; 51 | u8 values[14]; 52 | } MwlChanRegV3; 53 | 54 | typedef struct MwlChanCalibV3 { 55 | u8 bb_num_regs; 56 | MwlChanRegV3 regs[]; 57 | // Actually: 58 | // MwlChanRegV3 bb_regs[bb_num_regs]; 59 | // MwlChanRegV3 rf_regs[rf_num_regs]; 60 | } MwlChanCalibV3; 61 | 62 | bool mwlCalibLoad(void); 63 | 64 | alignas(2) extern u8 g_mwlCalibData[MWL_CALIB_NVRAM_MAX_SZ]; 65 | 66 | MK_INLINE MwlCalibData* mwlGetCalibData(void) 67 | { 68 | return (MwlCalibData*)g_mwlCalibData; 69 | } 70 | 71 | MK_EXTERN_C_END 72 | -------------------------------------------------------------------------------- /include/calico/dev/mwl/dev.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "types.h" 5 | 6 | #define MWL_MAC_RAM 0x4000 7 | #define MWL_MAC_RAM_SZ (0x2000 - sizeof(MwlMacVars)) 8 | 9 | #if defined(__NDS__) && defined(ARM7) 10 | #include "../../nds/io.h" 11 | 12 | #define MWL_MAC_RAM_ADDR (MM_IO + IO_MITSUMI_WS0 + MWL_MAC_RAM) 13 | #define g_mwlMacVars ((volatile MwlMacVars*)(MWL_MAC_RAM_ADDR + MWL_MAC_RAM_SZ)) 14 | #endif 15 | 16 | MK_EXTERN_C_START 17 | 18 | typedef enum MwlTxEvent { 19 | MwlTxEvent_Dropped = 0, 20 | MwlTxEvent_Queued = 1, 21 | MwlTxEvent_Done = 2, 22 | MwlTxEvent_Error = 3, 23 | } MwlTxEvent; 24 | 25 | typedef struct MwlMacVars { 26 | u16 unk_0x00[8]; 27 | u16 unk_0x10; 28 | u16 unk_0x12; 29 | u16 unk_0x14; 30 | u16 unk_0x16; 31 | u16 unk_0x18; 32 | u16 unk_0x1a; 33 | u16 unk_0x1c; 34 | u16 unk_0x1e; 35 | u16 wep_keys[4][0x10]; 36 | } MwlMacVars; 37 | 38 | typedef void (*MwlTxCallback)(void* arg, MwlTxEvent evt, MwlDataTxHdr* hdr); 39 | 40 | void mwlDevWakeUp(void); 41 | void mwlDevReset(void); 42 | void mwlDevSetChannel(unsigned ch); 43 | void mwlDevSetMode(MwlMode mode); 44 | void mwlDevSetBssid(const void* bssid); 45 | void mwlDevSetSsid(const char* ssid, unsigned ssid_len); 46 | void mwlDevSetPreamble(bool isShort); 47 | void mwlDevSetAuth(WlanBssAuthType type, WlanAuthData const* data); 48 | void mwlDevShutdown(void); 49 | 50 | void mwlDevStart(void); 51 | void mwlDevStop(void); 52 | void mwlDevGracefulStop(void); 53 | 54 | bool mwlDevWlanToDix(NetBuf* pPacket); 55 | bool mwlDevDixToWlan(NetBuf* pPacket); 56 | 57 | void mwlDevTx(unsigned qid, NetBuf* pPacket, MwlTxCallback cb, void* arg); 58 | 59 | MK_EXTERN_C_END 60 | -------------------------------------------------------------------------------- /include/calico/dev/mwl/mlme.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "types.h" 5 | 6 | MK_EXTERN_C_START 7 | 8 | typedef struct MwlMlmeCallbacks { 9 | void (* onBssInfo)(WlanBssDesc* bssInfo, WlanBssExtra* bssExtra); 10 | u32 (* onScanEnd)(void); 11 | void (* onJoinEnd)(bool ok); 12 | void (* onAuthEnd)(unsigned status); 13 | void (* onAssocEnd)(unsigned status); 14 | void (* onStateLost)(MwlStatus new_class, unsigned reason); 15 | 16 | void (* maData)(NetBuf* pPacket); 17 | } MwlMlmeCallbacks; 18 | 19 | MwlMlmeCallbacks* mwlMlmeGetCallbacks(void); 20 | bool mwlMlmeScan(WlanBssScanFilter const* filter, unsigned ch_dwell_time); 21 | bool mwlMlmeJoin(WlanBssDesc const* bssInfo, unsigned timeout); 22 | bool mwlMlmeAuthenticate(unsigned timeout); 23 | bool mwlMlmeAssociate(unsigned timeout, bool fake_cck_rates); 24 | bool mwlMlmeDeauthenticate(void); 25 | 26 | MK_EXTERN_C_END 27 | -------------------------------------------------------------------------------- /include/calico/dev/mwl/types.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../../types.h" 5 | #include "../wlan.h" 6 | 7 | MK_EXTERN_C_START 8 | 9 | typedef enum MwlMode { 10 | MwlMode_Test = 0, 11 | MwlMode_LocalHost = 1, 12 | MwlMode_LocalGuest = 2, 13 | MwlMode_Infra = 3, 14 | } MwlMode; 15 | 16 | typedef enum MwlStatus { 17 | MwlStatus_Idle = 0, 18 | MwlStatus_Class1 = 1, // 802.11 Class 1 = Unauthenticated & Unassociated 19 | MwlStatus_Class2 = 2, // 802.11 Class 2 = Authenticated & Unassociated 20 | MwlStatus_Class3 = 3, // 802.11 Class 3 = Authenticated & Associated 21 | } MwlStatus; 22 | 23 | typedef enum MwlRxType { 24 | MwlRxType_IeeeMgmtOther = 0, 25 | MwlRxType_IeeeBeacon = 1, 26 | MwlRxType_IeeeCtrl = 5, 27 | MwlRxType_IeeeData = 8, 28 | MwlRxType_MpCmdFrame = 12, 29 | MwlRxType_MpEndFrame = 13, 30 | MwlRxType_MpReplyFrame = 14, 31 | MwlRxType_Null = 15, 32 | } MwlRxType; 33 | 34 | typedef struct MwlDataTxHdr { 35 | u16 status; 36 | u16 mp_aid_mask; 37 | u16 retry_count; 38 | u16 app_rate; 39 | u16 service_rate; 40 | u16 mpdu_len; 41 | } MwlDataTxHdr; 42 | 43 | typedef struct MwlDataRxHdr { 44 | u16 status; 45 | u16 next_frame_offset; 46 | u16 timestamp; 47 | u16 service_rate; 48 | u16 mpdu_len; 49 | u16 rssi; 50 | } MwlDataRxHdr; 51 | 52 | MK_CONSTEXPR u8 mwlDecodeRssi(u16 in) 53 | { 54 | unsigned ret = (in & 0xfc) >> 2; 55 | if (!(in & 2)) ret += 25; 56 | return ret; 57 | } 58 | 59 | MK_EXTERN_C_END 60 | -------------------------------------------------------------------------------- /include/calico/dev/sdio.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "tmio.h" 6 | 7 | #define SDIO_CMD_GO_IDLE (TMIO_CMD_INDEX(0) | TMIO_CMD_RESP_NONE) 8 | #define SDIO_CMD_GET_RELATIVE_ADDR (TMIO_CMD_INDEX(3) | TMIO_CMD_RESP_48) 9 | #define SDIO_CMD_SEND_OP_COND (TMIO_CMD_INDEX(5) | TMIO_CMD_RESP_48_NOCRC) 10 | #define SDIO_CMD_SELECT_CARD (TMIO_CMD_INDEX(7) | TMIO_CMD_RESP_48_BUSY) 11 | #define SDIO_CMD_RW_DIRECT (TMIO_CMD_INDEX(52) | TMIO_CMD_RESP_48) 12 | #define SDIO_CMD_RW_EXTENDED (TMIO_CMD_INDEX(53) | TMIO_CMD_RESP_48 | TMIO_CMD_TX | TMIO_CMD_TX_SDIO) 13 | 14 | #define SDIO_RW_DIRECT_DATA(_x) ((_x)&0xff) 15 | #define SDIO_RW_DIRECT_ADDR(_x) (((_x)&0x1ffff)<<9) 16 | #define SDIO_RW_DIRECT_WR_RD (1U<<27) 17 | #define SDIO_RW_DIRECT_FUNC(_x) (((_x)&7)<<28) 18 | #define SDIO_RW_DIRECT_READ (0U<<31) 19 | #define SDIO_RW_DIRECT_WRITE (1U<<31) 20 | 21 | #define SDIO_RW_EXTENDED_COUNT(_x) ((_x)&0x1ff) 22 | #define SDIO_RW_EXTENDED_ADDR(_x) (((_x)&0x1ffff)<<9) 23 | #define SDIO_RW_EXTENDED_FIXED (0U<<26) 24 | #define SDIO_RW_EXTENDED_INCR (1U<<26) 25 | #define SDIO_RW_EXTENDED_BYTES (0U<<27) 26 | #define SDIO_RW_EXTENDED_BLOCKS (1U<<27) 27 | #define SDIO_RW_EXTENDED_FUNC(_x) (((_x)&7)<<28) 28 | #define SDIO_RW_EXTENDED_READ (0U<<31) 29 | #define SDIO_RW_EXTENDED_WRITE (1U<<31) 30 | 31 | #define SDIO_BLOCK_SZ 128 32 | 33 | MK_EXTERN_C_START 34 | 35 | typedef struct SdioManfid { 36 | u16 code; 37 | u16 id; 38 | } SdioManfid; 39 | 40 | typedef struct SdioCard { 41 | TmioCtl* ctl; 42 | TmioPort port; 43 | 44 | void (* dma_cb)(TmioCtl* ctl, TmioTx* tx); 45 | 46 | u16 rca; 47 | SdioManfid manfid; 48 | u8 revision; 49 | u8 caps; 50 | } SdioCard; 51 | 52 | bool sdioCardInit(SdioCard* card, TmioCtl* ctl, unsigned port); 53 | bool sdioCardSetIrqEnable(SdioCard* card, unsigned func, bool enable); 54 | bool sdioCardReadDirect(SdioCard* card, unsigned func, unsigned addr, void* out, size_t size); 55 | bool sdioCardWriteDirect(SdioCard* card, unsigned func, unsigned addr, const void* in, size_t size); 56 | bool sdioCardReadExtended(SdioCard* card, unsigned func, unsigned addr, void* out, size_t size); 57 | bool sdioCardWriteExtended(SdioCard* card, unsigned func, unsigned addr, const void* in, size_t size); 58 | 59 | MK_EXTERN_C_END 60 | -------------------------------------------------------------------------------- /include/calico/dev/sdmmc.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "tmio.h" 6 | 7 | #define SDMMC_CMD_GO_IDLE (TMIO_CMD_INDEX(0) | TMIO_CMD_RESP_NONE) 8 | #define SDMMC_CMD_SEND_OP_COND (TMIO_CMD_INDEX(1) | TMIO_CMD_RESP_48_NOCRC) 9 | #define SDMMC_CMD_ALL_GET_CID (TMIO_CMD_INDEX(2) | TMIO_CMD_RESP_136) 10 | #define SDMMC_CMD_MMC_SET_RELATIVE_ADDR (TMIO_CMD_INDEX(3) | TMIO_CMD_RESP_48) 11 | #define SDMMC_CMD_SD_GET_RELATIVE_ADDR (TMIO_CMD_INDEX(3) | TMIO_CMD_RESP_48) 12 | #define SDMMC_CMD_MMC_SWITCH (TMIO_CMD_INDEX(6) | TMIO_CMD_RESP_48_BUSY) 13 | #define SDMMC_CMD_SELECT_CARD (TMIO_CMD_INDEX(7) | TMIO_CMD_RESP_48_BUSY) 14 | #define SDMMC_CMD_SET_IF_COND (TMIO_CMD_INDEX(8) | TMIO_CMD_RESP_48) 15 | #define SDMMC_CMD_GET_CSD (TMIO_CMD_INDEX(9) | TMIO_CMD_RESP_136) 16 | #define SDMMC_CMD_GET_STATUS (TMIO_CMD_INDEX(13) | TMIO_CMD_RESP_48) 17 | #define SDMMC_CMD_SET_BLOCKLEN (TMIO_CMD_INDEX(16) | TMIO_CMD_RESP_48) 18 | #define SDMMC_CMD_READ_MULTIPLE_BLOCK (TMIO_CMD_INDEX(18) | TMIO_CMD_RESP_48 | TMIO_CMD_TX | TMIO_CMD_TX_READ | TMIO_CMD_TX_MULTI) 19 | #define SDMMC_CMD_WRITE_MULTIPLE_BLOCK (TMIO_CMD_INDEX(25) | TMIO_CMD_RESP_48 | TMIO_CMD_TX | TMIO_CMD_TX_WRITE | TMIO_CMD_TX_MULTI) 20 | #define SDMMC_CMD_APP_CMD (TMIO_CMD_INDEX(55) | TMIO_CMD_RESP_48) 21 | 22 | #define SDMMC_ACMD_SET_BUS_WIDTH (TMIO_CMD_INDEX(6) | TMIO_CMD_TYPE_ACMD | TMIO_CMD_RESP_48) 23 | #define SDMMC_ACMD_SEND_OP_COND (TMIO_CMD_INDEX(41) | TMIO_CMD_TYPE_ACMD | TMIO_CMD_RESP_48_NOCRC) 24 | #define SDMMC_ACMD_SET_CLR_CARD_DETECT (TMIO_CMD_INDEX(42) | TMIO_CMD_TYPE_ACMD | TMIO_CMD_RESP_48) 25 | #define SDMMC_ACMD_GET_SCR (TMIO_CMD_INDEX(51) | TMIO_CMD_TYPE_ACMD | TMIO_CMD_RESP_48 | TMIO_CMD_TX | TMIO_CMD_TX_READ) 26 | 27 | #define SDMMC_CMD_MMC_SWITCH_ARG(_access,_index,_value) \ 28 | ((((_value)&0xff)<<8) | (((_index)&0xff)<<16) | (((_access)&3)<<24)) 29 | 30 | #define SDMMC_SECTOR_SZ 512 31 | 32 | MK_EXTERN_C_START 33 | 34 | typedef enum SdmmcType { 35 | SdmmcType_Invalid = 0, 36 | SdmmcType_MMC, 37 | SdmmcType_SDv1, 38 | SdmmcType_SDv2_SDSC, 39 | SdmmcType_SDv2_SDHC, 40 | } SdmmcType; 41 | 42 | typedef struct SdmmcCard { 43 | TmioCtl* ctl; 44 | TmioPort port; 45 | 46 | u16 rca; 47 | SdmmcType type; 48 | 49 | TmioResp cid; 50 | TmioResp csd; 51 | u32 ocr; 52 | u32 scr_hi; 53 | u32 num_sectors; 54 | } SdmmcCard; 55 | 56 | typedef struct SdmmcFrozenState { 57 | TmioResp cid; 58 | TmioResp csd; 59 | u32 ocr; 60 | u32 scr_hi_be; 61 | u32 scr_lo_be; 62 | u16 rca; 63 | u16 is_mmc; 64 | u16 is_sdhc; 65 | u16 is_sd; 66 | u32 unknown; 67 | u32 csr; 68 | u16 tmio_clkctl; 69 | u16 tmio_option; 70 | u16 is_ejected; 71 | u16 tmio_port; 72 | } SdmmcFrozenState; 73 | 74 | bool sdmmcCardInit(SdmmcCard* card, TmioCtl* ctl, unsigned port, bool ismmc); 75 | bool sdmmcCardInitFromState(SdmmcCard* card, TmioCtl* ctl, SdmmcFrozenState const* state); 76 | void sdmmcCardDumpState(SdmmcCard* card, SdmmcFrozenState* state); 77 | 78 | bool sdmmcCardReadSectors(SdmmcCard* card, TmioTx* tx, u32 sector_id, u32 num_sectors); 79 | bool sdmmcCardWriteSectors(SdmmcCard* card, TmioTx* tx, u32 sector_id, u32 num_sectors); 80 | 81 | MK_EXTERN_C_END 82 | -------------------------------------------------------------------------------- /include/calico/dev/tmio.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "../system/mailbox.h" 6 | #include "../system/sysclock.h" 7 | #include "tmio_regs.h" 8 | 9 | MK_EXTERN_C_START 10 | 11 | typedef struct TmioPort TmioPort; 12 | typedef struct TmioResp TmioResp; 13 | typedef struct TmioCtl TmioCtl; 14 | typedef struct TmioTx TmioTx; 15 | 16 | typedef void (* TmioInsRemHandler)(TmioCtl* ctl, unsigned port, bool inserted); 17 | typedef void (* TmioCardIrqHandler)(TmioCtl* ctl, unsigned port); 18 | 19 | struct TmioPort { 20 | u16 clock; 21 | u8 num; 22 | u8 width; 23 | }; 24 | 25 | struct TmioResp { 26 | u32 value[4]; 27 | }; 28 | 29 | 30 | struct TmioCtl { 31 | uptr reg_base; 32 | uptr fifo_base; 33 | 34 | TmioPort cur_port; 35 | TmioTx* cur_tx; 36 | 37 | Mailbox mbox; 38 | 39 | u16 num_pending_blocks; 40 | bool cardirq_deferred; 41 | bool cardirq_ack_deferred; 42 | 43 | struct { 44 | TmioInsRemHandler insrem; 45 | TmioCardIrqHandler cardirq; 46 | void* user; 47 | } port_isr[1]; 48 | }; 49 | 50 | struct TmioTx { 51 | u32 status; 52 | 53 | TmioPort port; 54 | union { 55 | u32 arg; 56 | TmioResp resp; 57 | }; 58 | 59 | u16 type; 60 | u16 block_size; 61 | u16 num_blocks; 62 | u16 _pad; 63 | 64 | void (* callback)(TmioCtl* ctl, TmioTx* tx); 65 | void (* xfer_isr)(TmioCtl* ctl, TmioTx* tx); 66 | void* user; 67 | }; 68 | 69 | MK_CONSTEXPR u16 tmioSelectClock(unsigned freq) 70 | { 71 | if (freq < (SYSTEM_CLOCK>>8)) // HCLK/256 72 | return 0x80; // HCLK/512 73 | if (freq < (SYSTEM_CLOCK>>7)) // HCLK/128 74 | return 0x40; // HCLK/256 75 | if (freq < (SYSTEM_CLOCK>>6)) // HCLK/64 76 | return 0x20; // HCLK/128 77 | if (freq < (SYSTEM_CLOCK>>5)) // HCLK/32 78 | return 0x10; // HCLK/64 79 | if (freq < (SYSTEM_CLOCK>>4)) // HCLK/16 80 | return 0x08; // HCLK/32 81 | if (freq < (SYSTEM_CLOCK>>3)) // HCLK/8 82 | return 0x04; // HCLK/16 83 | if (freq < (SYSTEM_CLOCK>>2)) // HCLK/4 84 | return 0x02; // HCLK/8 85 | if (freq < (SYSTEM_CLOCK>>1)) // HCLK/2 86 | return 0x01; // HCLK/4 87 | return 0x00; // HCLK/2 88 | } 89 | 90 | MK_INLINE void* tmioGetPortUserData(TmioCtl* ctl, unsigned port) 91 | { 92 | return ctl->port_isr[port].user; 93 | } 94 | 95 | MK_INLINE void tmioSetPortUserData(TmioCtl* ctl, unsigned port, void* data) 96 | { 97 | ctl->port_isr[port].user = data; 98 | } 99 | 100 | bool tmioInit(TmioCtl* ctl, uptr reg_base, uptr fifo_base, u32* mbox_slots, unsigned num_mbox_slots); 101 | void tmioSetPortInsRemHandler(TmioCtl* ctl, unsigned port, TmioInsRemHandler isr); 102 | void tmioSetPortCardIrqHandler(TmioCtl* ctl, unsigned port, TmioCardIrqHandler isr); 103 | void tmioAckPortCardIrq(TmioCtl* ctl, unsigned port); 104 | 105 | void tmioIrqHandler(TmioCtl* ctl); 106 | int tmioThreadMain(TmioCtl* ctl); 107 | void tmioThreadCancel(TmioCtl* ctl); 108 | 109 | bool tmioTransact(TmioCtl* ctl, TmioTx* tx); 110 | 111 | void tmioXferRecvByCpu(TmioCtl* ctl, TmioTx* tx); 112 | void tmioXferSendByCpu(TmioCtl* ctl, TmioTx* tx); 113 | 114 | unsigned tmioDecodeTranSpeed(u8 tran_speed); 115 | 116 | MK_EXTERN_C_END 117 | -------------------------------------------------------------------------------- /include/calico/gba/bios.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | // Parameters for svcRegisterRamReset 7 | #define SVC_CLEAR_EWRAM (1<<0) 8 | #define SVC_CLEAR_IWRAM (1<<1) 9 | #define SVC_CLEAR_PALRAM (1<<2) 10 | #define SVC_CLEAR_VRAM (1<<3) 11 | #define SVC_CLEAR_OBJRAM (1<<4) 12 | #define SVC_CLEAR_SERIAL (1<<5) 13 | #define SVC_CLEAR_SOUND (1<<6) 14 | #define SVC_CLEAR_IO (1<<7) 15 | #define SVC_CLEAR_ALL 0xff 16 | 17 | // Parameters for svcCpuSet/svcCpuFastSet (FastSet only supports 32-bit mode) 18 | #define SVC_SET_SIZE_16(_sz) (((_sz)/2) & 0x1fffff) 19 | #define SVC_SET_SIZE_32(_sz) (((_sz)/4) & 0x1fffff) 20 | #define SVC_SET_FIXED (1<<24) 21 | #define SVC_SET_UNIT_16 (0<<26) 22 | #define SVC_SET_UNIT_32 (1<<26) 23 | 24 | MK_EXTERN_C_START 25 | 26 | /* TODO: ABI. This is intended to be returned as r0/r1 27 | typedef struct SvcDivResult { 28 | s32 quotient; 29 | s32 remainder; 30 | } SvcDivResult; 31 | */ 32 | 33 | typedef struct SvcAffineParams { 34 | s16 scale_x; 35 | s16 scale_y; 36 | u16 angle; 37 | } SvcAffineParams; 38 | 39 | typedef struct SvcAffineData { 40 | s16 pa; 41 | s16 pb; 42 | s16 pc; 43 | s16 pd; 44 | } SvcAffineData; 45 | 46 | typedef struct SvcBgAffineParams { 47 | s32 orig_center_x; 48 | s32 orig_center_y; 49 | s16 center_x; 50 | s16 center_y; 51 | SvcAffineParams params; 52 | } SvcBgAffineParams; 53 | 54 | typedef struct SvcBgAffineData { 55 | SvcAffineData data; 56 | s32 start_x; 57 | s32 start_y; 58 | } SvcBgAffineData; 59 | 60 | typedef struct SvcBitUnpackParams { 61 | u16 in_length_bytes; 62 | u8 in_width_bits; 63 | u8 out_width_bits; 64 | u32 data_offset : 31; 65 | u32 zero_data_flag : 1; 66 | } SvcBitUnpackParams; 67 | 68 | void svcSoftReset(void) MK_NORETURN; 69 | void svcRegisterRamReset(u32 flags); 70 | void svcHalt(void); 71 | void svcStop(void); 72 | void svcIntrWait(bool waitNext, u32 mask); 73 | void svcVBlankIntrWait(void); 74 | //SvcDivResult svcDiv(s32 num, s32 den); 75 | //SvcDivResult svcDivArm(s32 den, s32 num); 76 | u16 svcSqrt(u32 num); 77 | s16 svcArcTan(s16 value); 78 | u16 svcArcTan2(s32 x, s32 y); 79 | void svcCpuSet(const void* src, void* dst, u32 mode); 80 | void svcCpuFastSet(const void* src, void* dst, u32 mode); 81 | u32 svcGetBiosChecksum(void); 82 | void svcBgAffineSet(const SvcBgAffineParams* in, SvcBgAffineData* out, u32 count); 83 | void svcObjAffineSet(const SvcAffineParams* in, SvcAffineData* out, u32 count, u32 stride); 84 | void svcBitUnpack(const void* src, void* dst, SvcBitUnpackParams const* params); 85 | void svcLZ77UncompWram(const void* src, void* dst); 86 | void svcLZ77UncompVram(const void* src, void* dst); 87 | void svcHuffUncomp(const void* src, void* dst); 88 | void svcRLUncompWram(const void* src, void* dst); 89 | void svcRLUncompVram(const void* src, void* dst); 90 | void svcDiff8bitUnfilterWram(const void* src, void* dst); 91 | void svcDiff8bitUnfilterVram(const void* src, void* dst); 92 | void svcDiff16bitUnfilter(const void* src, void* dst); 93 | void svcSoundBias(bool enable); 94 | u32 svcMidiKey2Freq(const void* wave, u8 key, u8 finetune); 95 | u32 svcMultiBoot(const void* param, u32 mode); // todo: add types 96 | void svcHardReset(void) MK_NORETURN; 97 | 98 | MK_EXTERN_C_END 99 | -------------------------------------------------------------------------------- /include/calico/gba/io.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__GBA__) 5 | #error "This header file is only for GBA" 6 | #endif 7 | 8 | #include "mm.h" 9 | 10 | // Video engine 11 | #define IO_DISPCNT 0x000 12 | #define IO_DISPSTAT 0x004 13 | #define IO_VCOUNT 0x006 14 | #define IO_BG0CNT 0x008 15 | #define IO_BG1CNT 0x00a 16 | #define IO_BG2CNT 0x00c 17 | #define IO_BG3CNT 0x00e 18 | #define IO_BG0HOFS 0x010 19 | #define IO_BG0VOFS 0x012 20 | #define IO_BG1HOFS 0x014 21 | #define IO_BG1VOFS 0x016 22 | #define IO_BG2HOFS 0x018 23 | #define IO_BG2VOFS 0x01a 24 | #define IO_BG3HOFS 0x01c 25 | #define IO_BG3VOFS 0x01e 26 | #define IO_BG2PA 0x020 27 | #define IO_BG2PB 0x022 28 | #define IO_BG2PC 0x024 29 | #define IO_BG2PD 0x026 30 | #define IO_BG2X 0x028 31 | #define IO_BG2Y 0x02c 32 | #define IO_BG3PA 0x030 33 | #define IO_BG3PB 0x032 34 | #define IO_BG3PC 0x034 35 | #define IO_BG3PD 0x036 36 | #define IO_BG3X 0x038 37 | #define IO_BG3Y 0x03c 38 | #define IO_WIN0H 0x040 39 | #define IO_WIN1H 0x042 40 | #define IO_WIN0V 0x044 41 | #define IO_WIN1V 0x046 42 | #define IO_WININ 0x048 43 | #define IO_WINOUT 0x04a 44 | #define IO_MOSAIC 0x04c 45 | #define IO_BLDCNT 0x050 46 | #define IO_BLDALPHA 0x052 47 | #define IO_BLDY 0x054 48 | 49 | #define IO_BGxCNT(_x) (IO_BG0CNT + (IO_BG1CNT -IO_BG0CNT )*(_x)) 50 | #define IO_BGxHOFS(_x) (IO_BG0HOFS + (IO_BG1HOFS-IO_BG0HOFS)*(_x)) 51 | #define IO_BGxVOFS(_x) (IO_BG0VOFS + (IO_BG1VOFS-IO_BG0VOFS)*(_x)) 52 | #define IO_WINxH(_x) (IO_WIN0H + (IO_WIN1H -IO_WIN0H )*(_x)) 53 | #define IO_WINxV(_x) (IO_WIN0V + (IO_WIN1V -IO_WIN0V )*(_x)) 54 | 55 | // DMA 56 | #define IO_DMAxSAD(_x) (0x0b0 + 0xc*(_x)) 57 | #define IO_DMAxDAD(_x) (0x0b4 + 0xc*(_x)) 58 | #define IO_DMAxCNT(_x) (0x0b8 + 0xc*(_x)) 59 | 60 | // Timer 61 | #define IO_TMxCNT(_x) (0x100 + 0x4*(_x)) 62 | 63 | // Keypad input 64 | #define IO_KEYINPUT 0x130 65 | #define IO_KEYCNT 0x132 66 | 67 | // Interrupt/system control 68 | #define IO_IE 0x200 69 | #define IO_IF 0x202 70 | #define IO_WAITCNT 0x204 71 | #define IO_IME 0x208 72 | -------------------------------------------------------------------------------- /include/calico/gba/irq.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__GBA__) 5 | #error "This header file is only for GBA" 6 | #endif 7 | 8 | #include "../types.h" 9 | #include "../arm/common.h" 10 | #include "io.h" 11 | 12 | #define REG_IE MK_REG(u16, IO_IE) 13 | #define REG_IF MK_REG(u16, IO_IF) 14 | #define REG_IME MK_REG(u16, IO_IME) 15 | 16 | #define IRQ_VBLANK (1U << 0) 17 | #define IRQ_HBLANK (1U << 1) 18 | #define IRQ_VCOUNT (1U << 2) 19 | #define IRQ_TIMER0 (1U << 3) 20 | #define IRQ_TIMER1 (1U << 4) 21 | #define IRQ_TIMER2 (1U << 5) 22 | #define IRQ_TIMER3 (1U << 6) 23 | #define IRQ_SERIAL (1U << 7) 24 | #define IRQ_DMA0 (1U << 8) 25 | #define IRQ_DMA1 (1U << 9) 26 | #define IRQ_DMA2 (1U << 10) 27 | #define IRQ_DMA3 (1U << 11) 28 | #define IRQ_KEYPAD (1U << 12) 29 | #define IRQ_CART (1U << 13) 30 | 31 | #define IRQ_TIMER(_x) (1U << (3+(_x))) 32 | #define IRQ_DMA(_x) (1U << (8+(_x))) 33 | 34 | #define MK_IRQ_NUM_HANDLERS 16 35 | 36 | MK_EXTERN_C_START 37 | 38 | typedef unsigned IrqState; 39 | typedef u16 IrqMask; 40 | 41 | MK_INLINE IrqState irqLock(void) 42 | { 43 | armCompilerBarrier(); 44 | IrqState saved = REG_IME; 45 | REG_IME = 0; 46 | armCompilerBarrier(); 47 | return saved; 48 | } 49 | 50 | MK_INLINE void irqUnlock(IrqState state) 51 | { 52 | armCompilerBarrier(); 53 | REG_IME = state; 54 | armCompilerBarrier(); 55 | } 56 | 57 | MK_EXTERN_C_END 58 | -------------------------------------------------------------------------------- /include/calico/gba/keypad.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | #if defined(__GBA__) 7 | #include "io.h" 8 | #elif defined(__NDS__) 9 | #include "../nds/io.h" 10 | #ifdef ARM7 11 | #include "../nds/arm7/gpio.h" 12 | #endif 13 | #else 14 | #error "This header file is only for GBA and NDS" 15 | #endif 16 | 17 | /*! @addtogroup keypad 18 | @{ 19 | */ 20 | 21 | /*! @name Keypad memory mapped I/O 22 | @{ 23 | */ 24 | 25 | #define REG_KEYINPUT MK_REG(u16, IO_KEYINPUT) 26 | #define REG_KEYCNT MK_REG(u16, IO_KEYCNT) 27 | 28 | #define KEYCNT_IRQ_ENABLE (1U<<14) 29 | #define KEYCNT_IRQ_OR (0U<<15) 30 | #define KEYCNT_IRQ_AND (1U<<15) 31 | 32 | //! @} 33 | 34 | /*! @name Keypad button bits 35 | @{ 36 | */ 37 | 38 | #define KEY_A (1U<<0) 39 | #define KEY_B (1U<<1) 40 | #define KEY_SELECT (1U<<2) 41 | #define KEY_START (1U<<3) 42 | #define KEY_RIGHT (1U<<4) 43 | #define KEY_LEFT (1U<<5) 44 | #define KEY_UP (1U<<6) 45 | #define KEY_DOWN (1U<<7) 46 | #define KEY_R (1U<<8) 47 | #define KEY_L (1U<<9) 48 | #define KEY_MASK 0x03ff 49 | 50 | #if defined(__NDS__) 51 | #define KEY_X (1U<<10) 52 | #define KEY_Y (1U<<11) 53 | #define KEY_HINGE (1U<<12) 54 | #define KEY_DEBUG (1U<<13) 55 | #define KEY_MASK_EXT 0x3c00 56 | #endif 57 | 58 | //! @} 59 | 60 | MK_EXTERN_C_START 61 | 62 | //! Keypad state object 63 | typedef struct Keypad { 64 | u16 cur; //!< Currently held keys 65 | u16 old; //!< Previously held heys 66 | } Keypad; 67 | 68 | //! @private 69 | MK_INLINE unsigned keypadGetInState(void) 70 | { 71 | return ~REG_KEYINPUT & KEY_MASK; 72 | } 73 | 74 | #if defined(__GBA__) 75 | 76 | //! Retrieves the current state of all keys 77 | MK_INLINE unsigned keypadGetState(void) 78 | { 79 | return keypadGetInState(); 80 | } 81 | 82 | #elif defined(__NDS__) && defined(ARM7) 83 | 84 | //! @private 85 | MK_INLINE unsigned keypadGetExtState(void) 86 | { 87 | unsigned state = 0; 88 | unsigned rcnt_ext = REG_RCNT_EXT; 89 | state |= (~rcnt_ext & (RCNT_EXT_X|RCNT_EXT_Y|RCNT_EXT_DEBUG)) * KEY_X; 90 | state |= ( rcnt_ext & RCNT_EXT_HINGE) ? KEY_HINGE : 0U; 91 | return state; 92 | } 93 | 94 | //! Retrieves the current state of all keys 95 | MK_INLINE unsigned keypadGetState(void) 96 | { 97 | return keypadGetInState() | keypadGetExtState(); 98 | } 99 | 100 | //! Starts sharing extended key state with the ARM9 101 | void keypadStartExtServer(void); 102 | 103 | #else 104 | 105 | //! Retrieves the current state of all keys 106 | unsigned keypadGetState(void); 107 | 108 | #endif 109 | 110 | //! Updates the state of Keypad object @p k 111 | MK_INLINE void keypadRead(Keypad* k) 112 | { 113 | k->old = k->cur; 114 | k->cur = keypadGetState(); 115 | } 116 | 117 | //! Retrieves the bitmask of held keys in @p k 118 | MK_INLINE u16 keypadHeld(Keypad const* k) 119 | { 120 | return k->cur; 121 | } 122 | 123 | //! Retrieves the bitmask of recently pressed keys in @p k 124 | MK_INLINE u16 keypadDown(Keypad const* k) 125 | { 126 | return ~k->old & k->cur; 127 | } 128 | 129 | //! Retrieves the bitmask of recently released keys in @p k 130 | MK_INLINE u16 keypadUp(Keypad const* k) 131 | { 132 | return k->old & ~k->cur; 133 | } 134 | 135 | MK_EXTERN_C_END 136 | 137 | //! @} 138 | -------------------------------------------------------------------------------- /include/calico/gba/mm.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__GBA__) 5 | #error "This header file is only for GBA" 6 | #endif 7 | 8 | #define MM_BIOS 0x0000000 // 32-bit bus 9 | #define MM_BIOS_SZ 0x4000 // 16kb 10 | 11 | #define MM_EWRAM 0x2000000 // 16-bit bus 12 | #define MM_EWRAM_SZ 0x40000 // 256kb 13 | 14 | #define MM_IWRAM 0x3000000 // 32-bit bus 15 | #define MM_IWRAM_SZ 0x8000 // 32kb 16 | 17 | #define MM_IO 0x4000000 // 32-bit bus 18 | #define MM_IO_SZ 0x400 // 1kb 19 | 20 | #define MM_PALRAM 0x5000000 // 16-bit bus 21 | #define MM_PALRAM_SZ 0x400 // 1kb 22 | 23 | #define MM_VRAM 0x6000000 // 16-bit bus 24 | #define MM_VRAM_SZ 0x18000 // 96kb 25 | 26 | #define MM_OBJRAM 0x7000000 // 32-bit bus 27 | #define MM_OBJRAM_SZ 0x400 // 1kb 28 | 29 | #define MM_CARTROM0 0x8000000 // 16-bit bus 30 | #define MM_CARTROM0_SZ 0x2000000 // 32mb 31 | 32 | #define MM_CARTROM1 0xa000000 // 16-bit bus 33 | #define MM_CARTROM1_SZ 0x2000000 // 32mb 34 | 35 | #define MM_CARTROM2 0xc000000 // 16-bit bus 36 | #define MM_CARTROM2_SZ 0x2000000 // 32mb 37 | 38 | #define MM_CARTRAM 0xe000000 // 8-bit bus 39 | #define MM_CARTRAM_SZ 0x10000 // 64kb 40 | -------------------------------------------------------------------------------- /include/calico/gba/timer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "../system/sysclock.h" 6 | 7 | #if defined(__GBA__) 8 | #include "io.h" 9 | #elif defined(__NDS__) 10 | #include "../nds/io.h" 11 | #else 12 | #error "This header file is only for GBA and NDS" 13 | #endif 14 | 15 | /*! @addtogroup timer 16 | @note Hardware timers 2 and 3 are reserved by calico's @ref tick subsystem. 17 | Consider using @ref tick instead of hardware timers directly to conserve 18 | hardware resources if you don't need extremely low latency. 19 | @{ 20 | */ 21 | 22 | //! Base frequency used by hardware timers 23 | #define TIMER_BASE_FREQ SYSTEM_CLOCK 24 | 25 | /*! @name Hardware timer registers 26 | @{ 27 | */ 28 | 29 | #define REG_TMxCNT(_x) MK_REG(u32, IO_TMxCNT(_x)) 30 | #define REG_TMxCNT_L(_x) MK_REG(u16, IO_TMxCNT(_x)+0) 31 | #define REG_TMxCNT_H(_x) MK_REG(u16, IO_TMxCNT(_x)+2) 32 | 33 | #define TIMER_PRESCALER_1 (0<<0) 34 | #define TIMER_PRESCALER_64 (1<<0) 35 | #define TIMER_PRESCALER_256 (2<<0) 36 | #define TIMER_PRESCALER_1024 (3<<0) 37 | #define TIMER_CASCADE (1<<2) 38 | #define TIMER_ENABLE_IRQ (1<<6) 39 | #define TIMER_ENABLE (1<<7) 40 | 41 | //! @} 42 | 43 | MK_EXTERN_C_START 44 | 45 | //! Calculates the period of a timer with the given @p prescaler (TIMER_PRESCALER_\*) and @p freq (in Hz) 46 | MK_CONSTEXPR unsigned timerCalcPeriod(unsigned prescaler, unsigned freq) 47 | { 48 | unsigned basefreq = TIMER_BASE_FREQ; 49 | if (prescaler) basefreq >>= prescaler*2 + 4; 50 | return (basefreq + freq/2) / freq; 51 | } 52 | 53 | //! Calculates the reload value of a timer with the given @p prescaler and @p freq (in Hz) 54 | MK_CONSTEXPR u16 timerCalcReload(unsigned prescaler, unsigned freq) 55 | { 56 | unsigned period = timerCalcPeriod(prescaler, freq); 57 | return period < 0x10000 ? (0x10000-period) : 0; 58 | } 59 | 60 | //! Stops hardware timer @p id 61 | MK_INLINE void timerEnd(unsigned id) 62 | { 63 | REG_TMxCNT_H(id) = 0; 64 | } 65 | 66 | /*! @brief Configures and starts hardware timer @p id 67 | @param[in] prescaler Prescaler value to use (see TIMER_PRESCALER_\*) 68 | @param[in] freq Timer frequency in Hz 69 | @param[in] wantIrq Pass true to enable interrupt generation (see @ref IRQ_TIMER) 70 | */ 71 | MK_INLINE void timerBegin(unsigned id, unsigned prescaler, unsigned freq, bool wantIrq) 72 | { 73 | timerEnd(id); 74 | REG_TMxCNT_L(id) = timerCalcReload(prescaler, freq); 75 | REG_TMxCNT_H(id) = prescaler | TIMER_ENABLE | (wantIrq ? TIMER_ENABLE_IRQ : 0); 76 | } 77 | 78 | //! Configures hardware timer @p id in cascade mode 79 | MK_INLINE void timerBeginCascade(unsigned id, bool wantIrq) 80 | { 81 | timerEnd(id); 82 | REG_TMxCNT_L(id) = 0; 83 | REG_TMxCNT_H(id) = TIMER_CASCADE | TIMER_ENABLE | (wantIrq ? TIMER_ENABLE_IRQ : 0); 84 | } 85 | 86 | //! Reads the current 16-bit counter of hardware timer @p id 87 | MK_INLINE u16 timerRead(unsigned id) 88 | { 89 | return REG_TMxCNT_L(id); 90 | } 91 | 92 | MK_EXTERN_C_END 93 | 94 | //! @} 95 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/codec.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "spi.h" 10 | #include "tsc.h" 11 | 12 | MK_EXTERN_C_START 13 | 14 | typedef enum CdcPage { 15 | CdcPage_Control = 0x00, 16 | CdcPage_Sound = 0x01, 17 | CdcPage_TscControl = 0x03, 18 | CdcPage_AdcCoeffs = 0x04, // 0x04..0x05 19 | CdcPage_DacCoeffsA = 0x08, // 0x08..0x0b 20 | CdcPage_DacCoeffsB = 0x0c, // 0x0c..0x0f 21 | CdcPage_AdcInstr = 0x20, // 0x20..0x2b 22 | CdcPage_DacInstr = 0x40, // 0x40..0x5f 23 | CdcPage_Dummy = 0x63, 24 | CdcPage_TscData = 0xfc, 25 | CdcPage_DsMode = 0xff, // Nintendo custom 26 | } CdcPage; 27 | 28 | typedef enum CdcTscCtrlReg { 29 | CdcTscCtrlReg_SarAdcCtrl = 0x02, 30 | CdcTscCtrlReg_SarAdcConvMode = 0x03, 31 | CdcTscCtrlReg_PrechargeSense = 0x04, 32 | CdcTscCtrlReg_PanelVoltStblz = 0x05, 33 | CdcTscCtrlReg_Status0 = 0x09, 34 | CdcTscCtrlReg_BufferMode = 0x0e, // Normally 0x0d. Not exactly following datasheet 35 | CdcTscCtrlReg_ScanModeTimer = 0x0f, 36 | CdcTscCtrlReg_DebounceTimer = 0x12, 37 | CdcTscCtrlReg_DacDataPath = 0x3f, 38 | CdcTscCtrlReg_AdcDigitalMic = 0x51, 39 | CdcTscCtrlReg_AdcDigitalVolFine = 0x52, 40 | } CdcTscCtrlReg; 41 | 42 | typedef enum CdcTscSndReg { 43 | CdcTscSndReg_MicBias = 0x2e, 44 | CdcTscSndReg_MicPga = 0x2f, 45 | } CdcTscSndReg; 46 | 47 | MK_INLINE bool cdcIsTwlMode(void) 48 | { 49 | extern bool g_cdcIsTwlMode; 50 | return g_cdcIsTwlMode; 51 | } 52 | 53 | u8 cdcReadReg(CdcPage page, unsigned reg); 54 | bool cdcWriteReg(CdcPage page, unsigned reg, u8 value); 55 | bool cdcWriteRegMask(CdcPage page, unsigned reg, u8 mask, u8 value); 56 | 57 | bool cdcReadRegArray(CdcPage page, unsigned reg, void* data, unsigned len); 58 | bool cdcWriteRegArray(CdcPage page, unsigned reg, const void* data, unsigned len); 59 | 60 | void cdcTscInit(void); 61 | TscResult cdcTscReadTouch(TscTouchData* out, unsigned diff_threshold, u16* out_max_diff); 62 | 63 | void cdcMicSetAmp(bool enable, unsigned gain); 64 | 65 | MK_EXTERN_C_END 66 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/debug.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | 10 | MK_EXTERN_C_START 11 | 12 | typedef enum DebugBufferMode { 13 | DbgBufMode_None = 0, 14 | DbgBufMode_Line = 1, 15 | DbgBufMode_Full = 2, 16 | } DebugBufferMode; 17 | 18 | MK_INLINE void debugSetBufferMode(DebugBufferMode mode) { 19 | extern DebugBufferMode g_dbgBufMode; 20 | g_dbgBufMode = mode; 21 | } 22 | 23 | void debugOutput(const char* buf, size_t size); 24 | 25 | MK_EXTERN_C_END 26 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/i2c.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../../system/mutex.h" 10 | #include "../io.h" 11 | 12 | #define REG_I2C_DATA MK_REG(u8, IO_I2C_DATA) 13 | #define REG_I2C_CNT MK_REG(u8, IO_I2C_CNT) 14 | 15 | MK_EXTERN_C_START 16 | 17 | typedef enum I2cDevice { 18 | I2cDev_MCU = 0x4a, 19 | } I2cDevice; 20 | 21 | extern Mutex g_i2cMutex; 22 | 23 | MK_INLINE void i2cLock(void) 24 | { 25 | mutexLock(&g_i2cMutex); 26 | } 27 | 28 | MK_INLINE void i2cUnlock(void) 29 | { 30 | mutexUnlock(&g_i2cMutex); 31 | } 32 | 33 | bool i2cWriteRegister8(I2cDevice dev, u8 reg, u8 data); 34 | u8 i2cReadRegister8(I2cDevice dev, u8 reg); 35 | 36 | MK_EXTERN_C_END 37 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/mcu.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | 10 | #define MCU_IRQ_PWRBTN_RESET (1U << 0) // Depressed prior to a period of time = Reset request 11 | #define MCU_IRQ_PWRBTN_SHUTDOWN (1U << 1) // Held down for a period of time = Shutdown request 12 | #define MCU_IRQ_PWRBTN_BEGIN (1U << 3) // Begin pressing 13 | #define MCU_IRQ_BATTERY_EMPTY (1U << 4) 14 | #define MCU_IRQ_BATTERY_LOW (1U << 5) 15 | #define MCU_IRQ_VOLBTN (1U << 6) 16 | 17 | MK_EXTERN_C_START 18 | 19 | typedef enum McuRegister { 20 | McuReg_Version = 0x00, 21 | McuReg_Unk01 = 0x01, 22 | McuReg_Unk02 = 0x02, 23 | 24 | McuReg_IrqFlags = 0x10, 25 | McuReg_DoReset = 0x11, 26 | McuReg_Config = 0x12, 27 | 28 | McuReg_BatteryState = 0x20, 29 | McuReg_BatteryUnk = 0x21, 30 | 31 | McuReg_WifiLed = 0x30, 32 | McuReg_CamLed = 0x31, 33 | 34 | McuReg_VolumeLevel = 0x40, 35 | McuReg_BacklightLevel = 0x41, 36 | 37 | McuReg_Unk60 = 0x60, 38 | McuReg_Unk61 = 0x61, 39 | McuReg_Unk62 = 0x62, 40 | McuReg_PowerLed = 0x63, 41 | 42 | McuReg_User0 = 0x70, 43 | McuReg_User1 = 0x71, 44 | McuReg_User2 = 0x72, 45 | McuReg_User3 = 0x73, 46 | McuReg_User4 = 0x74, 47 | McuReg_User5 = 0x75, 48 | McuReg_User6 = 0x76, 49 | McuReg_User7 = 0x77, 50 | 51 | McuReg_WarmbootFlag = McuReg_User0, 52 | 53 | McuReg_PwrBtnTapDelay = 0x80, 54 | McuReg_PwrBtnHoldDelay = 0x81, 55 | } McuRegister; 56 | 57 | typedef enum McuPwrBtnState { 58 | McuPwrBtnState_Normal = 0, 59 | McuPwrBtnState_Begin = 1, 60 | McuPwrBtnState_Reset = 2, 61 | McuPwrBtnState_Shutdown = 3, 62 | } McuPwrBtnState; 63 | 64 | typedef void (*McuIrqHandler)(unsigned irq_mask); 65 | 66 | MK_INLINE McuPwrBtnState mcuGetPwrBtnState(void) 67 | { 68 | extern McuPwrBtnState g_mcuPwrBtnState; 69 | return g_mcuPwrBtnState; 70 | } 71 | 72 | void mcuInit(void); 73 | void mcuStartThread(u8 thread_prio); 74 | void mcuIrqSet(unsigned irq_mask, McuIrqHandler fn); 75 | void mcuIssueReset(void) MK_NORETURN; 76 | void mcuIssueShutdown(void) MK_NORETURN; 77 | 78 | MK_EXTERN_C_END 79 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/mic.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../io.h" 10 | #include "../mic.h" 11 | #include "tsc.h" 12 | #include "codec.h" 13 | 14 | #define REG_MICEX_CNT MK_REG(u16, IO_MICEX_CNT) 15 | #define REG_MICEX_DATA MK_REG(u32, IO_MICEX_DATA) 16 | 17 | #define MICEX_CNT_NO_L (1U<<0) 18 | #define MICEX_CNT_NO_R (1U<<1) 19 | #define MICEX_CNT_RATE_DIV(_x) (((_x)&3)<<2) 20 | #define MICEX_CNT_FIFO_EMPTY (1U<<8) 21 | #define MICEX_CNT_FIFO_HALF (1U<<9) 22 | #define MICEX_CNT_FIFO_FULL (1U<<10) 23 | #define MICEX_CNT_FIFO_BORKED (1U<<11) 24 | #define MICEX_CNT_CLEAR_FIFO (1U<<12) 25 | #define MICEX_CNT_IE_FIFO_HALF (1U<<13) 26 | #define MICEX_CNT_IE_FIFO_FULL (1U<<14) 27 | #define MICEX_CNT_ENABLE (1U<<15) 28 | 29 | MK_EXTERN_C_START 30 | 31 | void micStartServer(u8 thread_prio); 32 | 33 | MK_EXTERN_C_END 34 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/ntrwifi.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../../dev/wlan.h" 10 | 11 | MK_EXTERN_C_START 12 | 13 | typedef void (*NtrWifiScanCompleteFn)(void* user, WlanBssDesc* bss_list, unsigned bss_count); 14 | typedef void (*NtrWifiAssocFn)(void* user, bool success, unsigned reason); 15 | 16 | bool ntrwifiInit(void); 17 | void ntrwifiExit(void); 18 | bool ntrwifiStartScan(WlanBssDesc* out_table, WlanBssScanFilter const* filter, NtrWifiScanCompleteFn cb, void* user); 19 | bool ntrwifiAssociate(WlanBssDesc const* bss, WlanAuthData const* auth, NtrWifiAssocFn cb, void* user); 20 | bool ntrwifiDisassociate(void); 21 | 22 | bool ntrwifiTx(NetBuf* pPacket); 23 | 24 | MK_EXTERN_C_END 25 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/nvram.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "spi.h" 10 | 11 | #define NVRAM_PAGE_SZ 0x100 12 | 13 | #define NVRAM_STATUS_WIP (1U<<0) // Write In Progress 14 | #define NVRAM_STATUS_WEL (1U<<1) // Write Enable Latch 15 | 16 | MK_EXTERN_C_START 17 | 18 | typedef enum NvramCmd { 19 | NvramCmd_WriteEnable = 0x06, 20 | NvramCmd_WriteDisable = 0x04, 21 | NvramCmd_ReadJedec = 0x9f, 22 | NvramCmd_ReadStatus = 0x05, 23 | NvramCmd_ReadDataBytes = 0x03, 24 | NvramCmd_ReadDataBytesFast = 0x0b, 25 | NvramCmd_PageWrite = 0x0a, 26 | NvramCmd_PageProgram = 0x02, 27 | NvramCmd_PageErase = 0xdb, 28 | NvramCmd_SectorErase = 0xd8, 29 | NvramCmd_EnterDeepSleep = 0xb9, 30 | NvramCmd_LeaveDeepSleep = 0xab, 31 | } NvramCmd; 32 | 33 | bool nvramWaitReady(void); 34 | bool nvramReadJedec(u32* out); 35 | bool nvramReadDataBytes(void* data, u32 addr, u32 len); 36 | 37 | MK_EXTERN_C_END 38 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/pmic.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "spi.h" 10 | 11 | // Bits for PmicReg_Control 12 | #define PMIC_CTRL_SOUND_ENABLE (1U<<0) 13 | #define PMIC_CTRL_SOUND_MUTE (1U<<1) 14 | #define PMIC_CTRL_LCD_BL_BOTTOM (1U<<2) 15 | #define PMIC_CTRL_LCD_BL_TOP (1U<<3) 16 | #define PMIC_CTRL_LED_STEADY (0U<<4) 17 | #define PMIC_CTRL_LED_BLINK_SLOW (1U<<4) 18 | #define PMIC_CTRL_LED_BLINK_FAST (3U<<4) 19 | #define PMIC_CTRL_LED_MASK (3U<<4) 20 | #define PMIC_CTRL_SHUTDOWN (1U<<6) 21 | 22 | // Bits for PmicReg_BatteryStatus 23 | #define PMIC_BATT_STAT_NORMAL (0U<<0) 24 | #define PMIC_BATT_STAT_LOW (1U<<0) 25 | 26 | // Bits for PmicReg_MicAmpControl 27 | #define PMIC_MIC_AMP_CTRL_ENABLE (1U<<0) 28 | 29 | // Bits for PmicReg_MicAmpGain 30 | #define PMIC_MIC_AMP_GAIN(_x) ((_x)&3) 31 | #define PMIC_MIC_AMP_GAIN_MASK (3U<<0) 32 | 33 | // Bits for PmicReg_BacklightLevel 34 | #define PMIC_BL_LEVEL(_x) ((_x)&3) 35 | #define PMIC_BL_LEVEL_MASK (3U<<0) 36 | #define PMIC_BL_CHARGER_BL_MAX (1U<<2) 37 | #define PMIC_BL_CHARGER_DETECTED (1U<<3) 38 | 39 | // Bits for PmicReg_ControlExt 40 | #define PMIC_CTRL_EXT_RESET (1U<<0) 41 | #define PMIC_CTRL_EXT_USER (1U<<1) 42 | 43 | MK_EXTERN_C_START 44 | 45 | typedef enum PmicRegister { 46 | PmicReg_Control = 0x00, 47 | PmicReg_BatteryStatus = 0x01, 48 | PmicReg_MicAmpControl = 0x02, 49 | PmicReg_MicAmpGain = 0x03, 50 | PmicReg_BacklightLevel = 0x04, // DS Lite exclusive 51 | PmicReg_ControlExt = 0x10, // DSi exclusive 52 | } PmicRegister; 53 | 54 | typedef enum PmicMicGain { 55 | PmicMicGain_20 = 0, 56 | PmicMicGain_40 = 1, 57 | PmicMicGain_80 = 2, 58 | PmicMicGain_160 = 3, 59 | } PmicMicGain; 60 | 61 | bool pmicWriteRegister(PmicRegister reg, u8 data); 62 | u8 pmicReadRegister(PmicRegister reg); 63 | 64 | void pmicIssueShutdown(void) MK_NORETURN; 65 | 66 | MK_EXTERN_C_END 67 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/rtc.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | 10 | #define RTC_STATUS1_RESET (1U<<0) 11 | #define RTC_STATUS1_12HRS (0U<<1) 12 | #define RTC_STATUS1_24HRS (1U<<1) 13 | #define RTC_STATUS1_USER0 (1U<<2) 14 | #define RTC_STATUS1_USER1 (1U<<3) 15 | #define RTC_STATUS1_INT1 (1U<<4) 16 | #define RTC_STATUS1_INT2 (1U<<5) 17 | #define RTC_STATUS1_BLD (1U<<6) 18 | #define RTC_STATUS1_POC (1U<<7) 19 | 20 | #define RTC_STATUS2_INT1_MODE(_x) ((_x)&0xf) 21 | #define RTC_STATUS2_USER2 (1U<<4) 22 | #define RTC_STATUS2_USER3 (1U<<5) 23 | #define RTC_STATUS2_INT2_EN (1U<<6) 24 | #define RTC_STATUS2_TEST (1U<<7) 25 | 26 | MK_EXTERN_C_START 27 | 28 | typedef enum RtcRegister { 29 | // Available on all models (Seiko S-35180) 30 | RtcReg_Status1 = 0x0, 31 | RtcReg_Status2 = 0x1, 32 | RtcReg_DateTime = 0x2, 33 | RtcReg_Time = 0x3, 34 | RtcReg_FreqDuty = 0x4, 35 | RtcReg_Alarm1Time = 0x4, 36 | RtcReg_Alarm2Time = 0x5, 37 | RtcReg_ClockAdj = 0x6, 38 | RtcReg_User = 0x7, 39 | 40 | // Available on DSi (Seiko S-35199A01) 41 | RtcReg_UpCounter = 0x8, 42 | RtcReg_FoutHi = 0x9, 43 | RtcReg_FoutLo = 0xa, 44 | RtcReg_Alarm1Date = 0xc, 45 | RtcReg_Alarm2Date = 0xd, 46 | } RtcRegister; 47 | 48 | typedef enum RtcInt1Mode { 49 | RtcInt1Mode_Disabled = 0x0, 50 | RtcInt1Mode_FreqDuty = 0x1, 51 | RtcInt1Mode_MinEdge = 0x2, 52 | RtcInt1Mode_MinSteady = 0x3, 53 | RtcInt1Mode_Alarm1 = 0x4, 54 | RtcInt1Mode_MinSteadyPulse = 0x7, 55 | RtcInt1Mode_32kHz = 0x8, 56 | } RtcInt1Mode; 57 | 58 | typedef struct RtcDateTime { 59 | u8 year; // 2000-2099 (only last two digits) 60 | u8 month; // 1-12 61 | u8 day; // 1-31 62 | u8 weekday; // 0-7 starting Monday 63 | u8 hour; // 0-23 64 | u8 minute; // 0-59 65 | u8 second; // 0-59 66 | } RtcDateTime; 67 | 68 | MK_CONSTEXPR u8 rtcDecodeBcd(u8 bcd) 69 | { 70 | return 10*(bcd>>4) + (bcd & 0xf); 71 | } 72 | 73 | void rtcInit(void); 74 | void rtcSyncTime(void); 75 | 76 | void rtcReadRegister(RtcRegister reg, void* data, size_t size); 77 | void rtcWriteRegister(RtcRegister reg, const void* data, size_t size); 78 | 79 | void rtcReadDateTime(RtcDateTime* t); 80 | u32 rtcDateTimeToUnix(const RtcDateTime* t); 81 | 82 | MK_INLINE u8 rtcReadRegister8(RtcRegister reg) 83 | { 84 | u8 value; 85 | rtcReadRegister(reg, &value, 1); 86 | return value; 87 | } 88 | 89 | MK_INLINE void rtcWriteRegister8(RtcRegister reg, u8 value) 90 | { 91 | rtcWriteRegister(reg, &value, 1); 92 | } 93 | 94 | MK_INLINE u32 rtcReadUnixTime(void) 95 | { 96 | RtcDateTime t; 97 | rtcReadDateTime(&t); 98 | return rtcDateTimeToUnix(&t); 99 | } 100 | 101 | MK_EXTERN_C_END 102 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/spi.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../../system/mutex.h" 10 | #include "../io.h" 11 | 12 | #define REG_SPICNT MK_REG(u16, IO_SPICNT) 13 | #define REG_SPIDATA MK_REG(u16, IO_SPIDATA) 14 | 15 | #define SPICNT_BUSY (1U << 7) 16 | #define SPICNT_DEVICE(_x) ((unsigned)((_x) & 3) << 8) 17 | #define SPICNT_HOLD (1U << 11) 18 | #define SPICNT_IRQ_ENABLE (1U << 14) 19 | #define SPICNT_ENABLE (1U << 15) 20 | 21 | MK_EXTERN_C_START 22 | 23 | typedef enum SpiBaudrate { 24 | SpiBaud_4MHz = 0, 25 | SpiBaud_2MHz, 26 | SpiBaud_1MHz, 27 | SpiBaud_512KHz, 28 | SpiBaud_8MHz, // DSi-only 29 | } SpiBaudrate; 30 | 31 | typedef enum SpiDevice { 32 | SpiDev_PMIC = 0, 33 | SpiDev_NVRAM, 34 | SpiDev_TSC, 35 | } SpiDevice; 36 | 37 | extern Mutex g_spiMutex; 38 | 39 | MK_INLINE void spiLock(void) 40 | { 41 | mutexLock(&g_spiMutex); 42 | } 43 | 44 | MK_INLINE void spiUnlock(void) 45 | { 46 | mutexUnlock(&g_spiMutex); 47 | } 48 | 49 | MK_INLINE void spiWaitBusy(void) 50 | { 51 | while (REG_SPICNT & SPICNT_BUSY); 52 | } 53 | 54 | MK_INLINE void spiRawStartHold(SpiDevice dev, SpiBaudrate baud) 55 | { 56 | spiWaitBusy(); 57 | REG_SPICNT = baud | SPICNT_DEVICE(dev) | SPICNT_HOLD | SPICNT_ENABLE; 58 | } 59 | 60 | MK_INLINE void spiRawEndHold(SpiDevice dev, SpiBaudrate baud) 61 | { 62 | REG_SPICNT = baud | SPICNT_DEVICE(dev) | SPICNT_ENABLE; 63 | } 64 | 65 | MK_INLINE void spiRawWriteByteAsync(u8 data) 66 | { 67 | REG_SPIDATA = data; 68 | } 69 | 70 | MK_INLINE void spiRawWriteByte(u8 data) 71 | { 72 | spiRawWriteByteAsync(data); 73 | spiWaitBusy(); 74 | } 75 | 76 | MK_INLINE u8 spiRawWriteReadByte(u8 data) 77 | { 78 | spiRawWriteByte(data); 79 | return REG_SPIDATA; 80 | } 81 | 82 | MK_INLINE u8 spiRawReadByte(void) 83 | { 84 | return spiRawWriteReadByte(0); 85 | } 86 | 87 | MK_EXTERN_C_END 88 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/tsc.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "spi.h" 10 | 11 | MK_EXTERN_C_START 12 | 13 | typedef enum TscPowerMode { 14 | TscPowerMode_Auto = 0U<<0, 15 | TscPowerMode_AdcOn = 1U<<0, 16 | TscPowerMode_RefOn = 2U<<0, 17 | TscPowerMode_AllOn = 3U<<0, 18 | } TscPowerMode; 19 | 20 | typedef enum TscRef { 21 | TscRef_Differential = 0U<<2, 22 | TscRef_SingleEnded = 1U<<2, 23 | } TscRef; 24 | 25 | typedef enum TscConvMode { 26 | TscConvMode_12bit = 0U<<3, 27 | TscConvMode_8bit = 1U<<3, 28 | } TscConvMode; 29 | 30 | typedef enum TscChannel { 31 | TscChannel_T0 = (0U<<4) | TscRef_SingleEnded, 32 | TscChannel_Y = (1U<<4) | TscRef_Differential, 33 | TscChannel_VBAT = (2U<<4) | TscRef_SingleEnded, 34 | TscChannel_Z1 = (3U<<4) | TscRef_Differential, 35 | TscChannel_Z2 = (4U<<4) | TscRef_Differential, 36 | TscChannel_X = (5U<<4) | TscRef_Differential, 37 | TscChannel_AUX = (6U<<4) | TscRef_SingleEnded, 38 | TscChannel_T1 = (7U<<4) | TscRef_SingleEnded, 39 | } TscChannel; 40 | 41 | typedef enum TscResult { 42 | TscResult_None = 0, 43 | TscResult_Noisy = 1, 44 | TscResult_Valid = 2, 45 | } TscResult; 46 | 47 | typedef struct MK_STRUCT_ALIGN(4) TscTouchData { 48 | u16 x, y; 49 | } TscTouchData; 50 | 51 | MK_CONSTEXPR unsigned tscAbs(signed x) 52 | { 53 | return x >= 0 ? x : (-x); 54 | } 55 | 56 | MK_CONSTEXPR u8 tscMakeCmd(TscChannel ch, TscConvMode conv, TscPowerMode pm) 57 | { 58 | return pm | conv | ch | (1U<<7); 59 | } 60 | 61 | void tscInit(void); 62 | TscResult tscReadTouch(TscTouchData* out, unsigned diff_threshold, u16* out_max_diff); 63 | unsigned tscReadChannel8(TscChannel ch); 64 | unsigned tscReadChannel12(TscChannel ch); 65 | 66 | MK_EXTERN_C_END 67 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/twlblk.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | 10 | MK_EXTERN_C_START 11 | 12 | bool twlblkInit(void); 13 | 14 | bool twlSdInit(void); 15 | bool twlSdIsInserted(void); 16 | bool twlSdReadSectors(void* buffer, u32 first_sector, u32 num_sectors); 17 | bool twlSdWriteSectors(const void* buffer, u32 first_sector, u32 num_sectors); 18 | 19 | bool twlNandInit(void); 20 | bool twlNandReadSectors(void* buffer, u32 first_sector, u32 num_sectors); 21 | bool twlNandWriteSectors(const void* buffer, u32 first_sector, u32 num_sectors); 22 | bool twlNandReadSectorsAes(void* buffer, u32 first_sector, u32 num_sectors); 23 | bool twlNandWriteSectorsAes(const void* buffer, u32 first_sector, u32 num_sectors); 24 | 25 | MK_EXTERN_C_END 26 | -------------------------------------------------------------------------------- /include/calico/nds/arm7/twlwifi.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM7) 5 | #error "This header file is only for NDS ARM7" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../../dev/wlan.h" 10 | 11 | MK_EXTERN_C_START 12 | 13 | typedef void (*TwlWifiScanCompleteFn)(void* user, WlanBssDesc* bss_list, unsigned bss_count); 14 | typedef void (*TwlWifiAssocFn)(void* user, bool success, unsigned reason); 15 | 16 | bool twlwifiInit(void); 17 | void twlwifiExit(void); 18 | bool twlwifiStartScan(WlanBssDesc* out_table, WlanBssScanFilter const* filter, TwlWifiScanCompleteFn cb, void* user); 19 | bool twlwifiIsScanning(void); 20 | bool twlwifiAssociate(WlanBssDesc const* bss, WlanAuthData const* auth, TwlWifiAssocFn cb, void* user); 21 | bool twlwifiDisassociate(void); 22 | 23 | bool twlwifiTx(NetBuf* pPacket); 24 | 25 | MK_EXTERN_C_END 26 | -------------------------------------------------------------------------------- /include/calico/nds/arm9/arm7_debug.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM9) 5 | #error "This header file is only for NDS ARM9" 6 | #endif 7 | 8 | #include "../../types.h" 9 | 10 | /*! @addtogroup env 11 | @{ 12 | */ 13 | 14 | MK_EXTERN_C_START 15 | 16 | /*! @brief ARM7 debug output callback 17 | @param[in] buf Message buffer (not NUL-terminated) 18 | @param[in] size Length of the message buffer in bytes 19 | */ 20 | typedef void (* Arm7DebugFn)(const char* buf, size_t size); 21 | 22 | /*! @brief Starts a server thread for handling the ARM7's debug output 23 | @param[in] fn Callback function (see @ref Arm7DebugFn) 24 | @param[in] thread_prio Priority of the server thread 25 | */ 26 | void installArm7DebugSupport(Arm7DebugFn fn, u8 thread_prio); 27 | 28 | MK_EXTERN_C_END 29 | 30 | //! @} 31 | -------------------------------------------------------------------------------- /include/calico/nds/arm9/mic.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM9) 5 | #error "This header file is only for NDS ARM9" 6 | #endif 7 | 8 | #include "../mic.h" 9 | 10 | /*! @addtogroup mic 11 | @{ 12 | */ 13 | 14 | MK_EXTERN_C_START 15 | 16 | /*! @brief Microphone recording callback, invoked when an entire audio buffer has been recorded 17 | @param[in] user User-provided data passed to @ref micSetCallback 18 | @param[in] buf Address of buffer containing the recorded audio 19 | @param[in] byte_sz Size in bytes of the recorded audio 20 | */ 21 | typedef void (*MicBufferFn)(void* user, void* buf, size_t byte_sz); 22 | 23 | //! Initializes the microphone driver 24 | void micInit(void); 25 | 26 | /*! @brief Configures the microphone sampling rate 27 | @param[in] prescaler CPU timer prescaler (see TIMER_PRESCALER_\*) 28 | @param[in] period CPU timer period (see @ref timerCalcPeriod) 29 | @return true on success, false on failure 30 | 31 | Microphone sampling on the Nintendo DS is driven manually using CPU timers. 32 | This means the ARM7 must execute code to read a sample from the microphone 33 | at very precise moments. As a result, microphone sampling is very CPU intensive, 34 | and the performance of other drivers that run on the ARM7 (such as touch 35 | screen, storage device or wireless networking) will be more affected in 36 | proportion to the microphone sampling rate. 37 | 38 | On the DSi, the hardware supports entirely automatic (DMA-driven) microphone 39 | sampling, albeit at only a fixed number of sampling rate presets. Consider 40 | using @ref micSetDmaRate unless you have a need for a very specific sampling 41 | rate. Note that @ref micSetDmaRate will graciously fall back to compatible 42 | CPU timer driven sampling in DS mode. 43 | */ 44 | bool micSetCpuTimer(unsigned prescaler, unsigned period); 45 | 46 | /*! @brief Configures the microphone sampling rate using a @p rate preset (see @ref MicRate) 47 | @return true on success, false on failure 48 | 49 | On the DSi, calico supports using DMA based microphone sampling. This method 50 | is more efficient because it utilizes hardware resources to automatically fill 51 | in the buffer without ARM7 CPU involvement; however the hardware only supports 52 | a fixed number of sampling rates. Unless you have a need for a very specific 53 | sampling rate, use this function. 54 | 55 | This function falls back to standard CPU timer based sampling in DS mode. 56 | */ 57 | bool micSetDmaRate(MicRate rate); 58 | 59 | //! Configures the recording callback @p fn with the specified @p user data 60 | void micSetCallback(MicBufferFn fn, void* user); 61 | 62 | /*! @brief Starts microphone recording activity 63 | @param[out] buf Recording buffer. As an output buffer, it must be cache 64 | line (32-byte) aligned and visible to ARM7. 65 | @param[in] byte_sz Size of the buffer in bytes (must be 32-byte aligned) 66 | @param[in] fmt Recording format (see @ref MicFmt) 67 | @param[in] mode Recording mode (see @ref MicMode) 68 | @return true on success, false on failure 69 | 70 | @note For @ref MicMode_DoubleBuffer, @p buf points to the first buffer, and @p byte_sz 71 | specifies the size of a single buffer. The second buffer starts at `(u8*)buf + byte_sz`. 72 | 73 | @note Do not forget to call @ref pmMicSetAmp in order to turn on/off the microphone amplifier! 74 | */ 75 | bool micStart(void* buf, size_t byte_sz, MicFmt fmt, MicMode mode); 76 | 77 | //! Stops microphone recording activity 78 | void micStop(void); 79 | 80 | MK_EXTERN_C_END 81 | 82 | //! @} 83 | -------------------------------------------------------------------------------- /include/calico/nds/arm9/ovl.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../../types.h" 5 | #include "../env.h" 6 | 7 | /*! @addtogroup ovl 8 | 9 | Overlays allow large programs to be split up in smaller pieces that can be 10 | loaded dynamically. Moreover, pieces of code that do not need to be accessed 11 | simultaneously can be loaded to the same address, therefore saving memory. 12 | An example would be code related to different game modes (e.g. overworld/battle), 13 | menu systems, or stage specific effects. 14 | 15 | The DS ROM file format has support for overlay files that are loaded to 16 | predetermined memory addresses. In order to add overlays to the executable, 17 | it is necessary to use a custom linker script that places the desired 18 | code/data sections into special overlay segments that are then processed by 19 | ndstool and converted into overlay files. 20 | 21 | For a simple example of how to use overlays, see nds-examples/filesystem/nitrofs/overlays. 22 | 23 | @{ 24 | */ 25 | 26 | MK_EXTERN_C_START 27 | 28 | typedef EnvNdsOverlay OvlParams; //!< @private 29 | typedef void (*OvlStaticFn)(void); //!< @private 30 | 31 | /*! @brief Initializes the overlay system 32 | 33 | The overlay system uses @ref nitroromGetSelf to obtain access to the 34 | application's DS ROM. Please refer to its documentation for more details. 35 | 36 | @return true on success, false on failure 37 | */ 38 | bool ovlInit(void); 39 | 40 | /*! @brief Preloads the specified overlay into its target address, without activating it 41 | @param[in] ovl_id ID of the overlay to load 42 | @return true on success, false on failure 43 | */ 44 | bool ovlLoadInPlace(unsigned ovl_id); 45 | 46 | //! Activates overlay @p ovl_id, invoking its static constructors 47 | void ovlActivate(unsigned ovl_id); 48 | 49 | //! Deactivates overlay @p ovl_id, invoking its static destructors 50 | void ovlDeactivate(unsigned ovl_id); 51 | 52 | /*! @brief Loads and activates the specified overlay 53 | @param[in] ovl_id ID of the overlay to load 54 | @return true on success, false on failure 55 | */ 56 | MK_INLINE bool ovlLoadAndActivate(unsigned ovl_id) 57 | { 58 | bool ok = ovlLoadInPlace(ovl_id); 59 | if (ok) { 60 | ovlActivate(ovl_id); 61 | } 62 | return ok; 63 | } 64 | 65 | MK_EXTERN_C_END 66 | 67 | //! @} 68 | -------------------------------------------------------------------------------- /include/calico/nds/arm9/vram.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) || !defined(ARM9) 5 | #error "This header file is only for NDS ARM9" 6 | #endif 7 | 8 | #include "../../types.h" 9 | #include "../io.h" 10 | 11 | /*! @addtogroup hw 12 | @{ 13 | */ 14 | 15 | /*! @name VRAM configuration registers 16 | @{ 17 | */ 18 | 19 | #define REG_VRAMCNT_A MK_REG(u8, IO_VRAMCNT_A) 20 | #define REG_VRAMCNT_B MK_REG(u8, IO_VRAMCNT_B) 21 | #define REG_VRAMCNT_C MK_REG(u8, IO_VRAMCNT_C) 22 | #define REG_VRAMCNT_D MK_REG(u8, IO_VRAMCNT_D) 23 | #define REG_VRAMCNT_E MK_REG(u8, IO_VRAMCNT_E) 24 | #define REG_VRAMCNT_F MK_REG(u8, IO_VRAMCNT_F) 25 | #define REG_VRAMCNT_G MK_REG(u8, IO_VRAMCNT_G) 26 | #define REG_VRAMCNT_H MK_REG(u8, IO_VRAMCNT_H) 27 | #define REG_VRAMCNT_I MK_REG(u8, IO_VRAMCNT_I) 28 | 29 | #define REG_VRAMCNT_ABCD MK_REG(u32, IO_VRAMCNT_A) 30 | #define REG_VRAMCNT_AB MK_REG(u16, IO_VRAMCNT_A) 31 | #define REG_VRAMCNT_CD MK_REG(u16, IO_VRAMCNT_C) 32 | #define REG_VRAMCNT_EF MK_REG(u16, IO_VRAMCNT_E) 33 | #define REG_VRAMCNT_HI MK_REG(u16, IO_VRAMCNT_H) 34 | 35 | #define VRAM_ENABLE (1U<<7) 36 | #define VRAM_MST(_x) ((_x)&7) 37 | #define VRAM_OFFSET(_x) (((_x)&3)<<3) 38 | #define VRAM_CONFIG(_mst, _off) (VRAM_MST(_mst) | VRAM_OFFSET(_off) | VRAM_ENABLE) 39 | 40 | //! @} 41 | 42 | //! @} 43 | -------------------------------------------------------------------------------- /include/calico/nds/bios.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | /*! @addtogroup bios 7 | @{ 8 | */ 9 | 10 | // Parameters for svcCpuSet 11 | #define SVC_SET_SIZE_16(_sz) (((_sz)/2) & 0x1fffff) 12 | #define SVC_SET_SIZE_32(_sz) (((_sz)/4) & 0x1fffff) 13 | #define SVC_SET_FIXED (1<<24) 14 | #define SVC_SET_UNIT_16 (0<<26) 15 | #define SVC_SET_UNIT_32 (1<<26) 16 | 17 | #define SVC_RSA_HEAP_SZ 0x1000 18 | #define SVC_RSA_BUFFER_SZ 0x80 19 | #define SVC_SHA1_DIGEST_SZ 0x14 20 | 21 | MK_EXTERN_C_START 22 | 23 | typedef struct SvcDivResult { 24 | s32 quot; 25 | s32 rem; 26 | } SvcDivResult; 27 | 28 | typedef struct SvcBitUnpackParams { 29 | u16 in_length_bytes; 30 | u8 in_width_bits; 31 | u8 out_width_bits; 32 | u32 data_offset : 31; 33 | u32 zero_data_flag : 1; 34 | } SvcBitUnpackParams; 35 | 36 | typedef struct SvcRsaHeapContext { 37 | void* start; 38 | void* end; 39 | size_t size; 40 | } SvcRsaHeapContext; 41 | 42 | typedef struct SvcRsaParams { 43 | void* output; 44 | const void* input; 45 | const void* key; 46 | } SvcRsaParams; 47 | 48 | typedef struct SvcSha1Context { 49 | u32 state[5]; 50 | u32 total[2]; 51 | u8 frag_buffer[64]; 52 | u32 frag_size; 53 | void (*hash_block)(struct SvcSha1Context* ctx, const void* data, size_t size); // MUST be set to 0 before init! 54 | } SvcSha1Context; 55 | 56 | void svcWaitByLoop(s32 loop_cycles); 57 | void svcHalt(void); 58 | #ifdef ARM7 59 | void svcSleep(void); 60 | void svcSoundBias(bool enable, u32 delay_count); 61 | #endif 62 | u64 svcDivModImpl(s32 num, s32 den) __asm__("svcDivMod"); //!< @private 63 | void svcCpuSet(const void* src, void* dst, u32 mode); 64 | u16 svcSqrt(u32 num); 65 | u16 svcGetCRC16(u16 initial_crc, const void* mem, u32 size); 66 | void svcBitUnpack(const void* src, void* dst, SvcBitUnpackParams const* params); 67 | void svcLZ77UncompWram(const void* src, void* dst); 68 | void svcRLUncompWram(const void* src, void* dst); 69 | void svcDiff8bitUnfilterWram(const void* src, void* dst); 70 | void svcDiff16bitUnfilter(const void* src, void* dst); 71 | 72 | MK_INLINE SvcDivResult svcDivMod(s32 num, s32 den) 73 | { 74 | union { 75 | u64 ret; 76 | SvcDivResult res; 77 | } u = { svcDivModImpl(num, den) }; 78 | return u.res; 79 | } 80 | 81 | #ifdef ARM7 82 | MK_NORETURN void svcCustomHalt(unsigned mode); 83 | #endif 84 | 85 | void svcRsaHeapInitTWL(SvcRsaHeapContext* ctx, void* mem, size_t size); 86 | bool svcRsaDecryptRawTWL(SvcRsaHeapContext* ctx, const SvcRsaParams* params, size_t* out_size); 87 | bool svcRsaDecryptUnpadTWL(SvcRsaHeapContext* ctx, void* output, const void* input, const void* key); // sizeof(output) >= SVC_RSA_BUFFER_SZ 88 | bool svcRsaDecryptDerSha1TWL(SvcRsaHeapContext* ctx, void* output, const void* input, const void* key); 89 | 90 | void svcSha1InitTWL(SvcSha1Context* ctx); 91 | void svcSha1UpdateTWL(SvcSha1Context* ctx, const void* data, size_t size); 92 | void svcSha1DigestTWL(void* digest, SvcSha1Context* ctx); 93 | void svcSha1CalcTWL(void* digest, const void* data, size_t size); 94 | bool svcSha1VerifyTWL(const void* lhs, const void* rhs); 95 | void svcSha1RandomTWL(void* output, size_t out_size, const void* seed, size_t seed_size); 96 | 97 | MK_EXTERN_C_END 98 | 99 | //! @} 100 | -------------------------------------------------------------------------------- /include/calico/nds/dma.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../gba/dma.h" 5 | -------------------------------------------------------------------------------- /include/calico/nds/gbacart.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) 5 | #error "This header file is only for NDS" 6 | #endif 7 | 8 | #include "../types.h" 9 | #include "mm.h" 10 | #include "system.h" 11 | 12 | /*! @addtogroup gbacart 13 | @{ 14 | */ 15 | 16 | /*! @name GBA cartridge slot timings 17 | @{ 18 | */ 19 | 20 | #define GBA_WAIT_SRAM_MASK (3U<<0) 21 | #define GBA_WAIT_SRAM_10 (0U<<0) 22 | #define GBA_WAIT_SRAM_8 (1U<<0) 23 | #define GBA_WAIT_SRAM_6 (2U<<0) 24 | #define GBA_WAIT_SRAM_18 (3U<<0) 25 | 26 | #define GBA_WAIT_ROM_N_MASK (3U<<2) 27 | #define GBA_WAIT_ROM_N_10 (0U<<2) 28 | #define GBA_WAIT_ROM_N_8 (1U<<2) 29 | #define GBA_WAIT_ROM_N_6 (2U<<2) 30 | #define GBA_WAIT_ROM_N_18 (3U<<2) 31 | 32 | #define GBA_WAIT_ROM_S_MASK (1U<<4) 33 | #define GBA_WAIT_ROM_S_6 (0U<<4) 34 | #define GBA_WAIT_ROM_S_4 (1U<<4) 35 | 36 | #define GBA_WAIT_ROM_MASK (GBA_WAIT_ROM_N_MASK|GBA_WAIT_ROM_S_MASK) 37 | 38 | #define GBA_PHI_MASK (3U<<5) 39 | #define GBA_PHI_LOW (0U<<5) 40 | #define GBA_PHI_4_19 (1U<<5) 41 | #define GBA_PHI_8_38 (2U<<5) 42 | #define GBA_PHI_16_76 (3U<<5) 43 | 44 | #define GBA_ALL_MASK (GBA_WAIT_SRAM_MASK|GBA_WAIT_ROM_MASK|GBA_PHI_MASK) 45 | 46 | //! @} 47 | 48 | MK_EXTERN_C_START 49 | 50 | /*! @brief Brokers ownership and access to the GBA cartridge slot from the current CPU 51 | @return true on success, false if the hardware is in use by the other CPU 52 | 53 | The GBA cartridge slot does not exist on the DSi, and any attempts to open it while 54 | in DSi mode will fail. In DS mode it will however succeed, although nothing meaningful 55 | can be done with it since the non-existent slot behaves as open bus (no cartridge inserted). 56 | 57 | On the ARM9, access to the GBA ROM/RAM address space requires ownership of the GBA 58 | cartridge slot. If the ARM9 does not currently own the slot, attempts to access the 59 | address space will cause prefetch/data abort exceptions ("segfaults"). 60 | 61 | When DLDI drivers for Slot-2 flashcards are loaded, the ARM7 takes ownership 62 | of the GBA slot; which means calling this function from the ARM9 will fail. 63 | */ 64 | bool gbacartOpen(void); 65 | 66 | //! Releases GBA cartridge slot ownership obtained by @ref gbacartOpen 67 | void gbacartClose(void); 68 | 69 | //! Returns true if the current CPU owns the GBA cartridge slot 70 | bool gbacartIsOpen(void); 71 | 72 | /*! @brief Configures GBA cartridge slot timings 73 | @param[in] mask Bitmask of timing values to modify 74 | @param[in] timing New timing values to set 75 | @return Previous timing values in use 76 | */ 77 | unsigned gbacartSetTiming(unsigned mask, unsigned timing); 78 | 79 | MK_EXTERN_C_END 80 | 81 | //! @} 82 | -------------------------------------------------------------------------------- /include/calico/nds/keypad.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../gba/keypad.h" 5 | -------------------------------------------------------------------------------- /include/calico/nds/lcd.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../gba/lcd.h" 5 | -------------------------------------------------------------------------------- /include/calico/nds/mic.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) 5 | #error "This header file is only for NDS" 6 | #endif 7 | 8 | #include "../types.h" 9 | #include "../system/sysclock.h" 10 | #include "timer.h" 11 | 12 | /*! @addtogroup mic 13 | @{ 14 | */ 15 | 16 | //! Microphone sampling formats 17 | typedef enum MicFmt { 18 | MicFmt_Pcm8 = 0, //!< Signed 8-bit PCM 19 | MicFmt_Pcm16 = 1, //!< Signed 16-bit PCM 20 | } MicFmt; 21 | 22 | //! Microphone sampling modes 23 | typedef enum MicMode { 24 | MicMode_OneShot = 0, //!< Records a single audio buffer, and stops afterwards 25 | MicMode_Repeat = 1, //!< Records a single audio buffer continuously 26 | MicMode_DoubleBuffer = 2, //!< Records audio to two alternating and consecutive buffers 27 | } MicMode; 28 | 29 | //! Microphone sampling rate presets 30 | typedef enum MicRate { 31 | MicRate_Full = 0, //!< Sampling frequency is equal to sound mixer output (typically 32728 Hz, see @ref SOUND_MIXER_FREQ_HZ) 32 | MicRate_Div2 = 1, //!< Sampling frequency is 1/2 of sound mixer output (typically 16364 Hz) 33 | MicRate_Div3 = 2, //!< Sampling frequency is 1/3 of sound mixer output (typically 10909 Hz) 34 | MicRate_Div4 = 3, //!< Sampling frequency is 1/4 of sound mixer output (typically 8182 Hz) 35 | } MicRate; 36 | 37 | //! Calculates the required sound timer value for the specified mic @p rate 38 | MK_CONSTEXPR unsigned soundTimerFromMicRate(MicRate rate) 39 | { 40 | return 512*((unsigned)rate + 1); 41 | } 42 | 43 | //! @} 44 | -------------------------------------------------------------------------------- /include/calico/nds/mm.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) 5 | #error "This header file is only for NDS" 6 | #endif 7 | 8 | /*! @addtogroup mm 9 | @{ 10 | */ 11 | 12 | #ifdef ARM7 13 | #define MM_BIOS 0x0000000 // 32-bit bus 14 | #define MM_BIOS_SZ_NTR 0x4000 // 16kb 15 | #define MM_BIOS_SZ_TWL 0x10000 // 64kb 16 | #endif 17 | 18 | #ifdef ARM9 19 | #define MM_VECTORS 0x0000000 // ITCM 20 | #define MM_VECTORS_SZ 0x20 // 32 bytes 21 | 22 | #define MM_ITCM 0x1ff8000 // ITCM 23 | #define MM_ITCM_SZ 0x8000 // 32kb 24 | #endif 25 | 26 | #define MM_MAINRAM 0x2000000 // 16-bit bus 27 | #define MM_MAINRAM_SZ_NTR 0x400000 // 4mb 28 | #define MM_MAINRAM_SZ_DBG 0x800000 // 8mb 29 | #define MM_MAINRAM_SZ_TWL 0x1000000 // 16mb 30 | 31 | #ifdef ARM9 32 | #define MM_DTCM 0x2ff0000 // DTCM 33 | #define MM_DTCM_SZ 0x4000 // 16kb 34 | #endif 35 | 36 | #define MM_TWLWRAM_MAP 0x3000000 37 | #define MM_TWLWRAM_BANK_SZ 0x40000 // 256kb 38 | #define MM_TWLWRAM_SLOT_A_SZ 0x10000 // 64kb 39 | #define MM_TWLWRAM_SLOT_B_SZ 0x8000 // 32kb 40 | #define MM_TWLWRAM_SLOT_C_SZ 0x8000 // 32kb 41 | 42 | #ifdef ARM7 43 | #define MM_A7WRAM 0x37f8000 // 32-bit bus 44 | #define MM_A7WRAM_SZ 0x18000 // 96kb 45 | #endif 46 | 47 | #define MM_IO 0x4000000 // 32-bit bus 48 | 49 | #ifdef ARM9 50 | #define MM_PALRAM 0x5000000 // 16-bit bus 51 | #define MM_PALRAM_SZ 0x800 // 2kb 52 | #endif 53 | 54 | #define MM_VRAM 0x6000000 // 16-bit bus 55 | 56 | #ifdef ARM7 57 | #define MM_VRAM_SZ_MAX 0x40000 // 256kb 58 | #endif 59 | 60 | #ifdef ARM9 61 | #define MM_VRAM_BG_A (MM_VRAM) 62 | #define MM_VRAM_BG_B (MM_VRAM+0x200000) 63 | #define MM_VRAM_OBJ_A (MM_VRAM+0x400000) 64 | #define MM_VRAM_OBJ_B (MM_VRAM+0x600000) 65 | 66 | #define MM_VRAM_A (MM_VRAM+0x800000) 67 | #define MM_VRAM_A_SZ 0x20000 // 128kb 68 | 69 | #define MM_VRAM_B (MM_VRAM+0x820000) 70 | #define MM_VRAM_B_SZ 0x20000 // 128kb 71 | 72 | #define MM_VRAM_C (MM_VRAM+0x840000) 73 | #define MM_VRAM_C_SZ 0x20000 // 128kb 74 | 75 | #define MM_VRAM_D (MM_VRAM+0x860000) 76 | #define MM_VRAM_D_SZ 0x20000 // 128kb 77 | 78 | #define MM_VRAM_E (MM_VRAM+0x880000) 79 | #define MM_VRAM_E_SZ 0x10000 // 64kb 80 | 81 | #define MM_VRAM_F (MM_VRAM+0x890000) 82 | #define MM_VRAM_F_SZ 0x4000 // 16kb 83 | 84 | #define MM_VRAM_G (MM_VRAM+0x894000) 85 | #define MM_VRAM_G_SZ 0x4000 // 16kb 86 | 87 | #define MM_VRAM_H (MM_VRAM+0x898000) 88 | #define MM_VRAM_H_SZ 0x8000 // 32kb 89 | 90 | #define MM_VRAM_I (MM_VRAM+0x8a0000) 91 | #define MM_VRAM_I_SZ 0x4000 // 16kb 92 | 93 | #define MM_OBJRAM 0x7000000 // 32-bit bus 94 | #define MM_OBJRAM_SZ 0x800 // 2kb 95 | #endif 96 | 97 | #define MM_CARTROM 0x8000000 // 16-bit bus 98 | #define MM_CARTROM_SZ 0x2000000 // 32mb 99 | 100 | #define MM_CARTRAM 0xa000000 // 8-bit bus 101 | #define MM_CARTRAM_SZ 0x10000 // 64kb 102 | 103 | #define MM_MAINRAM2_TWL 0xc000000 // 16-bit bus 104 | #define MM_MAINRAM2_TWL_SZ 0x1000000 // 16mb 105 | #define MM_MAINRAM2_TWL_SZ_DBG 0x2000000 // 32mb 106 | 107 | #ifdef ARM9 108 | #define MM_BIOS 0xffff0000 // 32-bit bus 109 | #define MM_BIOS_SZ_NTR 0x1000 // 4kb 110 | #define MM_BIOS_SZ_TWL 0x10000 // 64kb 111 | #endif 112 | 113 | //! @} 114 | -------------------------------------------------------------------------------- /include/calico/nds/smutex.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | /*! @addtogroup sync 7 | @{ 8 | */ 9 | /*! @name System-wide mutex (or "Super-mutex") 10 | Provides a mutex that can be used to arbitrate accesses to resources between 11 | the ARM9 and the ARM7. Unlike @ref Mutex, this primitive does not implement 12 | priority inheritance. 13 | @{ 14 | */ 15 | 16 | #if defined(ARM9) 17 | #define SMUTEX_MY_CPU_ID 9 18 | #elif defined(ARM7) 19 | #define SMUTEX_MY_CPU_ID 7 20 | #else 21 | #error "ARM9 or ARM7 must be defined" 22 | #endif 23 | 24 | MK_EXTERN_C_START 25 | 26 | //! System-wide mutex object 27 | typedef struct SMutex { 28 | u32 spinner; //!< @private 29 | u32 thread_ptr : 28; //!< @private 30 | u32 cpu_id : 4; //!< @private 31 | } SMutex; 32 | 33 | //! @brief Locks the SMutex @p m 34 | MK_EXTERN32 void smutexLock(SMutex* m); 35 | 36 | //! @brief Tries to lock the SMutex @p m without blocking, returning true on success 37 | MK_EXTERN32 bool smutexTryLock(SMutex* m); 38 | 39 | //! @brief Unlocks the SMutex @p m 40 | MK_EXTERN32 void smutexUnlock(SMutex* m); 41 | 42 | MK_EXTERN_C_END 43 | 44 | //! @} 45 | 46 | //! @} 47 | -------------------------------------------------------------------------------- /include/calico/nds/system.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) 5 | #error "This header file is only for NDS" 6 | #endif 7 | 8 | #include "../types.h" 9 | #include "io.h" 10 | 11 | /*! @addtogroup hw 12 | @{ 13 | */ 14 | 15 | /*! @name "External" memory configuration registers 16 | @{ 17 | */ 18 | 19 | #define REG_EXMEMCNT MK_REG(u16, IO_EXMEMCNT) 20 | #ifdef ARM7 21 | #define REG_EXMEMCNT2 MK_REG(u16, IO_EXMEMCNT2) 22 | #endif 23 | 24 | #define EXMEMCNT_GBA_SLOT_ARM9 (0U<<7) 25 | #define EXMEMCNT_GBA_SLOT_ARM7 (1U<<7) 26 | #define EXMEMCNT_NDS_SLOT_ARM9 (0U<<11) 27 | #define EXMEMCNT_NDS_SLOT_ARM7 (1U<<11) 28 | #define EXMEMCNT_MAIN_RAM_IFACE_ASYNC (0U<<14) 29 | #define EXMEMCNT_MAIN_RAM_IFACE_SYNC (1U<<14) 30 | #define EXMEMCNT_MAIN_RAM_PRIO_ARM9 (0U<<15) 31 | #define EXMEMCNT_MAIN_RAM_PRIO_ARM7 (1U<<15) 32 | 33 | //! @} 34 | 35 | MK_EXTERN_C_START 36 | 37 | //! Returns true if the application is running in DSi mode 38 | MK_INLINE bool systemIsTwlMode(void) 39 | { 40 | extern bool g_isTwlMode; 41 | return g_isTwlMode; 42 | } 43 | 44 | MK_EXTERN_C_END 45 | 46 | //! @} 47 | -------------------------------------------------------------------------------- /include/calico/nds/timer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../gba/timer.h" 5 | -------------------------------------------------------------------------------- /include/calico/nds/touch.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #if !defined(__NDS__) 5 | #error "This header file is only for NDS" 6 | #endif 7 | 8 | #include "../types.h" 9 | 10 | /*! @addtogroup touch 11 | @{ 12 | */ 13 | 14 | MK_EXTERN_C_START 15 | 16 | //! Touchscreen state 17 | typedef struct MK_STRUCT_ALIGN(4) TouchData { 18 | u16 px; //!< Touch X position in pixels 19 | u16 py; //!< Touch Y position in pixels 20 | u16 rawx; //!< Raw 12-bit touch X position reported by the ADC 21 | u16 rawy; //!< Raw 12-bit touch Y position reported by the ADC 22 | } TouchData; 23 | 24 | #if defined(ARM7) 25 | void touchInit(void); 26 | void touchStartServer(unsigned lyc, u8 thread_prio); 27 | void touchLoadCalibration(void); 28 | #endif 29 | 30 | /*! @brief Obtains the current state of the touchscreen 31 | @param[out] out @ref TouchData structure to fill 32 | @return true if the screen is being touched, false otherwise 33 | */ 34 | bool touchRead(TouchData* out); 35 | 36 | MK_EXTERN_C_END 37 | 38 | //! @} 39 | -------------------------------------------------------------------------------- /include/calico/system/condvar.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "thread.h" 6 | #include "mutex.h" 7 | 8 | /*! @addtogroup sync 9 | @{ 10 | */ 11 | /*! @name Condition variable 12 | Synchronization primitive used alongside a @ref Mutex to block one or more 13 | threads until a different thread both modifies a shared variable (i.e. the 14 | @em condition) and notifies the condition variable. 15 | @{ 16 | */ 17 | 18 | MK_EXTERN_C_START 19 | 20 | //! Condition variable object 21 | typedef struct CondVar { 22 | u8 dummy; //!< @private 23 | } CondVar; 24 | 25 | //! Wakes up at most one thread waiting on condition variable @p cv. 26 | void condvarSignal(CondVar* cv); 27 | 28 | //! Wakes up all threads waiting on condition variable @p cv. 29 | void condvarBroadcast(CondVar* cv); 30 | 31 | //! @brief Blocks the current thread until the condition variable @p cv is awakened. 32 | //! The Mutex @p m is atomically unlocked/locked during the wait. 33 | void condvarWait(CondVar* cv, Mutex* m); 34 | 35 | MK_EXTERN_C_END 36 | 37 | //! @} 38 | 39 | //! @} 40 | -------------------------------------------------------------------------------- /include/calico/system/dietprint.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include "../types.h" 6 | 7 | /*! @addtogroup system 8 | @{ 9 | */ 10 | 11 | /*! @name Lightweight print formatting 12 | 13 | Calico provides a lightweight alternative to printf for use in memory 14 | constrained scenarios such as the ARM7. @ref dietPrint supports all 15 | features of standard C format specifier syntax, with the following 16 | exceptions: 17 | 18 | - `%%o` (octal) and `%%n` (number of characters written) are not supported. 19 | - `%%ls` and `%%lc` ("wide" strings and characters) are not supported. 20 | - Floating point arguments are not supported. 21 | - Decimal 64-bit integers larger than `UINT32_MAX` are not supported. 22 | - POSIX-style argument reordering (e.g. `%1$s`) is not supported. 23 | 24 | @{ 25 | */ 26 | 27 | MK_EXTERN_C_START 28 | 29 | /*! @brief Printing callback used by @ref dietPrint. 30 | @note The incoming @p buf may be NULL, in which case the callback is 31 | expected to output the number of space characters given by @p size. 32 | */ 33 | typedef void (*DietPrintFn)(const char* buf, size_t size); 34 | 35 | /*! @brief Sets @p fn as the current printing callback. 36 | @warning This function changes global state, and as such is not thread safe. 37 | */ 38 | MK_INLINE void dietPrintSetFunc(DietPrintFn fn) 39 | { 40 | extern DietPrintFn g_dietPrintFn; 41 | g_dietPrintFn = fn; 42 | } 43 | 44 | //! @brief Prints the specified formatted text (works like printf). 45 | void dietPrint(const char* fmt, ...) __attribute__((format(printf, 1, 2))); 46 | 47 | //! @brief Prints the specified formatted text (works like vprintf). 48 | void dietPrintV(const char* fmt, va_list va) __attribute__((format(printf, 1, 0))); 49 | 50 | MK_EXTERN_C_END 51 | 52 | //! @} 53 | 54 | //! @} 55 | -------------------------------------------------------------------------------- /include/calico/system/irq.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | 6 | #if defined(__GBA__) 7 | #include "../gba/irq.h" 8 | #elif defined(__NDS__) 9 | #include "../nds/irq.h" 10 | #else 11 | #error "Unsupported platform." 12 | #endif 13 | 14 | /*! @addtogroup irq 15 | @{ 16 | */ 17 | 18 | MK_EXTERN_C_START 19 | 20 | /*! @brief Interrupt service routine (ISR) function pointer datatype 21 | @note ISRs execute in a special mode of the ARM CPU called interrupt mode, 22 | or IRQ mode for short. This mode has its own dedicated stack independent of any 23 | currently running thread. Interrupts are disabled while executing ISRs, meaning 24 | they are unable to nest. Please exercise caution when writing an interrupt handler. 25 | Do **not** call threading functions, C standard library functions, or access thread 26 | local variables from within ISR mode. As an exception, it is possible to call 27 | threadUnblock\* functions or @ref mailboxTrySend in order to wake up threads in 28 | response to hardware events. These threads should be the ones in charge of performing 29 | any heavy processing, instead of doing it from within the ISR. 30 | */ 31 | typedef void (*IrqHandler)(void); 32 | 33 | //! @private 34 | extern volatile IrqMask __irq_flags; 35 | 36 | /*! @brief Assigns an interrupt service routine (ISR) to one or more interrupts 37 | @param[in] mask Bitmask of interrupts to which assign the ISR 38 | @param[in] handler Pointer to ISR (see @ref IrqHandler) 39 | @note There can only be one ISR assigned to a given interrupt at a time. 40 | Assigning a different routine to the same interrupt will replace the previous one. 41 | */ 42 | void irqSet(IrqMask mask, IrqHandler handler); 43 | 44 | //! Removes all ISRs registered for all interrupts in the given @p mask 45 | MK_INLINE void irqClear(IrqMask mask) 46 | { 47 | irqSet(mask, NULL); 48 | } 49 | 50 | //! Enables all interrupts selected by the given @p mask 51 | MK_INLINE void irqEnable(IrqMask mask) 52 | { 53 | IrqState st = irqLock(); 54 | REG_IE |= mask; 55 | irqUnlock(st); 56 | } 57 | 58 | //! Disables all interrupts selected by the given @p mask 59 | MK_INLINE void irqDisable(IrqMask mask) 60 | { 61 | IrqState st = irqLock(); 62 | REG_IE &= ~mask; 63 | irqUnlock(st); 64 | } 65 | 66 | #if MK_IRQ_NUM_HANDLERS > 32 67 | 68 | //! @private 69 | extern volatile IrqMask __irq_flags2; 70 | 71 | //! Like @ref irqSet, but for the extended DSi ARM7 interrupt controller 72 | void irqSet2(IrqMask mask, IrqHandler handler); 73 | 74 | //! Like @ref irqClear, but for the extended DSi ARM7 interrupt controller 75 | MK_INLINE void irqClear2(IrqMask mask) 76 | { 77 | irqSet2(mask, NULL); 78 | } 79 | 80 | //! Like @ref irqEnable, but for the extended DSi ARM7 interrupt controller 81 | MK_INLINE void irqEnable2(IrqMask mask) 82 | { 83 | IrqState st = irqLock(); 84 | REG_IE2 |= mask; 85 | irqUnlock(st); 86 | } 87 | 88 | //! Like @ref irqDisable, but for the extended DSi ARM7 interrupt controller 89 | MK_INLINE void irqDisable2(IrqMask mask) 90 | { 91 | IrqState st = irqLock(); 92 | REG_IE2 &= ~mask; 93 | irqUnlock(st); 94 | } 95 | 96 | #endif 97 | 98 | MK_EXTERN_C_END 99 | 100 | //! @} 101 | -------------------------------------------------------------------------------- /include/calico/system/mailbox.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "thread.h" 6 | 7 | /*! @addtogroup sync 8 | @{ 9 | */ 10 | /*! @name Mailbox 11 | Synchronization primitive that provides a way to transfer messages between 12 | threads. Messages are delived in the same order they are sent (i.e. FIFO). 13 | @{ 14 | */ 15 | 16 | MK_EXTERN_C_START 17 | 18 | //! Mailbox object 19 | typedef struct Mailbox { 20 | u32* slots; //!< @private 21 | u8 num_slots; //!< @private 22 | u8 cur_slot; //!< @private 23 | u8 pending_slots; //!< @private 24 | u8 send_waiters : 4; //!< @private 25 | u8 recv_waiters : 4; //!< @private 26 | } Mailbox; 27 | 28 | /*! @brief Prepares a Mailbox object @p mb for use 29 | @param[in] slots Storage space for messages 30 | @param[in] num_slots Capacity of the storage space in words 31 | @note The storage space must remain valid throughout the lifetime of the Mailbox object. 32 | */ 33 | MK_INLINE void mailboxPrepare(Mailbox* mb, u32* slots, unsigned num_slots) 34 | { 35 | mb->slots = slots; 36 | mb->num_slots = num_slots; 37 | mb->cur_slot = 0; 38 | mb->pending_slots = 0; 39 | } 40 | 41 | //! @brief Asynchronously sends a @p message to Mailbox @p mb. 42 | //! Returns true on success, false when the mailbox is full. 43 | bool mailboxTrySend(Mailbox* mb, u32 message); 44 | 45 | //! @brief Asynchronously receives a message from Mailbox @p mb. 46 | bool mailboxTryRecv(Mailbox* mb, u32* out); 47 | 48 | //! @brief Receives a message from Mailbox @p mb, blocking the current thread if empty. 49 | u32 mailboxRecv(Mailbox* mb); 50 | 51 | MK_EXTERN_C_END 52 | 53 | //! @} 54 | 55 | //! @} 56 | -------------------------------------------------------------------------------- /include/calico/system/mutex.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "thread.h" 6 | 7 | /*! @addtogroup sync 8 | @{ 9 | */ 10 | /*! @name Mutex 11 | The quintessential synchronization primitive, used to protect shared data 12 | from being simultaneously accessed by multiple threads. Calico implements 13 | priority inheritance for mutexes, which means that if a higher priority 14 | thread is waiting on a mutex held by a lower priority thread; said lower 15 | thread temporarily inherits the priority of the higher thread, so that the 16 | lower thread gets a chance to run and does not result in priority inversion. 17 | @{ 18 | */ 19 | 20 | MK_EXTERN_C_START 21 | 22 | //! @brief Mutex object 23 | typedef struct Mutex { 24 | Thread* owner; //!< @private 25 | } Mutex; 26 | 27 | /*! @brief Recursive mutex object 28 | 29 | Recursive mutexes can be locked multiple times by the same thread. 30 | It is necessary to balance calls to @ref rmutexLock and @ref rmutexUnlock, 31 | or else the mutex is never released. 32 | */ 33 | typedef struct RMutex { 34 | Mutex mutex; //!< @private 35 | u32 counter; //!< @private 36 | } RMutex; 37 | 38 | //! @brief Returns true if @p m is held by the current thread 39 | MK_INLINE bool mutexIsLockedByCurrentThread(Mutex* m) 40 | { 41 | return m->owner == threadGetSelf(); 42 | } 43 | 44 | //! @brief Locks the Mutex @p m 45 | void mutexLock(Mutex* m); 46 | 47 | /*! @brief Unlocks the Mutex @p m 48 | @warning @p m **must** be held by the current thread 49 | */ 50 | void mutexUnlock(Mutex* m); 51 | 52 | //! @brief Locks the RMutex @p m 53 | MK_INLINE void rmutexLock(RMutex* m) 54 | { 55 | if (mutexIsLockedByCurrentThread(&m->mutex)) { 56 | m->counter ++; 57 | } else { 58 | mutexLock(&m->mutex); 59 | m->counter = 1; 60 | } 61 | } 62 | 63 | //! @brief Unlocks the RMutex @p m 64 | MK_INLINE void rmutexUnlock(RMutex* m) 65 | { 66 | if (!--m->counter) { 67 | mutexUnlock(&m->mutex); 68 | } 69 | } 70 | 71 | MK_EXTERN_C_END 72 | 73 | //! @} 74 | 75 | //! @} 76 | -------------------------------------------------------------------------------- /include/calico/system/sysclock.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | 5 | /*! @addtogroup system 6 | @{ 7 | */ 8 | 9 | #if defined(__GBA__) 10 | #define SYSTEM_CLOCK 0x1000000 //!< GBA system bus speed: exactly 2^24 Hz ~= 16.78 MHz 11 | #elif defined(__NDS__) 12 | #define SYSTEM_CLOCK 0x1FF61FE //!< NDS system bus speed: approximately 33.51 MHz 13 | #else 14 | #error "This header file is only for GBA and NDS" 15 | #endif 16 | 17 | //! @} 18 | -------------------------------------------------------------------------------- /include/calico/system/tick.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include "../types.h" 5 | #include "sysclock.h" 6 | 7 | /*! @addtogroup tick 8 | @{ 9 | */ 10 | 11 | //! Frequency in Hz of the system timer used for counting ticks 12 | #define TICK_FREQ (SYSTEM_CLOCK/64) 13 | 14 | MK_EXTERN_C_START 15 | 16 | // Forward declaration 17 | typedef struct TickTask TickTask; 18 | 19 | /*! @brief Tick task callback function 20 | @param[in] t Pointer to @ref TickTask object that triggered the event 21 | @note The callback runs in IRQ mode - exercise caution! 22 | See @ref IrqHandler for more details on how to write IRQ mode handlers. 23 | */ 24 | typedef void (* TickTaskFn)(TickTask* t); 25 | 26 | //! Tick task object, representing a scheduled timed event 27 | struct TickTask { 28 | TickTask* next; //!< @private 29 | u32 target; //!< @private 30 | u32 period; //!< @private 31 | TickTaskFn fn; //!< @private 32 | }; 33 | 34 | //! Converts microseconds (@p us) to system ticks 35 | MK_CONSTEXPR u32 ticksFromUsec(u32 us) 36 | { 37 | return (us * (u64)TICK_FREQ) / 1000000; 38 | } 39 | 40 | //! Converts frequency in @p hz to a period measured in system ticks 41 | MK_CONSTEXPR u32 ticksFromHz(u32 hz) 42 | { 43 | return (TICK_FREQ + hz/2) / hz; 44 | } 45 | 46 | //! @private 47 | void tickInit(void); 48 | 49 | //! Returns the current value of the system tick counter 50 | u64 tickGetCount(void); 51 | 52 | /*! @brief Configures and starts a tick task @p t 53 | @param[in] fn Event callback to invoke when the tick task needs to run. 54 | @param[in] delay_ticks Time to wait (in system ticks) for the first invocation of the task. 55 | @param[in] period_ticks For periodic tasks, specifies the interval (in system ticks) between invocations. Pass 0 for one-shot tasks. 56 | @note Use @ref ticksFromUsec and @ref ticksFromHz to convert from microseconds/Hz into system ticks 57 | */ 58 | void tickTaskStart(TickTask* t, TickTaskFn fn, u32 delay_ticks, u32 period_ticks); 59 | 60 | //! Stops the tick task @p t 61 | void tickTaskStop(TickTask* t); 62 | 63 | MK_EXTERN_C_END 64 | 65 | //! @} 66 | -------------------------------------------------------------------------------- /share/ds7.specs: -------------------------------------------------------------------------------- 1 | %include 2 | 3 | *link: 4 | + -dT ds7.ld --gc-sections --nmagic --no-warn-rwx-segments 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s --require-defined=main 8 | -------------------------------------------------------------------------------- /share/ds9-legacy.specs: -------------------------------------------------------------------------------- 1 | %include 2 | 3 | *link: 4 | + -dT ds9-legacy.ld --gc-sections --nmagic --no-warn-rwx-segments --use-blx 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s --require-defined=main 8 | -------------------------------------------------------------------------------- /share/ds9.specs: -------------------------------------------------------------------------------- 1 | %include 2 | 3 | *link: 4 | + -dT ds9.ld --gc-sections --nmagic --no-warn-rwx-segments --use-blx 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s --require-defined=main 8 | -------------------------------------------------------------------------------- /share/gba-cart.specs: -------------------------------------------------------------------------------- 1 | %include 2 | 3 | *link: 4 | + -dT gba-cart.ld --gc-sections --nmagic --no-warn-rwx-segments 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s --require-defined=main 8 | -------------------------------------------------------------------------------- /share/gba-mb.specs: -------------------------------------------------------------------------------- 1 | %include 2 | 3 | *link: 4 | + -dT gba-mb.ld --gc-sections --nmagic --no-warn-rwx-segments 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s --require-defined=main 8 | -------------------------------------------------------------------------------- /share/nds-icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/calico/6d437b7651ba5c95036a90f534c30079bb926945/share/nds-icon.bmp -------------------------------------------------------------------------------- /source/arm/arm-cache.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | FUNC_START32 armDrainWriteBuffer 7 | 8 | mov r0, #0 9 | mcr p15, 0, r0, c7, c10, 4 10 | bx lr 11 | 12 | FUNC_END 13 | 14 | FUNC_START32 armDCacheFlushAll 15 | 16 | @ Flush all cache lines 17 | mov r1, #0 18 | .Ldfa_clean_way: 19 | mov r0, #0 20 | .Ldfa_clean_line: 21 | orr r2, r1, r0 22 | mcr p15, 0, r2, c7, c14, 2 @ Clean+Invalidate DCache entry by Set/Way 23 | add r0, r0, #ARM_CACHE_LINE_SZ 24 | cmp r0, #ARM_DCACHE_SZ/ARM_DCACHE_WAYS 25 | bne .Ldfa_clean_line 26 | adds r1, r1, #(1 << (32 - ARM_DCACHE_WAYS_LOG2)) 27 | bne .Ldfa_clean_way 28 | 29 | b armDrainWriteBuffer 30 | 31 | FUNC_END 32 | 33 | FUNC_START32 armDCacheFlush 34 | 35 | add r1, r0, r1 36 | bic r0, r0, #(ARM_CACHE_LINE_SZ-1) 37 | 0: mcr p15, 0, r0, c7, c14, 1 @ Clean+Invalidate DCache entry by MVA 38 | add r0, r0, #ARM_CACHE_LINE_SZ 39 | cmp r0, r1 40 | bmi 0b 41 | 42 | b armDrainWriteBuffer 43 | 44 | FUNC_END 45 | 46 | 47 | FUNC_START32 armDCacheInvalidate 48 | 49 | add r1, r0, r1 50 | bic r0, r0, #(ARM_CACHE_LINE_SZ-1) 51 | 0: mcr p15, 0, r0, c7, c6, 1 @ Invalidate DCache entry by MVA 52 | add r0, r0, #ARM_CACHE_LINE_SZ 53 | cmp r0, r1 54 | bmi 0b 55 | 56 | bx lr 57 | 58 | FUNC_END 59 | 60 | FUNC_START32 armICacheInvalidateAll 61 | 62 | mov r0, #0 63 | mcr p15, 0, r0, c7, c5, 0 64 | bx lr 65 | 66 | FUNC_END 67 | 68 | FUNC_START32 armICacheInvalidate 69 | 70 | add r1, r0, r1 71 | bic r0, r0, #(ARM_CACHE_LINE_SZ-1) 72 | 0: mcr p15, 0, r0, c7, c5, 1 @ Invalidate ICache entry by MVA 73 | add r0, r0, #ARM_CACHE_LINE_SZ 74 | cmp r0, r1 75 | bls 0b 76 | 77 | bx lr 78 | 79 | FUNC_END 80 | -------------------------------------------------------------------------------- /source/arm/arm-context.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | .global armContextLoadFromSvc 7 | .type armContextLoadFromSvc, %function 8 | 9 | @--------------------------------------------------------------------------------- 10 | FUNC_START32 armContextSave 11 | @--------------------------------------------------------------------------------- 12 | mrs r12, cpsr 13 | str r2, [r0], #15*4 @ store a non-null value into r0 (r1-r3 never saved) 14 | bic r3, r12, #(ARM_PSR_I | ARM_PSR_F) 15 | adr r2, 1f 16 | orr r3, r3, r1 17 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_SVC) 18 | stmdb r0, {r4-r14}^ @ save r4-r14 -- XX: r12 is saved, even though it's volatile 19 | stmia r0, {r2,r3,sp} @ r2=pc, r3=psr, sp=sp_svc 20 | msr cpsr_c, r12 21 | mov r0, #0 22 | 1: bx lr 23 | FUNC_END 24 | 25 | @--------------------------------------------------------------------------------- 26 | FUNC_START32 armContextLoad 27 | @--------------------------------------------------------------------------------- 28 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_SVC) 29 | armContextLoadFromSvc: 30 | ldr lr, [r0, #15*4] 31 | ldr r3, [r0, #16*4] 32 | ldr sp, [r0, #17*4] 33 | msr spsr, r3 34 | ldm r0, {r0-r14}^ 35 | nop @ Architecturally required before accessing a banked reg (pre-ARMv6) 36 | movs pc, lr 37 | FUNC_END 38 | -------------------------------------------------------------------------------- /source/arm/arm-copy-fill.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | FUNC_START32 armCopyMem32 6 | push {r4-r10} @ Not 8-byte aligned 7 | bics r12, r2, #0x1f 8 | beq .LcopyRemainder 9 | add r12, r0, r12 10 | 11 | 1: ldm r1!, {r3-r10} 12 | stm r0!, {r3-r10} 13 | cmp r12, r0 14 | bne 1b 15 | 16 | .LcopyRemainder: 17 | tst r2, #0x10 18 | ldmne r1!, {r4-r7} 19 | stmne r0!, {r4-r7} 20 | 21 | tst r2, #0x08 22 | ldmne r1!, {r4-r5} 23 | stmne r0!, {r4-r5} 24 | 25 | tst r2, #0x04 26 | ldmne r1!, {r4} 27 | stmne r0!, {r4} 28 | 29 | pop {r4-r10} 30 | bx lr 31 | FUNC_END 32 | 33 | FUNC_START32 armFillMem32 34 | push {r4-r9} 35 | bics r12, r2, #0x1f 36 | 37 | @ This is super dumb 38 | mov r4, r1 39 | mov r5, r1 40 | mov r6, r1 41 | mov r7, r1 42 | 43 | beq .LfillRemainder 44 | add r12, r0, r12 45 | 46 | @ This is also super dumb 47 | mov r3, r1 48 | mov r8, r1 49 | mov r9, r1 50 | 51 | 1: stm r0!, {r1,r3-r9} 52 | cmp r12, r0 53 | bne 1b 54 | 55 | .LfillRemainder: 56 | tst r2, #0x10 57 | stmne r0!, {r4-r7} 58 | 59 | tst r2, #0x08 60 | stmne r0!, {r4-r5} 61 | 62 | tst r2, #0x04 63 | stmne r0!, {r4} 64 | 65 | pop {r4-r9} 66 | bx lr 67 | FUNC_END 68 | -------------------------------------------------------------------------------- /source/arm/arm-readtp.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | @ Contrary to the AAPCS32, __aeabi_read_tp is NOT allowed to clobber r1-r3. 6 | @ As a result of this, we cannot use C to implement this function. 7 | @ The corresponding C pseudocode for the following ASM is: 8 | 9 | @ void* __aeabi_read_tp(void) { 10 | @ return threadGetSelf()->tp; 11 | @ } 12 | 13 | FUNC_START32 __aeabi_read_tp 14 | ldr r0, =__sched_state 15 | ldr r0, [r0, #0] @ ThrSchedState::cur 16 | ldr r0, [r0, #18*4] @ Thread::tp 17 | bx lr 18 | FUNC_END 19 | -------------------------------------------------------------------------------- /source/arm/arm-shims-mpu.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | #define _MPU_AUTOGEN(_name, _reg) \ 6 | extern u32 armMpuGet##_name(void); \ 7 | extern void armMpuSet##_name(u32 value); 8 | 9 | _MPU_ACCESSORS 10 | -------------------------------------------------------------------------------- /source/arm/arm-shims.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | extern u32 armGetCpsr(void); 6 | extern void armSetCpsrC(u32 value); 7 | extern u32 armGetSpsr(void); 8 | extern void armSetSpsr(u32 value); 9 | extern u32 armSwapWord(u32 value, vu32* addr); 10 | extern u8 armSwapByte(u8 value, vu8* addr); 11 | 12 | #if __ARM_ARCH >= 5 13 | extern void armWaitForIrq(void); 14 | extern u32 armGetCp15Cr(void); 15 | extern void armSetCp15Cr(u32 value); 16 | #endif 17 | 18 | extern ArmIrqState armIrqLockByPsr(void); 19 | extern void armIrqUnlockByPsr(ArmIrqState st); 20 | -------------------------------------------------------------------------------- /source/dev/ar6k/common.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | 8 | //#define AR6K_DEBUG 9 | 10 | #ifdef AR6K_DEBUG 11 | #include 12 | #else 13 | #define dietPrint(...) ((void)0) 14 | #endif 15 | 16 | typedef struct Ar6kIrqProcRegs { 17 | u8 host_int_status; 18 | u8 cpu_int_status; 19 | u8 error_int_status; 20 | u8 counter_int_status; 21 | u8 mbox_frame; 22 | u8 rx_lookahead_valid; 23 | u8 _pad[2]; 24 | u32 rx_lookahead[2]; 25 | } Ar6kIrqProcRegs; 26 | 27 | // Internal API 28 | bool _ar6kDevSetIrqEnable(Ar6kDev* dev, bool enable); 29 | bool _ar6kDevPollMboxMsgRecv(Ar6kDev* dev, u32* lookahead, unsigned attempts); 30 | bool _ar6kDevSendPacket(Ar6kDev* dev, const void* pktmem, size_t pktsize); 31 | bool _ar6kDevRecvPacket(Ar6kDev* dev, void* pktmem, size_t pktsize); 32 | 33 | bool _ar6kHtcRecvMessagePendingHandler(Ar6kDev* dev); 34 | bool _ar6kHtcSendPacket(Ar6kDev* dev, Ar6kHtcEndpointId epid, NetBuf* pPacket); 35 | 36 | void _ar6kWmiEventRx(Ar6kDev* dev, NetBuf* pPacket); 37 | void _ar6kWmiDataRx(Ar6kDev* dev, Ar6kHtcSrvId srvid, NetBuf* pPacket); 38 | -------------------------------------------------------------------------------- /source/dev/dldi_stub.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | .section .dldi, "ax", %progbits 7 | .align 2 8 | .global __dldi_start 9 | 10 | __dldi_start: 11 | @ Header magic 12 | .word DLDI_MAGIC_VAL 13 | .asciz DLDI_MAGIC_STRING 14 | 15 | @ Properties 16 | .byte 1 @ version_num 17 | .byte DLDI_SIZE_MAX @ driver_sz_log2 18 | .byte 0 @ fix_flags 19 | .byte DLDI_SIZE_MAX @ alloc_sz_log2 20 | 21 | @ Interface name 22 | 1: .ascii "Default (No interface)" 23 | .space DLDI_FRIENDLY_NAME_LEN - (. - 1b) 24 | 25 | @ Address table 26 | .word __dldi_start @ dldi_start 27 | .word .Ldldi_end @ dldi_end 28 | .word 0 @ glue_start 29 | .word 0 @ glue_end 30 | .word 0 @ got_start 31 | .word 0 @ got_end 32 | .word 0 @ bss_start 33 | .word 0 @ bss_end 34 | 35 | @ Disc interface 36 | .ascii "DLDI" @ io_type 37 | .word 0 @ features 38 | .word .Ldummy_func @ startup 39 | .word .Ldummy_func @ is_inserted 40 | .word .Ldummy_func @ read_sectors 41 | .word .Ldummy_func @ write_sectors 42 | .word .Ldummy_func @ clear_status 43 | .word .Ldummy_func @ shutdown 44 | 45 | .Ldummy_func: 46 | mov r0, #0 47 | bx lr 48 | 49 | .pool 50 | .space DLDI_MAX_ALLOC_SZ - (. - __dldi_start) 51 | .Ldldi_end: 52 | -------------------------------------------------------------------------------- /source/dev/fugu.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | MK_INLINE u32 _fuguSubstitute(FuguState const* state, u32 x) 6 | { 7 | u32 h = state->S[0][x>>24] + state->S[1][(x>>16)&0xff]; 8 | return (h ^ state->S[2][(x>>8)&0xff]) + state->S[3][x&0xff]; 9 | } 10 | 11 | MK_INLINE void _fuguSwap(u32* L, u32* R) 12 | { 13 | u32 temp = *L; 14 | *L = *R; 15 | *R = temp; 16 | } 17 | 18 | void fuguKeySchedule(FuguState* state, const u32* key, unsigned key_num_words) 19 | { 20 | for (unsigned i = 0, p = 0; i < FUGU_NUM_ROUNDS+2; i ++) { 21 | state->P[i] ^= __builtin_bswap32(key[p++]); 22 | if (p>=key_num_words) p = 0; 23 | } 24 | 25 | u32 pad[2] = { 0, 0 }; 26 | u32* out = (u32*)state; 27 | for (unsigned i = 0; i < sizeof(*state)/8; i ++) { 28 | fuguEncrypt(state, pad); 29 | out[0] = pad[1]; 30 | out[1] = pad[0]; 31 | out += 2; 32 | } 33 | } 34 | 35 | void fuguEncrypt(FuguState const* state, u32 buf[2]) 36 | { 37 | u32 L = buf[1]; 38 | u32 R = buf[0]; 39 | 40 | for (unsigned i = 0; i < FUGU_NUM_ROUNDS; i ++) { 41 | L ^= state->P[i]; 42 | R ^= _fuguSubstitute(state, L); 43 | _fuguSwap(&L, &R); 44 | } 45 | 46 | buf[0] = L ^ state->P[FUGU_NUM_ROUNDS+0]; 47 | buf[1] = R ^ state->P[FUGU_NUM_ROUNDS+1]; 48 | } 49 | 50 | void fuguDecrypt(FuguState const* state, u32 buf[2]) 51 | { 52 | u32 L = buf[1]; 53 | u32 R = buf[0]; 54 | 55 | for (unsigned i = FUGU_NUM_ROUNDS+1; i > 1; i --) { 56 | L ^= state->P[i]; 57 | R ^= _fuguSubstitute(state, L); 58 | _fuguSwap(&L, &R); 59 | } 60 | 61 | buf[0] = L ^ state->P[1]; 62 | buf[1] = R ^ state->P[0]; 63 | } 64 | -------------------------------------------------------------------------------- /source/dev/mwl/mwl_calib.16.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "common.h" 4 | #include 5 | #include 6 | 7 | alignas(2) u8 g_mwlCalibData[MWL_CALIB_NVRAM_MAX_SZ]; 8 | 9 | bool mwlCalibLoad(void) 10 | { 11 | MwlCalibData* calib = mwlGetCalibData(); 12 | 13 | // Check if calibration data is already loaded 14 | if (calib->crc16 != 0) { 15 | dietPrint("[MWL] Calib already loaded\n"); 16 | return true; 17 | } 18 | 19 | // Read data from NVRAM 20 | if (!pmReadNvram(g_mwlCalibData, MWL_CALIB_NVRAM_OFFSET, MWL_CALIB_NVRAM_MAX_SZ)) { 21 | dietPrint("[MWL] Calib load fail\n"); 22 | goto _fail; 23 | } 24 | 25 | if (calib->total_len > (MWL_CALIB_NVRAM_MAX_SZ-offsetof(MwlCalibData, total_len))) { 26 | dietPrint("[MWL] Bad calib size\n"); 27 | goto _fail; 28 | } 29 | 30 | if (calib->crc16 != svcGetCRC16(0, &calib->total_len, calib->total_len)) { 31 | dietPrint("[MWL] Calib CRC fail\n"); 32 | goto _fail; 33 | } 34 | 35 | dietPrint("[MWL] Calib v%u, RF type %u\n", calib->version, calib->rf_type); 36 | dietPrint("[MWL] MAC %02X:%02X:%02X:%02X:%02X:%02X\n", 37 | calib->mac_addr[0]&0xff, calib->mac_addr[0]>>8, 38 | calib->mac_addr[1]&0xff, calib->mac_addr[1]>>8, 39 | calib->mac_addr[2]&0xff, calib->mac_addr[2]>>8); 40 | 41 | calib->crc16 = 1; 42 | return true; 43 | 44 | _fail: 45 | calib->crc16 = 0; 46 | return false; 47 | } 48 | -------------------------------------------------------------------------------- /source/dev/mwl/mwl_dev_bbp_rf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "common.h" 4 | 5 | MK_INLINE void _mwlBbpBusyWait(void) 6 | { 7 | while (MWL_REG(W_BB_BUSY) & 1); 8 | } 9 | 10 | MK_INLINE void _mwlRfBusyWait(void) 11 | { 12 | while (MWL_REG(W_RF_BUSY) & 1); 13 | } 14 | 15 | unsigned _mwlBbpRead(unsigned reg) 16 | { 17 | MWL_REG(W_BB_CNT) = 0x6000 | reg; 18 | _mwlBbpBusyWait(); 19 | unsigned value = MWL_REG(W_BB_READ); 20 | //dietPrint("[MWL] rd BBP[0x%.2x] = 0x%.2x\n", reg, value); 21 | return value; 22 | } 23 | 24 | void _mwlBbpWrite(unsigned reg, unsigned value) 25 | { 26 | MWL_REG(W_BB_WRITE) = value; 27 | MWL_REG(W_BB_CNT) = 0x5000 | reg; 28 | _mwlBbpBusyWait(); 29 | //dietPrint("[MWL] wr BBP[0x%.2x] = 0x%.2x\n", reg, value); 30 | } 31 | 32 | void _mwlRfCmd(u32 cmd) 33 | { 34 | MWL_REG(W_RF_DATA1) = cmd; 35 | MWL_REG(W_RF_DATA2) = cmd>>16; 36 | _mwlRfBusyWait(); 37 | //dietPrint("[MWL] RF cmd %.8lx\n", cmd); 38 | } 39 | -------------------------------------------------------------------------------- /source/dev/mwl/mwl_dev_irq.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "common.h" 4 | #include 5 | 6 | static ThrListNode s_mwlTaskQueue; 7 | 8 | void _mwlPushTaskImpl(u32 mask) 9 | { 10 | ArmIrqState st = armIrqLockByPsr(); 11 | 12 | u32 cur_mask = s_mwlState.task_mask; 13 | u32 new_mask = mask | cur_mask; 14 | 15 | if_likely (new_mask != cur_mask) { 16 | s_mwlState.task_mask = new_mask; 17 | if_likely (s_mwlTaskQueue.next != NULL) { 18 | threadUnblockOneByValue(&s_mwlTaskQueue, 0); 19 | } 20 | } 21 | 22 | armIrqUnlockByPsr(st); 23 | } 24 | 25 | MwlTask _mwlPopTask(void) 26 | { 27 | ArmIrqState st = armIrqLockByPsr(); 28 | 29 | u32 mask; 30 | while (!(mask = s_mwlState.task_mask)) { 31 | threadBlock(&s_mwlTaskQueue, 0); 32 | } 33 | 34 | unsigned i; 35 | for (i = 0; i < 32; i ++) { 36 | unsigned bit = 1U< s_mwlState.beacon_loss_thr) { 61 | s_mwlState.has_beacon_sync = 0; 62 | s_mwlState.beacon_loss_cnt = 0; 63 | s_mwlState.beacon_loss_thr = 0; 64 | _mwlPushTask(MwlTask_BeaconLost); 65 | } 66 | } 67 | 68 | static void _mwlIrqTbttGuest(void) 69 | { 70 | MWL_REG(W_POWER_TX) |= 1; 71 | 72 | // XX: Power saving mode handling for listen interval/DTIM counters goes here 73 | 74 | // Reenable TX queues (HW disables them on TBTT IRQ) 75 | MWL_REG(W_TXREQ_SET) = 0xd; 76 | } 77 | 78 | static void _mwlIrqRxEnd(void) 79 | { 80 | s_mwlState.rx_wrcsr = MWL_REG(W_RXBUF_WRCSR); 81 | _mwlPushTask(MwlTask_RxEnd); 82 | } 83 | 84 | static void _mwlIrqTxEnd(void) 85 | { 86 | _mwlPushTask(MwlTask_TxEnd); 87 | } 88 | 89 | void _mwlIrqHandler(void) 90 | { 91 | for (;;) { 92 | unsigned cur_irq = MWL_REG(W_IE) & MWL_REG(W_IF); 93 | if (!cur_irq) { 94 | break; 95 | } 96 | MWL_REG(W_IF) = cur_irq; 97 | 98 | if (cur_irq & W_IRQ_TX_START) { 99 | // 100 | } 101 | 102 | if (cur_irq & W_IRQ_RX_START) { 103 | // 104 | } 105 | 106 | if (cur_irq & W_IRQ_PRE_TBTT) { 107 | _mwlIrqPreTbtt(); 108 | } 109 | 110 | if (cur_irq & W_IRQ_TBTT) { 111 | if (s_mwlState.mode >= MwlMode_LocalGuest) { 112 | _mwlIrqTbttGuest(); 113 | } 114 | } 115 | 116 | if (cur_irq & W_IRQ_POST_TBTT) { 117 | // 118 | } 119 | 120 | if (cur_irq & W_IRQ_TX_ERR) { 121 | // 122 | } 123 | 124 | if (cur_irq & W_IRQ_RX_CNT_INC) { 125 | // 126 | } 127 | 128 | if (cur_irq & W_IRQ_RX_END) { 129 | _mwlIrqRxEnd(); 130 | } 131 | 132 | if (cur_irq & W_IRQ_RX_CNT_OVF) { 133 | // 134 | } 135 | 136 | if (cur_irq & W_IRQ_TX_END) { 137 | _mwlIrqTxEnd(); 138 | } 139 | 140 | if (cur_irq & W_IRQ_MP_END) { 141 | // 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /source/dev/mwl/mwl_dev_misc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "common.h" 4 | 5 | bool mwlDevWlanToDix(NetBuf* pPacket) 6 | { 7 | WlanMacHdr* dot11hdr = netbufPopHeaderType(pPacket, WlanMacHdr); 8 | if (!dot11hdr) { 9 | return false; // shouldn't happen 10 | } 11 | 12 | NetLlcSnapHdr* llcsnap = netbufPopHeaderType(pPacket, NetLlcSnapHdr); 13 | if (!llcsnap) { 14 | return false; // shouldn't happen 15 | } 16 | 17 | NetMacHdr dix; 18 | dix.len_or_ethertype_be = llcsnap->ethertype_be; 19 | 20 | if (dot11hdr->fc.to_ds) { 21 | __builtin_memcpy(dix.dst_mac, dot11hdr->xtra_addr, 6); 22 | } else { 23 | __builtin_memcpy(dix.dst_mac, dot11hdr->rx_addr, 6); 24 | } 25 | 26 | if (dot11hdr->fc.from_ds) { 27 | __builtin_memcpy(dix.src_mac, dot11hdr->xtra_addr, 6); 28 | } else { 29 | __builtin_memcpy(dix.src_mac, dot11hdr->tx_addr, 6); 30 | } 31 | 32 | *netbufPushHeaderType(pPacket, NetMacHdr) = dix; 33 | return true; 34 | } 35 | 36 | bool mwlDevDixToWlan(NetBuf* pPacket) 37 | { 38 | NetMacHdr* pDix = netbufPopHeaderType(pPacket, NetMacHdr); 39 | if (!pDix) { 40 | return false; // shouldn't happen 41 | } 42 | 43 | NetMacHdr dix = *pDix; 44 | NetLlcSnapHdr* llcsnap = netbufPushHeaderType(pPacket, NetLlcSnapHdr); 45 | if (!llcsnap) { 46 | return false; // shouldn't happen 47 | } 48 | 49 | // Fill in LLC-SNAP header 50 | llcsnap->dsap = 0xaa; 51 | llcsnap->ssap = 0xaa; 52 | llcsnap->control = 0x03; 53 | llcsnap->oui[0] = 0; 54 | llcsnap->oui[1] = 0; 55 | llcsnap->oui[2] = 0; 56 | llcsnap->ethertype_be = dix.len_or_ethertype_be; 57 | 58 | WlanMacHdr* dot11hdr = netbufPushHeaderType(pPacket, WlanMacHdr); 59 | if (!dot11hdr) { 60 | return false; // shouldn't happen 61 | } 62 | 63 | // Fill in 802.11 header 64 | dot11hdr->fc.value = 0; 65 | dot11hdr->fc.type = WlanFrameType_Data; 66 | dot11hdr->fc.to_ds = 1; 67 | dot11hdr->fc.wep = s_mwlState.wep_enabled; 68 | dot11hdr->duration = 0; 69 | __builtin_memcpy(dot11hdr->rx_addr, s_mwlState.bssid, 6); 70 | __builtin_memcpy(dot11hdr->tx_addr, dix.src_mac, 6); 71 | __builtin_memcpy(dot11hdr->xtra_addr, dix.dst_mac, 6); 72 | dot11hdr->sc.value = 0; 73 | 74 | return true; 75 | } 76 | -------------------------------------------------------------------------------- /source/gba/bios.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | .macro BIOSFUNC id, name 6 | FUNC_START16 svc\name 7 | svc \id 8 | bx lr 9 | FUNC_END 10 | .endm 11 | 12 | BIOSFUNC 0x00, SoftReset 13 | BIOSFUNC 0x01, RegisterRamReset 14 | BIOSFUNC 0x02, Halt 15 | BIOSFUNC 0x03, Stop 16 | BIOSFUNC 0x04, IntrWait 17 | BIOSFUNC 0x05, VBlankIntrWait 18 | BIOSFUNC 0x06, Div 19 | BIOSFUNC 0x07, DivArm 20 | BIOSFUNC 0x08, Sqrt 21 | BIOSFUNC 0x09, ArcTan 22 | BIOSFUNC 0x0a, ArcTan2 23 | BIOSFUNC 0x0b, CpuSet 24 | BIOSFUNC 0x0c, CpuFastSet 25 | BIOSFUNC 0x0d, GetBiosChecksum 26 | BIOSFUNC 0x0e, BgAffineSet 27 | BIOSFUNC 0x0f, ObjAffineSet 28 | BIOSFUNC 0x10, BitUnpack 29 | BIOSFUNC 0x11, LZ77UncompWram 30 | BIOSFUNC 0x12, LZ77UncompVram 31 | BIOSFUNC 0x13, HuffUncomp 32 | BIOSFUNC 0x14, RLUncompWram 33 | BIOSFUNC 0x15, RLUncompVram 34 | BIOSFUNC 0x16, Diff8bitUnfilterWram 35 | BIOSFUNC 0x17, Diff8bitUnfilterVram 36 | BIOSFUNC 0x18, Diff16bitUnfilter 37 | BIOSFUNC 0x19, SoundBias 38 | BIOSFUNC 0x1f, MidiKey2Freq 39 | BIOSFUNC 0x25, MultiBoot 40 | BIOSFUNC 0x26, HardReset 41 | -------------------------------------------------------------------------------- /source/gba/crt0.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | REFERENCE __newlib_syscalls 9 | 10 | #ifndef MULTIBOOT 11 | FUNC_START32 __gba_start, crt0 12 | #else 13 | FUNC_START32 __gba_start_mb, crt0 14 | #endif 15 | 16 | @ Switch to supervisor mode and disable interrupts 17 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_SVC) 18 | mov r11, #MM_IO 19 | strb r11, [r11, #IO_IME] 20 | 21 | #ifdef MULTIBOOT 22 | @ Check if we are running from ROM 23 | mov r12, #0x08 24 | cmp r12, pc, lsr #24 25 | bne .LinEwram 26 | 27 | @ We are in ROM, so we have to copy ourselves into ewram 28 | mov r0, #0x08000000 29 | mov r1, #0x02000000 30 | mov r2, #(256*1024) 31 | 1: subs r2, #8*4 32 | ldmia r0!, {r3-r10} 33 | stmia r1!, {r3-r10} 34 | bgt 1b 35 | 36 | @ Jump to EWRAM 37 | adr r0, .LinEwram 38 | eor r0, r0, #(0x08000000 ^ 0x02000000) 39 | bx r0 40 | 41 | .LinEwram: 42 | #endif 43 | 44 | @ Set up supervisor mode stack 45 | ldr sp, =__sp_svc 46 | 47 | @ Set up interrupt mode stack 48 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_IRQ) 49 | ldr sp, =__sp_irq 50 | 51 | @ Switch to system mode and load a temporary stack pointer 52 | @ (IMPORTANT because the BIOS switches to the user stack and this gets CLEARED otherwise) 53 | msr cpsr_c, #ARM_PSR_MODE_SYS 54 | ldr sp, =MM_IWRAM + MM_IWRAM_SZ - 0x100 55 | 56 | @ Clear memory 57 | #ifndef MULTIBOOT 58 | mov r0, #0xff @ clear everything 59 | #else 60 | mov r0, #0xfe @ clear everything except for ewram 61 | #endif 62 | svc 0x01<<16 @ RegisterRamReset 63 | 64 | @ Finally, set up system mode stack 65 | ldr sp, =__sp_usr 66 | 67 | #ifndef MULTIBOOT 68 | @ Set cart speed 69 | ldr r12, =0x4317 70 | str r12, [r11, #IO_WAITCNT] 71 | #endif 72 | 73 | @ Copy IWRAM into place 74 | ldr r0, =__iwram_lma 75 | ldr r1, =__iwram_start 76 | ldr r2, =__iwram_end 77 | bl .Lcopy 78 | 79 | @ Set interrupt vector 80 | ldr r12, =__irq_vector 81 | ldr r1, =__irq_handler 82 | str r1, [r12] 83 | 84 | @ Enable interrupts 85 | mov r1, #1 86 | strb r1, [r11, #IO_IME] 87 | 88 | #ifndef MULTIBOOT 89 | @ Copy EWRAM into place 90 | ldr r0, =__ewram_lma 91 | ldr r1, =__ewram_start 92 | ldr r2, =__ewram_end 93 | bl .Lcopy 94 | #else 95 | @ TODO: Clear EWRAM BSS 96 | #endif 97 | 98 | @ Set up heap 99 | ldr r0, =fake_heap_start 100 | ldr r1, =__heap_start 101 | str r1, [r0] 102 | ldr r0, =fake_heap_end 103 | ldr r1, =__heap_end 104 | str r1, [r0] 105 | 106 | @ Initialize threading system 107 | bl _threadInit 108 | 109 | @ Call static ctors 110 | bl __libc_init_array 111 | 112 | @ Call the main function 113 | adr lr, .Lreset 114 | mov r0, #0 115 | mov r1, #0 116 | ldr r12, =main 117 | bx r12 118 | 119 | .Lreset: 120 | @ If main() ever returns, we soft-reset 121 | svc 0x00<<16 @ SoftReset 122 | 123 | .Lcopy: 124 | subs r2, r2, r1 125 | bxeq lr 126 | .LcopyLoop: 127 | subs r2, r2, #4 128 | ldmia r0!, {r3} 129 | stmia r1!, {r3} 130 | bne .LcopyLoop 131 | bx lr 132 | 133 | FUNC_END 134 | -------------------------------------------------------------------------------- /source/gba/crt0_mb.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #define MULTIBOOT 4 | #include "crt0.s" 5 | -------------------------------------------------------------------------------- /source/gba/dma_fill_buf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | vu32 __dma_fill[4]; 6 | -------------------------------------------------------------------------------- /source/gba/irq_handler.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | FUNC_START32 __irq_handler 9 | 10 | @ Retrieve active interrupt mask 11 | mov r12, #MM_IO 12 | ldr r0, [r12, #IO_IE] @ read both IE and IF at the same time 13 | ands r0, r0, r0, lsr #16 @ r0 <- IO_IE & IO_IF 14 | bxeq lr @ If r0 is empty we can't do anything 15 | 16 | @ Select an interrupt (LSB has priority) 17 | mov r3, #1 @ dummy 1 needed for shifting 18 | mov r1, #0 @ bit counter 19 | 1: ands r2, r0, r3, lsl r1 @ r2 -> cur_irq_mask 20 | addeq r1, r1, #1 @ r1 -> cur_irq_id 21 | beq 1b 22 | 23 | @ Acknowledge the interrupt 24 | add r3, r12, #IO_IE 25 | strh r2, [r3, #IO_IF-IO_IE] 26 | 27 | @ __irq_flags |= cur_irq_mask (using the same mirror as the BIOS) 28 | ldrh r3, [r12, #-8] 29 | orr r3, r3, r2 30 | strh r3, [r12, #-8] 31 | 32 | @ Load the handler and call it 33 | ldr r3, =__irq_table 34 | ldr r3, [r3, r1, lsl #2] 35 | push {r2, lr} @ save irq_mask & BIOS return address 36 | cmp r3, #0 37 | adr lr, 1f 38 | moveq r3, lr @ avoid crashing if no handler is registered 39 | bx r3 40 | 41 | @ Check if thread rescheduling is needed 42 | 1: ldr r3, [sp, #0] @ r3 <- cur_irq_mask 43 | ldr r2, =__sched_state 44 | ldrh r1, [r2, #3*4] @ r1 <- s_irqWaitMask 45 | ands r3, r3, r1 @ cur_irq_mask &= s_irqWaitMask 46 | beq 1f @ if (!cur_irq_mask) -> skip this section 47 | 48 | @ s_irqWaitMask &= ~cur_irq_mask 49 | bic r1, r1, r3 50 | strh r1, [r2, #3*4] 51 | 52 | @ __irq_flags &= ~cur_irq_mask 53 | mov r12, #MM_IO 54 | ldrh r1, [r12, #-8] 55 | bic r1, r1, r3 56 | strh r1, [r12, #-8] 57 | 58 | @ threadUnblock(&irqWaitList, -1, ThrUnblockMode_ByMask, cur_irq_mask) 59 | add r0, r2, #4*4 60 | @mov r1, #-1 61 | @mov r2, #2 62 | @bl threadUnblock 63 | mov r1, r3 64 | bl threadUnblockAllByMask 65 | 66 | @ Check if we have a pending reschedule 67 | ldr r2, =__sched_state 68 | 1: add sp, sp, #8 69 | ldr r0, [r2, #4] @ r0 <- s_deferredThread 70 | cmp r0, #0 71 | ldreq pc, [sp, #-4] @ Return to BIOS if not 72 | 73 | @ s_curThread = s_deferredThread; s_deferredThread = NULL; 74 | mov r3, #0 75 | ldr r1, [r2, #0] 76 | stm r2, {r0, r3} 77 | 78 | @ Save old thread's context 79 | mrs r2, spsr 80 | str r2, [r1, #16*4] 81 | pop {r2,r3} 82 | stm r1!, {r2,r3} 83 | pop {r2,r3,r12,lr} 84 | sub lr, lr, #4 85 | stm r1, {r2-r14}^ 86 | str lr, [r1, #(15-2)*4] 87 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_SVC) 88 | str sp, [r1, #(17-2)*4] 89 | 90 | @ Load new thread's context 91 | b armContextLoadFromSvc 92 | 93 | FUNC_END 94 | -------------------------------------------------------------------------------- /source/gba/rom_header.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | .section .romhdr, "ax", %progbits 6 | .align 2 7 | 8 | .global __gba_boot_mode 9 | .global __gba_mb_slave_id 10 | 11 | #ifndef MULTIBOOT 12 | .global __gba_rom_header 13 | __gba_rom_header: 14 | b __gba_start @ (0x000) ROM Entrypoint 15 | #else 16 | .global __gba_rom_header_mb 17 | __gba_rom_header_mb: 18 | b __gba_start_mb @ (0x000) ROM Entrypoint 19 | #endif 20 | .fill 156,1,0 @ (0x004) Nintendo Logo 21 | .fill 16,1,0 @ (0x0a0) Game Title 22 | .ascii "01" @ (0x0b0) Maker Code 23 | .byte 0x96 @ (0x0b2) Fixed Value 24 | .byte 0 @ (0x0b3) Main Unit Code 25 | .byte 0 @ (0x0b4) Device Type 26 | .fill 7,1,0 @ (0x0b5) Reserved Area 27 | .byte 0 @ (0x0bc) Software Version 28 | .byte 0xf0 @ (0x0bd) Complement Check 29 | .hword 0 @ (0x0be) Reserved Area 30 | 31 | #ifndef MULTIBOOT 32 | 1: b 1b @ (0x0c0) RAM Entrypoint 33 | #else 34 | b __gba_start_mb @ (0x0c0) RAM Entrypoint 35 | #endif 36 | __gba_boot_mode: 37 | .byte 0 @ (0x0c4) Boot mode 38 | __gba_mb_slave_id: 39 | .byte 0 @ (0x0c5) Slave ID Number 40 | .fill 10,1,0 @ (0x0c6) Unused 41 | -------------------------------------------------------------------------------- /source/gba/rom_header_mb.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #define MULTIBOOT 4 | #include "rom_header.s" 5 | -------------------------------------------------------------------------------- /source/nds/arm7/ar6k.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "../../dev/ar6k/ar6k_dev.c" 4 | #include "../../dev/ar6k/ar6k_bmi.c" 5 | #include "../../dev/ar6k/ar6k_htc.c" 6 | #include "../../dev/ar6k/ar6k_wmi.c" 7 | -------------------------------------------------------------------------------- /source/nds/arm7/bootstub_arm7.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | REFERENCE __newlib_syscalls 10 | 11 | FUNC_START32 __ds7_bootstub, bootstub 12 | b .Lactual_start 13 | 14 | .Lmodule_header: 15 | .ascii "MOD7" 16 | .hword 1 @ Flags 17 | .hword .Lactual_start - .Lmodule_header 18 | 19 | .word __loadlist_lma 20 | .word __loadlist_start 21 | .word __loadlist_end 22 | .word __twl_loadlist_lma 23 | .word __twl_loadlist_start 24 | .word __twl_loadlist_end 25 | 26 | .Lactual_start: 27 | @ Switch to supervisor mode and mask interrupts 28 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_SVC) 29 | 30 | @ Set up supervisor mode stack 31 | ldr sp, =__sp_svc 32 | 33 | @ Disable interrupts in the IRQ controller 34 | mov r11, #MM_IO 35 | strb r11, [r11, #IO_IME] 36 | 37 | @ Set interrupt vector 38 | ldr r12, =__irq_vector 39 | ldr r1, =__irq_handler 40 | str r1, [r12] 41 | 42 | @ Set up interrupt mode stack 43 | msr cpsr_c, #(ARM_PSR_I | ARM_PSR_F | ARM_PSR_MODE_IRQ) 44 | ldr sp, =__sp_irq 45 | 46 | @ Set up system mode stack (and unmask interrupts) 47 | msr cpsr_c, #ARM_PSR_MODE_SYS 48 | ldr sp, =__sp_usr 49 | 50 | @ Synchronize with arm9, receiving DSi mode flag 51 | adr r0, .LsyncWith9 52 | sub r1, sp, #.LsyncWith9_end-.LsyncWith9 53 | 1: ldr r2, [r0], #4 54 | str r2, [r1], #4 55 | cmp r1, sp 56 | bne 1b 57 | adr lr, 1f 58 | ldr r3, =(1<<3) | (1<<14) | (1<<15) 59 | sub pc, sp, #.LsyncWith9_end-.LsyncWith9 60 | 1: 61 | 62 | @ Run the crt0 logic 63 | adr r0, .Lmodule_header 64 | mov r1, r4 65 | ldr r2, =crt0Startup 66 | adr lr, 1f 67 | bx r2 68 | 1: 69 | @ Call global constructors 70 | ldr r0, =__libc_init_array 71 | adr lr, 1f 72 | bx r0 73 | 1: 74 | @ Calculate end of main RAM reserved for ARM9 75 | cmp r4, #0 76 | ldr r4, =__main_start 77 | bne 1f 78 | sub r4, r4, #(MM_MAINRAM_SZ_TWL-MM_MAINRAM_SZ_NTR) 79 | svc 0x0f0000 @ svcIsDebugger 80 | cmp r0, #0 81 | addne r4, r4, #(MM_MAINRAM_SZ_DBG-MM_MAINRAM_SZ_NTR) 82 | 1: 83 | @ Set up trampoline for jumping to main 84 | adr r7, .LjumpToMain 85 | ldm r7, {r8-r9} 86 | stmdb sp, {r8-r9} 87 | 88 | @ Jump to main() 89 | ldr r2, =MM_ENV_ARGV_HEADER+0x0c 90 | ldr r5, =main 91 | ldr lr, =exit 92 | ldm r2, {r0, r1} @ argc, argv 93 | sub pc, sp, #8 94 | 95 | .LsyncWith9: 96 | str r3, [r11, #IO_PXI_CNT] 97 | ldrb r0, [r11, #IO_PXI_SYNC] 98 | mov r1, #0 99 | 1: add r1, r1, #1 100 | and r1, r1, #0xF 101 | strb r1, [r11, #IO_PXI_SYNC+1] 102 | ldrb r2, [r11, #IO_PXI_SYNC] 103 | cmp r0, r2 104 | beq 1b 105 | add r1, r1, #1 106 | and r1, r1, #0xF 107 | strb r1, [r11, #IO_PXI_SYNC+1] 108 | 109 | @ Wait for DSi mode flag to arrive 110 | 1: ldr r0, [r11, #IO_PXI_CNT] 111 | tst r0, #(1<<8) 112 | bne 1b 113 | 114 | @ Read DSi mode flag 115 | mov r4, #MM_IO + IO_PXI_RECV 116 | ldr r4, [r4] 117 | 118 | bx lr 119 | .LsyncWith9_end: 120 | 121 | .LjumpToMain: 122 | str r4, [r11, #IO_PXI_SEND] 123 | bx r5 124 | 125 | FUNC_END 126 | -------------------------------------------------------------------------------- /source/nds/arm7/debug.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../transfer.h" 9 | 10 | DebugBufferMode g_dbgBufMode = DbgBufMode_Line; 11 | static Mutex s_debugMutex; 12 | 13 | void debugOutput(const char* buf, size_t size) 14 | { 15 | mutexLock(&s_debugMutex); 16 | 17 | while (size) { 18 | while ((s_debugBuf->flags & (DBG_BUF_ALIVE|DBG_BUF_BUSY)) != DBG_BUF_ALIVE) { 19 | pxiWaitForPing(); 20 | } 21 | 22 | u32 remaining_sz = sizeof(s_debugBuf->data) - s_debugBuf->size; 23 | u32 this_size = size > remaining_sz ? remaining_sz : size; 24 | 25 | bool should_ping = g_dbgBufMode == DbgBufMode_None || this_size == remaining_sz; 26 | char* outbuf = s_debugBuf->data + s_debugBuf->size; 27 | if_likely (buf) { 28 | for (u32 i = 0; i < this_size; i ++) { 29 | outbuf[i] = buf[i]; 30 | if_unlikely (buf[i] == '\n' && g_dbgBufMode == DbgBufMode_Line) { 31 | // Flush on newline 32 | should_ping = true; 33 | this_size = i + 1; 34 | } 35 | } 36 | } else { 37 | // Hack, so that printing padding spaces through dietPrint is more efficient 38 | memset(outbuf, ' ', this_size); 39 | } 40 | 41 | s_debugBuf->size += this_size; 42 | buf += this_size; 43 | size -= this_size; 44 | 45 | if (should_ping) { 46 | s_debugBuf->flags |= DBG_BUF_BUSY; 47 | pxiPing(); 48 | } 49 | } 50 | 51 | mutexUnlock(&s_debugMutex); 52 | } 53 | -------------------------------------------------------------------------------- /source/nds/arm7/env.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //#define ENV_DEBUG 10 | 11 | #ifdef ENV_DEBUG 12 | #include 13 | #else 14 | #define dietPrint(...) ((void)0) 15 | #endif 16 | 17 | MK_INLINE unsigned _envGetUserSettingsNvramOffset(void) 18 | { 19 | u16 off_div8 = g_envExtraInfo->nvram_offset_div8; 20 | if (!off_div8) { 21 | nvramReadDataBytes(&off_div8, 0x20, sizeof(u16)); 22 | g_envExtraInfo->nvram_offset_div8 = off_div8; 23 | nvramReadDataBytes(&g_envExtraInfo->nvram_console_type, 0x1d, sizeof(u8)); 24 | 25 | if (g_envExtraInfo->nvram_console_type == 0xff) { 26 | g_envExtraInfo->nvram_console_type = EnvConsoleType_DS; 27 | } 28 | } 29 | return off_div8*8; 30 | } 31 | 32 | static bool _envValidateUserSettings(EnvUserSettingsNvram* cfg) 33 | { 34 | u16 calc_crc16 = svcGetCRC16(0xffff, &cfg->base, sizeof(cfg->base)); 35 | if (cfg->crc16 != calc_crc16) { 36 | dietPrint("[NVRAM] CRC16 %.4X != %.4X\n", cfg->crc16, calc_crc16); 37 | return false; 38 | } 39 | 40 | if (cfg->base.version != ENV_USER_SETTINGS_VERSION) { 41 | dietPrint("[NVRAM] Bad version %u\n", cfg->base.version); 42 | return false; 43 | } 44 | 45 | u16 calc_ext_crc16 = svcGetCRC16(0xffff, &cfg->ext, sizeof(cfg->ext)); 46 | if (cfg->ext_crc16 == calc_ext_crc16) { 47 | dietPrint("[NVRAM] Has ext\n"); 48 | if (cfg->ext.version != ENV_USER_SETTINGS_VERSION_EXT) { 49 | dietPrint("[NVRAM] Bad ext version %u\n", cfg->ext.version); 50 | } else { 51 | // Copy language info 52 | cfg->base.config.language = cfg->ext.language; 53 | } 54 | } 55 | 56 | return true; 57 | } 58 | 59 | static void _envLoadUserSettings(void) 60 | { 61 | EnvUserSettingsNvram cfg[2]; 62 | 63 | unsigned user_off = _envGetUserSettingsNvramOffset(); 64 | dietPrint("NVRAM off = %.4X\n", user_off); 65 | 66 | nvramReadDataBytes(cfg, user_off, sizeof(cfg)); 67 | 68 | bool ok0 = _envValidateUserSettings(&cfg[0]); 69 | bool ok1 = _envValidateUserSettings(&cfg[1]); 70 | 71 | EnvUserSettingsNvram* chosen_cfg = NULL; 72 | if (ok0 && ok1) { 73 | // Conflict, decide which to copy 74 | dietPrint("[NVRAM] choosing %.2X %.2X\n", cfg[0].counter, cfg[1].counter); 75 | chosen_cfg = &cfg[((cfg[0].counter + 1) & 0x7f) == cfg[1].counter]; 76 | } else if (ok0) { 77 | chosen_cfg = &cfg[0]; 78 | } else if (ok1) { 79 | chosen_cfg = &cfg[1]; 80 | } 81 | 82 | if (chosen_cfg) { 83 | dietPrint("[NVRAM] Chosen slot %u\n", chosen_cfg-cfg); 84 | armCopyMem32(g_envUserSettings, &chosen_cfg->base, sizeof(EnvUserSettings)); 85 | } else { 86 | dietPrint("[NVRAM] No settings loaded!\n"); 87 | armFillMem32(g_envUserSettings, 0, sizeof(EnvUserSettings)); 88 | } 89 | } 90 | 91 | void envReadNvramSettings(void) 92 | { 93 | spiLock(); 94 | nvramWaitReady(); 95 | _envLoadUserSettings(); 96 | spiUnlock(); 97 | } 98 | -------------------------------------------------------------------------------- /source/nds/arm7/gpio.twl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | void gpioSetWlModule(GpioWlModule module) 7 | { 8 | u16 wl_cur = REG_GPIO_WL; 9 | u16 wl_new = wl_cur; 10 | 11 | // Adjust register value based on the desired module 12 | switch (module) { 13 | default: 14 | case GpioWlModule_Atheros: 15 | wl_new &= ~GPIO_WL_MITSUMI; 16 | break; 17 | case GpioWlModule_Mitsumi: 18 | wl_new |= GPIO_WL_MITSUMI; 19 | break; 20 | } 21 | 22 | // Succeed early if the setting already matches 23 | if (wl_cur == wl_new) { 24 | return; 25 | } 26 | 27 | // Apply the new setting 28 | REG_GPIO_WL = wl_new; 29 | if (module == GpioWlModule_Mitsumi) { 30 | // 5ms delay needed after selecting Mitsumi 31 | threadSleep(5000); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /source/nds/arm7/i2c.twl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | 7 | Mutex g_i2cMutex; 8 | static s32 s_i2cDelay, s_i2cMcuDelay; 9 | 10 | MK_INLINE void _i2cWaitBusy(void) 11 | { 12 | while (REG_I2C_CNT & 0x80); 13 | } 14 | 15 | MK_INLINE void _i2cSetDelay(I2cDevice dev) 16 | { 17 | if (dev == I2cDev_MCU) { 18 | s_i2cDelay = s_i2cMcuDelay; 19 | } else { 20 | s_i2cDelay = 0; 21 | } 22 | } 23 | 24 | void _i2cSetMcuDelay(s32 delay) 25 | { 26 | s_i2cMcuDelay = delay; 27 | } 28 | 29 | MK_INLINE void _i2cDelay() 30 | { 31 | _i2cWaitBusy(); 32 | if (s_i2cDelay > 0) { 33 | svcWaitByLoop(s_i2cDelay); 34 | // !!! WARNING !!! Calling a BIOS function from within IRQ mode 35 | // will use up 4 words of SVC and 2 words of SYS stack from the **CURRENT** thread, 36 | // which may be the idle thread; which does NOT have enough space for nested syscall 37 | // frames! 38 | // For now, and because I am lazy, let's do this in shittily written C. 39 | //for (volatile s32 i = s_i2cDelay; i; i --); 40 | } 41 | } 42 | 43 | static void _i2cStop(u8 arg0) 44 | { 45 | if (s_i2cDelay) { 46 | REG_I2C_CNT = (arg0 << 5) | 0xC0; 47 | _i2cDelay(); 48 | REG_I2C_CNT = 0xC5; 49 | } else { 50 | REG_I2C_CNT = (arg0 << 5) | 0xC1; 51 | } 52 | } 53 | 54 | MK_INLINE bool _i2cGetResult() 55 | { 56 | _i2cWaitBusy(); 57 | return (REG_I2C_CNT >> 4) & 0x01; 58 | } 59 | 60 | MK_INLINE u8 _i2cGetData() 61 | { 62 | _i2cWaitBusy(); 63 | return REG_I2C_DATA; 64 | } 65 | 66 | static bool _i2cSelectDevice(I2cDevice dev) 67 | { 68 | _i2cWaitBusy(); 69 | REG_I2C_DATA = dev; 70 | REG_I2C_CNT = 0xC2; 71 | return _i2cGetResult(); 72 | } 73 | 74 | static bool _i2cSelectRegister(u8 reg) 75 | { 76 | _i2cDelay(); 77 | REG_I2C_DATA = reg; 78 | REG_I2C_CNT = 0xC0; 79 | return _i2cGetResult(); 80 | } 81 | 82 | bool i2cWriteRegister8(I2cDevice dev, u8 reg, u8 data) 83 | { 84 | if_unlikely (!mutexIsLockedByCurrentThread(&g_i2cMutex)) { 85 | return false; 86 | } 87 | 88 | _i2cSetDelay(dev); 89 | for (unsigned i = 0; i < 8; i ++) { 90 | if (_i2cSelectDevice(dev) && _i2cSelectRegister(reg)) { 91 | _i2cDelay(); 92 | REG_I2C_DATA = data; 93 | _i2cStop(0); 94 | 95 | if (_i2cGetResult()) { 96 | return true; 97 | } 98 | } 99 | REG_I2C_CNT = 0xC5; 100 | } 101 | 102 | return false; 103 | } 104 | 105 | u8 i2cReadRegister8(I2cDevice dev, u8 reg) 106 | { 107 | if_unlikely (!mutexIsLockedByCurrentThread(&g_i2cMutex)) { 108 | return 0xff; 109 | } 110 | 111 | _i2cSetDelay(dev); 112 | for (unsigned i = 0; i < 8; i++) { 113 | if (_i2cSelectDevice(dev) && _i2cSelectRegister(reg)) { 114 | _i2cDelay(); 115 | if (_i2cSelectDevice(dev | 1)) { 116 | _i2cDelay(); 117 | _i2cStop(1); 118 | return _i2cGetData(); 119 | } 120 | } 121 | 122 | REG_I2C_CNT = 0xC5; 123 | } 124 | 125 | return 0xff; 126 | } 127 | -------------------------------------------------------------------------------- /source/nds/arm7/mcu.twl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MCU_IRQ_MASK ( \ 10 | MCU_IRQ_PWRBTN_RESET|MCU_IRQ_PWRBTN_SHUTDOWN|MCU_IRQ_PWRBTN_BEGIN| \ 11 | MCU_IRQ_BATTERY_EMPTY|MCU_IRQ_BATTERY_LOW|MCU_IRQ_VOLBTN \ 12 | ) 13 | 14 | void _i2cSetMcuDelay(s32 delay); 15 | 16 | McuPwrBtnState g_mcuPwrBtnState; 17 | 18 | static Thread s_mcuThread; 19 | static alignas(8) u8 s_mcuThreadStack[0x200]; 20 | 21 | static McuIrqHandler s_mcuIrqTable[8]; 22 | 23 | static unsigned _mcuCheckIrqFlags(void) 24 | { 25 | i2cLock(); 26 | unsigned flags = i2cReadRegister8(I2cDev_MCU, McuReg_IrqFlags); 27 | i2cUnlock(); 28 | return flags; 29 | } 30 | 31 | MK_INLINE bool _mcuIrqMaskUnpack(unsigned* pmask, unsigned* pid) 32 | { 33 | if (!*pmask) 34 | return false; 35 | while (!(*pmask & (1U << *pid))) 36 | ++*pid; 37 | *pmask &= ~(1U << *pid); 38 | return true; 39 | } 40 | 41 | static int _mcuThread(void* unused) 42 | { 43 | // Enable MCU interrupt 44 | irqEnable2(IRQ2_MCU); 45 | 46 | for (;;) { 47 | unsigned flags = _mcuCheckIrqFlags(); 48 | 49 | // Update power button state 50 | if (flags & MCU_IRQ_PWRBTN_SHUTDOWN) { 51 | g_mcuPwrBtnState = McuPwrBtnState_Shutdown; 52 | } else if (flags & MCU_IRQ_PWRBTN_RESET) { 53 | g_mcuPwrBtnState = McuPwrBtnState_Reset; 54 | } else if (flags & MCU_IRQ_PWRBTN_BEGIN) { 55 | g_mcuPwrBtnState = McuPwrBtnState_Begin; 56 | } 57 | 58 | // Call irq handlers 59 | unsigned id = 0; 60 | while (_mcuIrqMaskUnpack(&flags, &id)) { 61 | if (s_mcuIrqTable[id]) { 62 | s_mcuIrqTable[id](1U << id); 63 | } 64 | } 65 | 66 | threadIrqWait2(false, IRQ2_MCU); 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | void mcuInit(void) 73 | { 74 | // Retrieve MCU firmware version, and set up the correct I2C delay for it 75 | i2cLock(); 76 | unsigned mcuVersion = i2cReadRegister8(I2cDev_MCU, McuReg_Version); 77 | i2cUnlock(); 78 | if (mcuVersion <= 0x20) { 79 | _i2cSetMcuDelay(0x180); 80 | } else { 81 | _i2cSetMcuDelay(0x90); 82 | } 83 | } 84 | 85 | void mcuStartThread(u8 thread_prio) 86 | { 87 | // Set up MCU thread 88 | threadPrepare(&s_mcuThread, _mcuThread, NULL, &s_mcuThreadStack[sizeof(s_mcuThreadStack)], thread_prio); 89 | threadStart(&s_mcuThread); 90 | } 91 | 92 | void mcuIrqSet(unsigned irq_mask, McuIrqHandler fn) 93 | { 94 | IrqState st = irqLock(); 95 | unsigned id = 0; 96 | irq_mask &= MCU_IRQ_MASK; 97 | while (_mcuIrqMaskUnpack(&irq_mask, &id)) { 98 | s_mcuIrqTable[id] = fn; 99 | } 100 | irqUnlock(st); 101 | } 102 | 103 | void mcuIssueReset(void) 104 | { 105 | armIrqLockByPsr(); 106 | i2cLock(); 107 | i2cWriteRegister8(I2cDev_MCU, McuReg_WarmbootFlag, 1); 108 | i2cWriteRegister8(I2cDev_MCU, McuReg_DoReset, 1); 109 | for (;;); // infinite loop just in case 110 | } 111 | 112 | void mcuIssueShutdown(void) 113 | { 114 | armIrqLockByPsr(); 115 | i2cLock(); 116 | i2cWriteRegister8(I2cDev_MCU, McuReg_DoReset, 2); 117 | pmicIssueShutdown(); 118 | } 119 | -------------------------------------------------------------------------------- /source/nds/arm7/nvram.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void _nvramSpiBegin(NvramCmd cmd) 9 | { 10 | spiRawStartHold(SpiDev_NVRAM, SpiBaud_4MHz); 11 | spiRawWriteByte(cmd); 12 | } 13 | 14 | MK_INLINE void _nvramSpiPreEnd(void) 15 | { 16 | spiRawEndHold(SpiDev_NVRAM, SpiBaud_4MHz); 17 | } 18 | 19 | static u8 _nvramReadStatus(void) 20 | { 21 | _nvramSpiBegin(NvramCmd_ReadStatus); 22 | _nvramSpiPreEnd(); 23 | return spiRawReadByte(); 24 | } 25 | 26 | bool nvramWaitReady(void) 27 | { 28 | if (!mutexIsLockedByCurrentThread(&g_spiMutex)) { 29 | return false; 30 | } 31 | 32 | while (_nvramReadStatus() & NVRAM_STATUS_WIP); 33 | 34 | return true; 35 | } 36 | 37 | bool nvramReadJedec(u32* out) 38 | { 39 | if (!mutexIsLockedByCurrentThread(&g_spiMutex)) { 40 | return false; 41 | } 42 | 43 | _nvramSpiBegin(NvramCmd_ReadJedec); 44 | unsigned hi = spiRawReadByte(); 45 | unsigned mid = spiRawReadByte(); 46 | _nvramSpiPreEnd(); 47 | unsigned lo = spiRawReadByte(); 48 | 49 | *out = lo | (mid<<8) | (hi<<16); 50 | return true; 51 | } 52 | 53 | bool nvramReadDataBytes(void* data, u32 addr, u32 len) 54 | { 55 | if (!len) { 56 | return true; 57 | } 58 | 59 | if (!mutexIsLockedByCurrentThread(&g_spiMutex)) { 60 | return false; 61 | } 62 | 63 | _nvramSpiBegin(NvramCmd_ReadDataBytes); 64 | spiRawWriteByte(addr >> 16); 65 | spiRawWriteByte(addr >> 8); 66 | spiRawWriteByte(addr); 67 | 68 | u8* data8 = (u8*)data; 69 | for (u32 i = 0; i < len - 1; i ++) { 70 | *data8++ = spiRawReadByte(); 71 | } 72 | 73 | _nvramSpiPreEnd(); 74 | *data8++ = spiRawReadByte(); 75 | 76 | return true; 77 | } 78 | -------------------------------------------------------------------------------- /source/nds/arm7/pm_arm7.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | unsigned pmGetBatteryState(void) 14 | { 15 | unsigned ret; 16 | 17 | if (systemIsTwlMode()) { 18 | // DSi mode: Read state from MCU 19 | // XX: Official code converts 0-15 into 0-5 with the following formula: 20 | // (level&1) + ((level&2)>>1) + ((level&0xc)>>2) 21 | i2cLock(); 22 | ret = i2cReadRegister8(I2cDev_MCU, McuReg_BatteryState); 23 | i2cUnlock(); 24 | } else { 25 | // DS mode: Read state from PMIC 26 | spiLock(); 27 | ret = (pmicReadRegister(PmicReg_BatteryStatus) & PMIC_BATT_STAT_LOW) ? 3 : 15; 28 | if (g_envExtraInfo->nvram_console_type & EnvConsoleType_DSLite) { 29 | // If on DS Lite: read charger status too 30 | ret |= (pmicReadRegister(PmicReg_BacklightLevel) & PMIC_BL_CHARGER_DETECTED) ? PM_BATT_CHARGING : 0; 31 | } 32 | spiUnlock(); 33 | } 34 | 35 | return ret; 36 | } 37 | 38 | void pmSetPowerLed(PmLedMode mode) 39 | { 40 | spiLock(); 41 | unsigned reg = pmicReadRegister(PmicReg_Control); 42 | pmicWriteRegister(PmicReg_Control, (reg&~PMIC_CTRL_LED_MASK) | ((mode&3)<<4)); 43 | spiUnlock(); 44 | } 45 | 46 | void pmSoundSetAmpPower(bool enable) 47 | { 48 | spiLock(); 49 | if (cdcIsTwlMode()) { 50 | // TODO: implement this with CODEC 51 | } else { 52 | // Use PMIC 53 | unsigned reg = pmicReadRegister(PmicReg_Control); 54 | if (enable) { 55 | reg = (reg &~ PMIC_CTRL_SOUND_MUTE) | PMIC_CTRL_SOUND_ENABLE; 56 | } else { 57 | reg = (reg &~ PMIC_CTRL_SOUND_ENABLE) | PMIC_CTRL_SOUND_MUTE; 58 | } 59 | pmicWriteRegister(PmicReg_Control, reg); 60 | } 61 | spiUnlock(); 62 | } 63 | 64 | MK_CONSTEXPR PmicMicGain _pmMicGainToPmic(unsigned gain) 65 | { 66 | if (gain < (PmMicGain_20+PmMicGain_40)/2) { 67 | return PmicMicGain_20; 68 | } else if (gain < (PmMicGain_40+PmMicGain_80)/2) { 69 | return PmicMicGain_40; 70 | } else if (gain < (PmMicGain_80+PmMicGain_160)/2) { 71 | return PmicMicGain_80; 72 | } else { 73 | return PmicMicGain_160; 74 | } 75 | } 76 | 77 | void pmMicSetAmp(bool enable, unsigned gain) 78 | { 79 | if (gain > PmMicGain_Max) { 80 | gain = PmMicGain_Max; 81 | } 82 | 83 | spiLock(); 84 | if (cdcIsTwlMode()) { 85 | // Use CODEC 86 | cdcMicSetAmp(enable, gain); 87 | } else { 88 | // Use PMIC 89 | pmicWriteRegister(PmicReg_MicAmpControl, enable ? 1 : 0); 90 | if (enable) { 91 | pmicWriteRegister(PmicReg_MicAmpGain, _pmMicGainToPmic(gain)); 92 | } 93 | } 94 | spiUnlock(); 95 | } 96 | 97 | bool pmReadNvram(void* data, u32 addr, u32 len) 98 | { 99 | spiLock(); 100 | bool rc = nvramReadDataBytes(data, addr, len); 101 | spiUnlock(); 102 | return rc; 103 | } 104 | -------------------------------------------------------------------------------- /source/nds/arm7/pmic.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void _pmicSpiBegin(u8 cmd) 9 | { 10 | spiRawStartHold(SpiDev_PMIC, SpiBaud_1MHz); 11 | spiRawWriteByte(cmd); 12 | spiRawEndHold(SpiDev_PMIC, SpiBaud_1MHz); 13 | } 14 | 15 | bool pmicWriteRegister(PmicRegister reg, u8 data) 16 | { 17 | if (!mutexIsLockedByCurrentThread(&g_spiMutex)) { 18 | return false; 19 | } 20 | 21 | _pmicSpiBegin(reg); 22 | spiRawWriteByte(data); 23 | return true; 24 | } 25 | 26 | u8 pmicReadRegister(PmicRegister reg) 27 | { 28 | if (!mutexIsLockedByCurrentThread(&g_spiMutex)) { 29 | return 0xff; 30 | } 31 | 32 | _pmicSpiBegin(reg | (1U<<7)); 33 | return spiRawReadByte(); 34 | } 35 | 36 | void pmicIssueShutdown(void) 37 | { 38 | armIrqLockByPsr(); 39 | spiLock(); 40 | pmicWriteRegister(PmicReg_Control, PMIC_CTRL_SHUTDOWN); 41 | for (;;); // infinite loop just in case 42 | } 43 | -------------------------------------------------------------------------------- /source/nds/arm7/scfg.twl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | MK_INLINE unsigned _scfgMcGetPowerState(void) 7 | { 8 | return REG_SCFG_MC & SCFG_MC_POWER_MASK; 9 | } 10 | 11 | MK_INLINE void _scfgMcSetPowerState(unsigned state) 12 | { 13 | REG_SCFG_MC = (REG_SCFG_MC &~ SCFG_MC_POWER_MASK) | (state & SCFG_MC_POWER_MASK); 14 | } 15 | 16 | static void _scfgMcPowerOn(void) 17 | { 18 | // Wait in case there's a scheduled power off request 19 | while (_scfgMcGetPowerState() == SCFG_MC_POWER_OFF_REQ) { 20 | threadSleep(1000); // 1ms 21 | } 22 | 23 | // We only need to do anything if the card is powered off 24 | if (_scfgMcGetPowerState() == SCFG_MC_POWER_OFF) { 25 | // Power on the card and assert reset 26 | threadSleep(1000); // 1ms 27 | _scfgMcSetPowerState(SCFG_MC_POWER_ON_REQ); 28 | 29 | // Transition to normal power on state 30 | threadSleep(10000); // 10ms 31 | _scfgMcSetPowerState(SCFG_MC_POWER_ON); 32 | 33 | // Enforce a delay before the ntrcard owner can deassert reset 34 | threadSleep(27000); // 27ms 35 | 36 | // XX: We would now set ROMCNT.bit29 and wait 120ms for the card to 37 | // stabilize. However, we do not necessarily own the NTRCARD registers. 38 | // For this reason, leave that task up to the user. 39 | } 40 | } 41 | 42 | static void _scfgMcPowerOff(void) 43 | { 44 | // Wait in case there's already a scheduled power off request 45 | while (_scfgMcGetPowerState() == SCFG_MC_POWER_OFF_REQ) { 46 | threadSleep(1000); // 1ms 47 | } 48 | 49 | // We only need to do anything if the card is powered on 50 | if (_scfgMcGetPowerState() == SCFG_MC_POWER_ON) { 51 | // Request power off 52 | _scfgMcSetPowerState(SCFG_MC_POWER_OFF_REQ); 53 | 54 | // Wait for the card to power off 55 | while (_scfgMcGetPowerState() != SCFG_MC_POWER_OFF) { 56 | threadSleep(1000); // 1ms 57 | } 58 | } 59 | } 60 | 61 | bool scfgSetMcPower(bool on) 62 | { 63 | if (!scfgIsPresent()) { 64 | return false; 65 | } 66 | 67 | if (on) { 68 | _scfgMcPowerOn(); 69 | } else { 70 | _scfgMcPowerOff(); 71 | } 72 | 73 | return true; 74 | } 75 | -------------------------------------------------------------------------------- /source/nds/arm7/sdio.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "../../dev/sdio.c" 4 | -------------------------------------------------------------------------------- /source/nds/arm7/sdmmc.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "../../dev/sdmmc.c" 4 | -------------------------------------------------------------------------------- /source/nds/arm7/sound/common.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../transfer.h" 10 | #include "../../pxi/sound.h" 11 | 12 | //#define SOUND_DEBUG 13 | 14 | #ifdef SOUND_DEBUG 15 | #include 16 | #else 17 | #define dietPrint(...) ((void)0) 18 | #endif 19 | 20 | typedef struct SoundState { 21 | u16 soundcnt_cfg; 22 | u16 channel_mask; 23 | u16 pxi_credits; 24 | bool mixer_sleep_lock; 25 | } SoundState; 26 | 27 | extern SoundState g_soundState; 28 | 29 | MK_INLINE bool _soundIsEnabled(void) 30 | { 31 | return g_soundState.soundcnt_cfg & SOUNDCNT_ENABLE; 32 | } 33 | 34 | void _soundEnable(void); 35 | void _soundDisable(void); 36 | void _soundSetAutoUpdate(bool enable); 37 | void _soundUpdateSharedState(void); 38 | void _soundPxiProcess(Mailbox* mb, bool do_credit_update); 39 | -------------------------------------------------------------------------------- /source/nds/arm7/spi.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | Mutex g_spiMutex; 7 | -------------------------------------------------------------------------------- /source/nds/arm7/tmio.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "../../dev/tmio.c" 4 | -------------------------------------------------------------------------------- /source/nds/arm7/wpa.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "../../dev/wpa.c" 4 | -------------------------------------------------------------------------------- /source/nds/arm7/wpa_aes.twl.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #define armAesEncrypt wpaAesEncrypt 4 | #define armAesDecrypt wpaAesDecrypt 5 | #define armAesSetEncryptKey wpaAesSetEncryptKey 6 | #define armAesSetDecryptKey wpaAesSetDecryptKey 7 | #include "../../arm/arm-aes.32.s" 8 | -------------------------------------------------------------------------------- /source/nds/arm7/wpa_hmac_sha1.twl.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../transfer.h" 9 | 10 | void wpaHmacSha1(void* out, const void* key, size_t key_len, const void* data, size_t data_len) 11 | { 12 | SvcSha1Context ctx; 13 | ctx.hash_block = NULL; 14 | 15 | u8 keyblock[64]; 16 | const u8* keyp = (const u8*)key; 17 | 18 | // Clamp down key length when larger than block size 19 | if (key_len > sizeof(keyblock)) { 20 | svcSha1CalcTWL(keyblock, key, key_len); 21 | keyp = keyblock; 22 | key_len = SVC_SHA1_DIGEST_SZ; 23 | } 24 | 25 | // Copy key (zeropadded) and XOR it with 0x36 26 | size_t i; 27 | for (i = 0; i < key_len; i ++) { 28 | keyblock[i] = keyp[i] ^ 0x36; 29 | } 30 | for (; i < sizeof(keyblock); i ++) { 31 | keyblock[i] = 0x36; 32 | } 33 | 34 | // Inner hash 35 | svcSha1InitTWL(&ctx); 36 | svcSha1UpdateTWL(&ctx, keyblock, sizeof(keyblock)); 37 | svcSha1UpdateTWL(&ctx, data, data_len); 38 | svcSha1DigestTWL(out, &ctx); 39 | 40 | // Convert inner key into outer key 41 | for (i = 0; i < sizeof(keyblock); i ++) { 42 | keyblock[i] ^= 0x36 ^ 0x5c; 43 | } 44 | 45 | // Outer hash 46 | svcSha1InitTWL(&ctx); 47 | svcSha1UpdateTWL(&ctx, keyblock, sizeof(keyblock)); 48 | svcSha1UpdateTWL(&ctx, out, SVC_SHA1_DIGEST_SZ); 49 | svcSha1DigestTWL(out, &ctx); 50 | } 51 | 52 | void wpaGenerateEapolNonce(void* out) 53 | { 54 | u32 data[8]; 55 | data[0] = *(u32*)&g_envExtraInfo->wlmgr_macaddr[0]; 56 | data[1] = *(u16*)&g_envExtraInfo->wlmgr_macaddr[4] | (lcdGetVCount()<<16); 57 | data[2] = g_envAppNdsHeader->arm9_size; 58 | data[3] = g_envAppNdsHeader->arm7_size; 59 | data[4] = g_envAppTwlHeader->arm9i_size; 60 | data[5] = g_envAppTwlHeader->arm7i_size; 61 | data[6] = s_transferRegion->unix_time; 62 | data[7] = tickGetCount(); 63 | 64 | u32* inner = (u32*)out + (WPA_EAPOL_NONCE_LEN - SVC_SHA1_DIGEST_SZ)/4; 65 | svcSha1CalcTWL(inner, data, sizeof(data)); 66 | 67 | for (unsigned i = 0; i < 8; i ++) { 68 | data[i] ^= inner[i&1]; 69 | } 70 | 71 | svcSha1CalcTWL(out, data, sizeof(data)); 72 | } 73 | -------------------------------------------------------------------------------- /source/nds/arm9/arm7_debug.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../transfer.h" 8 | 9 | static Thread s_arm7DebugThread; 10 | alignas(8) static u8 s_arm7DebugStack[8*1024]; 11 | 12 | MK_WEAK void* g_arm7DebugStackTop = &s_arm7DebugStack[sizeof(s_arm7DebugStack)]; 13 | 14 | static int _arm7DebugThread(void* data) 15 | { 16 | Arm7DebugFn fn = (Arm7DebugFn)data; 17 | 18 | s_debugBuf->flags = DBG_BUF_ALIVE; 19 | pxiPing(); 20 | 21 | for (;;) { 22 | u16 flags = s_debugBuf->flags; 23 | if (!(flags & DBG_BUF_BUSY)) { 24 | pxiWaitForPing(); 25 | continue; 26 | } 27 | 28 | if_likely (s_debugBuf->size) { 29 | fn(s_debugBuf->data, s_debugBuf->size); 30 | s_debugBuf->size = 0; 31 | } 32 | 33 | s_debugBuf->flags = flags &~ DBG_BUF_BUSY; 34 | pxiPing(); 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | void installArm7DebugSupport(Arm7DebugFn fn, u8 thread_prio) 41 | { 42 | threadPrepare(&s_arm7DebugThread, _arm7DebugThread, fn, g_arm7DebugStackTop, thread_prio); 43 | threadAttachLocalStorage(&s_arm7DebugThread, NULL); 44 | threadStart(&s_arm7DebugThread); 45 | } 46 | -------------------------------------------------------------------------------- /source/nds/arm9/excpt_handler.32.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | SECT_TEXT __excpt_entry 9 | 10 | @ Notes: 11 | @ The least significant 2 bits of SP are used to provide additional information 12 | @ about the exception. 13 | @ 14 | @ sp.bit1 = Handler type 15 | @ 0 (BIOS) or 1 (calico) 16 | @ sp.bit0 = Exception discriminator 17 | @ BIOS: 0 (rst) or 1 (pabt/dabt/und) 18 | @ calico: 0 (dabt) or 1 (pabt/und) 19 | 20 | @------------------------------------------------------------------------------ 21 | @ Reset (also occurs with NULL function pointers) 22 | @------------------------------------------------------------------------------ 23 | 24 | .weak __arm_excpt_rst 25 | .type __arm_excpt_rst, %function 26 | __arm_excpt_rst: 27 | bkpt #0x8000 @ cause a Prefetch Abort 28 | .size __arm_excpt_rst, .-__arm_excpt_rst 29 | 30 | @------------------------------------------------------------------------------ 31 | @ Prefetch Abort 32 | @------------------------------------------------------------------------------ 33 | 34 | .weak __arm_excpt_pabt 35 | .type __arm_excpt_pabt, %function 36 | __arm_excpt_pabt: 37 | sub lr, lr, #4 38 | @ Fallthrough 39 | .size __arm_excpt_pabt, .-__arm_excpt_pabt 40 | 41 | @------------------------------------------------------------------------------ 42 | @ Undefined Instruction 43 | @------------------------------------------------------------------------------ 44 | 45 | .weak __arm_excpt_und 46 | .type __arm_excpt_und, %function 47 | __arm_excpt_und: 48 | ldr sp, =MM_ENV_EXCPT_STACK_TOP 49 | orr sp, sp, #3 50 | b __excpt_entry 51 | .size __arm_excpt_und, .-__arm_excpt_und 52 | 53 | @------------------------------------------------------------------------------ 54 | @ Data Abort 55 | @------------------------------------------------------------------------------ 56 | 57 | .weak __arm_excpt_dabt 58 | .type __arm_excpt_dabt, %function 59 | __arm_excpt_dabt: 60 | sub lr, lr, #8 61 | ldr sp, =MM_ENV_EXCPT_STACK_TOP 62 | orr sp, sp, #2 63 | @ Fallthrough 64 | .size __arm_excpt_dabt, .-__arm_excpt_dabt 65 | 66 | @------------------------------------------------------------------------------ 67 | 68 | .type __excpt_entry, %function 69 | __excpt_entry: 70 | @ Save r12 and pc (exception address) 71 | push {r12, lr} 72 | 73 | @ Save cp15cr and exception spsr 74 | mrc p15, 0, r12, c1, c0, 0 75 | mrs lr, spsr 76 | push {r12, lr} 77 | 78 | @ Disable MPU 79 | bic r12, r12, #CP15_CR_PU_ENABLE 80 | mcr p15, 0, r12, c1, c0, 0 81 | 82 | @ Invoke exception handler if registered 83 | bic r12, sp, #3 @ remove extra flags 84 | ldr r12, [r12, #0x10] 85 | cmp r12, #0 86 | blxne r12 87 | 88 | @ Hang indefinitely if above returned 89 | 1: b 1b 90 | 91 | .pool 92 | .size __excpt_entry, .-__excpt_entry 93 | -------------------------------------------------------------------------------- /source/nds/arm9/mic.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../pxi/mic.h" 8 | 9 | static struct { 10 | MicBufferFn fn; 11 | void* user; 12 | size_t byte_sz; 13 | } s_micState; 14 | 15 | static Thread s_micThread; 16 | alignas(8) static u8 s_micThreadStack[0x2000]; 17 | 18 | MK_INLINE bool _micIssueCmd(PxiMicCmd cmd, unsigned imm) 19 | { 20 | u32 msg = pxiMicMakeCmdMsg(cmd, imm); 21 | return pxiSendAndReceive(PxiChannel_Mic, msg) != 0; 22 | } 23 | 24 | static int _micThreadMain(void* unused) 25 | { 26 | Mailbox mbox; 27 | u32 slots[2]; 28 | mailboxPrepare(&mbox, slots, sizeof(slots)/sizeof(u32)); 29 | pxiSetMailbox(PxiChannel_Mic, &mbox); 30 | 31 | for (;;) { 32 | void* buf = (void*)mailboxRecv(&mbox); 33 | if (s_micState.fn) { 34 | s_micState.fn(s_micState.user, buf, s_micState.byte_sz); 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | void micInit(void) 42 | { 43 | pxiWaitRemote(PxiChannel_Mic); 44 | } 45 | 46 | bool micSetCpuTimer(unsigned prescaler, unsigned period) 47 | { 48 | PxiMicImmDivTimer u = { 49 | .div = prescaler, 50 | .timer = period, 51 | }; 52 | 53 | return _micIssueCmd(PxiMicCmd_SetCpuTimer, u.imm); 54 | } 55 | 56 | bool micSetDmaRate(MicRate rate) 57 | { 58 | PxiMicImmDivTimer u = { 59 | .div = rate, 60 | .timer = 0, 61 | }; 62 | 63 | return _micIssueCmd(PxiMicCmd_SetDmaRate, u.imm); 64 | } 65 | 66 | void micSetCallback(MicBufferFn fn, void* user) 67 | { 68 | // Start mic thread if necessary 69 | if_unlikely (fn && !threadIsValid(&s_micThread)) { 70 | threadPrepare(&s_micThread, _micThreadMain, NULL, &s_micThreadStack[sizeof(s_micThreadStack)], 0x08); 71 | threadAttachLocalStorage(&s_micThread, NULL); 72 | threadStart(&s_micThread); 73 | } 74 | 75 | ArmIrqState st = armIrqLockByPsr(); 76 | s_micState.fn = fn; 77 | s_micState.user = user; 78 | armIrqUnlockByPsr(st); 79 | } 80 | 81 | bool micStart(void* buf, size_t byte_sz, MicFmt fmt, MicMode mode) 82 | { 83 | PxiMicArgStart arg = { 84 | .dest_addr = (u32)buf, 85 | .dest_sz = byte_sz, 86 | }; 87 | 88 | PxiMicImmStart u = { 89 | .is_16bit = fmt, 90 | .mode = mode, 91 | }; 92 | 93 | u32 msg = pxiMicMakeCmdMsg(PxiMicCmd_Start, u.imm); 94 | 95 | ArmIrqState st = armIrqLockByPsr(); 96 | unsigned ret = pxiSendWithDataAndReceive(PxiChannel_Mic, msg, (u32*)&arg, sizeof(arg)/sizeof(u32)); 97 | if (ret != 0) { 98 | s_micState.byte_sz = ret; 99 | } 100 | armIrqUnlockByPsr(st); 101 | 102 | return ret != 0; 103 | } 104 | 105 | void micStop(void) 106 | { 107 | _micIssueCmd(PxiMicCmd_Stop, 0); 108 | } 109 | -------------------------------------------------------------------------------- /source/nds/arm9/mpu_setup.crt0.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | 7 | FUNC_START32 crt0SetupMPU 8 | 9 | push {r4-r11} 10 | 11 | adr r3, .LmpuRegions 12 | cmp r0, #0 13 | ldm r3, {r4-r11} 14 | 15 | orrne r5, r5, #CP15_PU_16M 16 | bne 1f 17 | svc 0x0f0000 @ svcIsDebugger 18 | cmp r0, #0 19 | orreq r5, r5, #CP15_PU_4M 20 | orrne r5, r5, #CP15_PU_8M 21 | 1: 22 | 23 | mcr p15, 0, r4, c6, c0, 0 24 | mcr p15, 0, r5, c6, c1, 0 25 | mcr p15, 0, r6, c6, c2, 0 26 | mcr p15, 0, r7, c6, c3, 0 27 | mcr p15, 0, r8, c6, c4, 0 28 | mcr p15, 0, r9, c6, c5, 0 29 | mcr p15, 0, r10, c6, c6, 0 30 | mcr p15, 0, r11, c6, c7, 0 31 | 32 | mov r3, #0b00000010 33 | mcr p15, 0, r3, c3, c0, 0 34 | mov r3, #0b01000010 35 | mcr p15, 0, r3, c2, c0, 0 36 | mcr p15, 0, r3, c2, c0, 1 37 | ldr r3, =0x66600060 38 | mcr p15, 0, r3, c5, c0, 3 39 | ldr r3, =0x06330033 40 | mcr p15, 0, r3, c5, c0, 2 41 | 42 | mrc p15, 0, r3, c1, c0, 0 43 | ldr r2, =(CP15_CR_PU_ENABLE | CP15_CR_DCACHE_ENABLE | CP15_CR_ICACHE_ENABLE | CP15_CR_ROUND_ROBIN) 44 | orr r3, r3, r2 45 | bic r3, r3, #CP15_CR_ALT_VECTORS 46 | mcr p15, 0, r3, c1, c0, 0 47 | 48 | pop {r4-r11} 49 | bx lr 50 | 51 | .LmpuRegions: 52 | .word CP15_PU_ENABLE | CP15_PU_64M | MM_IO @ IO + VRAM 53 | .word CP15_PU_ENABLE | MM_MAINRAM @ Main RAM 54 | .word 0 55 | .word 0 56 | .word CP15_PU_ENABLE | CP15_PU_64K | MM_DTCM @ DTCM + high shared memory 57 | .word CP15_PU_ENABLE | CP15_PU_32K | MM_ITCM @ ITCM 58 | .word CP15_PU_ENABLE | CP15_PU_32K | MM_BIOS @ BIOS 59 | .word CP15_PU_ENABLE | CP15_PU_4K @ Exception vectors (in ITCM) 60 | 61 | FUNC_END 62 | -------------------------------------------------------------------------------- /source/nds/arm9/nitrorom.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct NitroRomFd { 12 | Mutex mutex; 13 | int fd; 14 | u32 pos; 15 | } NitroRomFd; 16 | 17 | MK_WEAK s8 g_nitroromCardDmaChannel = -1; 18 | 19 | static NitroRom s_nitroromSelf; 20 | static NitroRomFd s_nitroromFd; 21 | 22 | MK_INLINE bool _nitroromFdReadImpl(NitroRomFd* self, u32 offset, void* buf, u32 size) 23 | { 24 | if (self->pos != offset) { 25 | if (lseek(self->fd, offset, SEEK_SET) < 0) { 26 | return false; 27 | } 28 | self->pos = offset; 29 | } 30 | 31 | ssize_t bytes = read(self->fd, buf, size); 32 | if (bytes < 0) { 33 | return false; 34 | } 35 | 36 | self->pos += bytes; 37 | if (bytes != size) { 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | static bool _nitroromFdRead(void* user, u32 offset, void* buf, u32 size) 45 | { 46 | NitroRomFd* self = user; 47 | mutexLock(&self->mutex); 48 | bool ok = _nitroromFdReadImpl(self, offset, buf, size); 49 | mutexUnlock(&self->mutex); 50 | return ok; 51 | } 52 | 53 | static void _nitroromFdClose(void* user) 54 | { 55 | NitroRomFd* self = user; 56 | close(self->fd); 57 | } 58 | 59 | static const NitroRomIface s_nitroromFdIface = { 60 | .read = _nitroromFdRead, 61 | .close = _nitroromFdClose, 62 | }; 63 | 64 | static const NitroRomIface s_nitroromCardIface = { 65 | .read = (void*)ntrcardRomRead, 66 | .close = (void*)ntrcardClose, 67 | }; 68 | 69 | NitroRom* nitroromGetSelf(void) 70 | { 71 | // Succeed early if NitroROM is already open 72 | if_likely (s_nitroromSelf.iface) { 73 | return &s_nitroromSelf; 74 | } 75 | 76 | // Use FAT/FNT parameters from NDS header 77 | NitroRomParams params = { 78 | .fat_offset = g_envAppNdsHeader->fat_rom_offset, 79 | .fat_sz = g_envAppNdsHeader->fat_size, 80 | .fnt_offset = g_envAppNdsHeader->fnt_rom_offset, 81 | .fnt_sz = g_envAppNdsHeader->fnt_size, 82 | .img_offset = 0, 83 | }; 84 | 85 | bool ok = false; 86 | 87 | // Attempt to open argv[0] if provided 88 | const char* argv0 = g_envNdsArgvHeader->argv[0]; 89 | if (argv0) { 90 | int fd = open(argv0, O_RDONLY); 91 | if (fd >= 0) { 92 | s_nitroromFd.fd = fd; 93 | s_nitroromFd.pos = 0; 94 | ok = nitroromOpen(&s_nitroromSelf, ¶ms, &s_nitroromFdIface, &s_nitroromFd); 95 | if (!ok) { 96 | close(fd); 97 | } 98 | } 99 | } 100 | 101 | // If above failed and we're booted from a real NDS card (e.g. emulators), try direct card access 102 | if (!ok && !argv0 && g_envBootParam->boot_src == EnvBootSrc_Card) { 103 | ok = ntrcardOpen(); 104 | if (ok) { 105 | ok = nitroromOpen(&s_nitroromSelf, ¶ms, &s_nitroromCardIface, (void*)(int)g_nitroromCardDmaChannel); 106 | if (!ok) { 107 | ntrcardClose(); 108 | } 109 | } 110 | } 111 | 112 | return ok ? &s_nitroromSelf : NULL; 113 | } 114 | -------------------------------------------------------------------------------- /source/nds/arm9/ovl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static OvlParams* s_ovlTable; 14 | 15 | bool ovlInit(void) 16 | { 17 | // Succeed early if already initialized 18 | if (s_ovlTable) { 19 | return true; 20 | } 21 | 22 | // Fail early if this app has no overlays 23 | if (g_envAppNdsHeader->arm9_ovl_size < sizeof(OvlParams)) { 24 | return false; 25 | } 26 | 27 | // Open the NDS ROM 28 | NitroRom* nr = nitroromGetSelf(); 29 | if (!nr) { 30 | return false; 31 | } 32 | 33 | // Reserve memory for the overlay table (cache line aligned) 34 | s_ovlTable = aligned_alloc(ARM_CACHE_LINE_SZ, g_envAppNdsHeader->arm9_ovl_size); 35 | if (!s_ovlTable) { 36 | return false; 37 | } 38 | 39 | // Read the overlay table 40 | if (!nitroromRead(nr, g_envAppNdsHeader->arm9_ovl_rom_offset, s_ovlTable, g_envAppNdsHeader->arm9_ovl_size)) { 41 | free(s_ovlTable); 42 | s_ovlTable = NULL; 43 | return false; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | bool ovlLoadInPlace(unsigned ovl_id) 50 | { 51 | // Fail early if not initialized 52 | if (!s_ovlTable) { 53 | return false; 54 | } 55 | 56 | // Succeed early if this overlay is empty 57 | OvlParams* ovl = &s_ovlTable[ovl_id]; 58 | u32 total_sz = ovl->load_size + ovl->bss_size; 59 | if (ovl->ram_address == 0 || total_sz == 0) { 60 | return true; 61 | } 62 | 63 | // Load overlay file if needed 64 | if (ovl->load_size) { 65 | NitroRom* nr = nitroromGetSelf(); 66 | if (!nr) { 67 | return false; 68 | } 69 | 70 | if (!nitroromReadFile(nr, ovl->file_id, 0, (void*)ovl->ram_address, ovl->load_size)) { 71 | return false; 72 | } 73 | } 74 | 75 | // Clear BSS if needed 76 | if (ovl->bss_size) { 77 | armFillMem32((void*)(ovl->ram_address + ovl->load_size), 0, ovl->bss_size); 78 | } 79 | 80 | // Flush the cache if needed 81 | if (ovl->ram_address >= MM_MAINRAM) { 82 | armDCacheFlush((void*)ovl->ram_address, total_sz); 83 | armICacheInvalidateAll(); 84 | } 85 | 86 | return true; 87 | } 88 | 89 | void ovlActivate(unsigned ovl_id) 90 | { 91 | // Fail early if not initialized 92 | if (!s_ovlTable) { 93 | return; 94 | } 95 | 96 | // Run static constructors 97 | OvlParams* ovl = &s_ovlTable[ovl_id]; 98 | OvlStaticFn* pfn = (OvlStaticFn*)ovl->ctors_start; 99 | while (pfn != (OvlStaticFn*)ovl->ctors_end) { 100 | (*pfn)(); 101 | pfn ++; 102 | } 103 | } 104 | 105 | void ovlDeactivate(unsigned ovl_id) 106 | { 107 | // Fail early if not initialized 108 | if (!s_ovlTable) { 109 | return; 110 | } 111 | 112 | // Run static destructors (in reverse order) 113 | OvlParams* ovl = &s_ovlTable[ovl_id]; 114 | OvlStaticFn* pfn = (OvlStaticFn*)(ovl->reserved &~ 3); // remove reserved flag bits 115 | while (pfn != (OvlStaticFn*)ovl->ctors_end) { 116 | pfn --; 117 | (*pfn)(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /source/nds/arm9/pm_arm9.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../pxi/pm.h" 9 | 10 | unsigned pmGetBatteryState(void) 11 | { 12 | u32 msg = pxiPmMakeMsg(PxiPmMsg_GetBatteryState, 0); 13 | return pxiSendAndReceive(PxiChannel_Power, msg); 14 | } 15 | 16 | void pmSetPowerLed(PmLedMode mode) 17 | { 18 | u32 msg = pxiPmMakeMsg(PxiPmMsg_SetPowerLed, mode); 19 | pxiSendAndReceive(PxiChannel_Power, msg); 20 | } 21 | 22 | bool pmReadNvram(void* data, u32 addr, u32 len) 23 | { 24 | u32 msg = pxiPmMakeMsg(PxiPmMsg_ReadNvram, 0); 25 | u32 args[] = { 26 | (u32)data, 27 | addr, 28 | len, 29 | }; 30 | 31 | armDCacheFlush(data, len); 32 | return pxiSendWithDataAndReceive(PxiChannel_Power, msg, args, 3); 33 | } 34 | 35 | void pmMicSetAmp(bool enable, unsigned gain) 36 | { 37 | if (gain > PmMicGain_Max) { 38 | gain = PmMicGain_Max; 39 | } 40 | 41 | u32 msg = pxiPmMakeMsg(PxiPmMsg_MicSetAmp, gain | (enable << 8)); 42 | pxiSendAndReceive(PxiChannel_Power, msg); 43 | } 44 | 45 | bool scfgSetMcPower(bool on) 46 | { 47 | u32 msg = pxiPmMakeMsg(PxiPmMsg_SetMcPower, on ? 1 : 0); 48 | return pxiSendAndReceive(PxiChannel_Power, msg); 49 | } 50 | -------------------------------------------------------------------------------- /source/nds/arm9/sys_startup.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | MK_WEAK void systemUserStartup(void) 16 | { 17 | // Nothing 18 | } 19 | 20 | MK_WEAK void systemStartup(void) 21 | { 22 | // Clear video display registers 23 | REG_POWCNT = POWCNT_LCD | POWCNT_2D_GFX_A | POWCNT_2D_GFX_B | POWCNT_LCD_SWAP; 24 | dmaStartFill32(3, (void*)(MM_IO + IO_GFX_A), 0, IO_TVOUTCNT-IO_DISPCNT); 25 | dmaBusyWait(3); 26 | dmaStartFill32(3, (void*)(MM_IO + IO_GFX_B), 0, IO_TVOUTCNT-IO_DISPCNT); 27 | dmaBusyWait(3); 28 | 29 | // Unmap VRAM 30 | REG_VRAMCNT_ABCD = 0; 31 | REG_VRAMCNT_EF = 0; 32 | REG_VRAMCNT_G = 0; 33 | REG_VRAMCNT_HI = 0; 34 | 35 | // Wait for the LCDs to be initialized on DSi 36 | if (systemIsTwlMode()) { 37 | while (!(REG_DISPSTAT & DISPSTAT_LCD_READY_TWL)); 38 | } 39 | 40 | // Configure LCD interrupts (enabling VBlank) 41 | lcdSetIrqMask(DISPSTAT_IE_ALL, DISPSTAT_IE_VBLANK); 42 | irqEnable(IRQ_VBLANK); 43 | 44 | // Initialize PM 45 | pmInit(); 46 | 47 | // Call user initialization function 48 | systemUserStartup(); 49 | } 50 | -------------------------------------------------------------------------------- /source/nds/arm9/touch.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include "../transfer.h" 6 | 7 | bool touchRead(TouchData* out) 8 | { 9 | u16 state, state_old; 10 | bool valid; 11 | 12 | state = s_transferRegion->touch_state; 13 | do { 14 | valid = state & TOUCH_VALID; 15 | if (valid) { 16 | TouchData* data = (TouchData*)s_transferRegion->touch_data[state & TOUCH_BUF]; 17 | *out = *data; 18 | } 19 | 20 | state_old = state; 21 | state = s_transferRegion->touch_state; 22 | } while (state != state_old); 23 | 24 | if (!valid) { 25 | *out = (TouchData){0}; 26 | } 27 | 28 | return valid; 29 | } 30 | -------------------------------------------------------------------------------- /source/nds/bios.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | .macro BIOSFUNC id, name 6 | FUNC_START16 svc\name 7 | svc \id 8 | bx lr 9 | FUNC_END 10 | .endm 11 | 12 | @ "Basic" functions 13 | 14 | @ 0x00: SoftResetNTR (does not exist on TWL) 15 | @ 0x01: LZ77UncompWramCallbackTWL 16 | @ 0x02: LZ77UncompVramCallbackTWL 17 | BIOSFUNC 0x03, WaitByLoop 18 | @ 0x04: IntrWait (bugged on TWL, do not use) 19 | @ 0x05: VBlankIntrWait (bugged on TWL, do not use) 20 | BIOSFUNC 0x06, Halt 21 | #ifdef ARM7 22 | BIOSFUNC 0x07, Sleep 23 | BIOSFUNC 0x08, SoundBias 24 | #endif 25 | BIOSFUNC 0x09, DivMod 26 | @ 0x0a: (unused) 27 | BIOSFUNC 0x0b, CpuSet 28 | @ 0x0c: CpuFastSet (bugged on both NTR and TWL) 29 | BIOSFUNC 0x0d, Sqrt 30 | BIOSFUNC 0x0e, GetCRC16 31 | @ 0x0f: IsDebuggerNTR 32 | BIOSFUNC 0x10, BitUnpack 33 | BIOSFUNC 0x11, LZ77UncompWram 34 | @ 0x12: LZ77UncompVramCallbackNTR 35 | BIOSFUNC 0x13, HuffUncompCallback 36 | BIOSFUNC 0x14, RLUncompWram 37 | BIOSFUNC 0x15, RLUncompVramCallback 38 | #ifdef ARM9 39 | BIOSFUNC 0x16, Diff8bitUnfilterWram 40 | @ 0x17: (unused) 41 | BIOSFUNC 0x18, Diff16bitUnfilter 42 | #endif 43 | @ 0x19: Copy of LZ77UncompVramCallbackTWL 44 | #ifdef ARM7 45 | BIOSFUNC 0x1a, GetSineTable 46 | @ 0x1b: GetPitchTable (bugged on TWL, workaround available) 47 | BIOSFUNC 0x1c, GetVolumeTable 48 | BIOSFUNC 0x1d, GetBootProcs 49 | @ 0x1e: (unused) 50 | @ 0x1f: CustomHalt (param in r2, see wrapper below) 51 | #endif 52 | #ifdef ARM9 53 | BIOSFUNC 0x1f, CustomPost 54 | #endif 55 | 56 | FUNC_START16 svcLZ77UncompVramCallback 57 | push {r3} 58 | ldr r3, =g_isTwlMode 59 | ldrb r3, [r3] 60 | cmp r3, #0 61 | pop {r3} 62 | beq 1f 63 | 64 | @ DSi BIOS 65 | svc 0x02 66 | bx lr 67 | 68 | @ NDS BIOS 69 | 1: svc 0x12 70 | bx lr 71 | FUNC_END 72 | 73 | #ifdef ARM7 74 | 75 | FUNC_START16 svcGetPitchTable 76 | ldr r3, =g_isTwlMode 77 | ldrb r3, [r3] 78 | cmp r3, #0 79 | beq 1f 80 | 81 | @ Account for bugged table offset (DSi BIOS workaround) 82 | ldr r1, =0x46a 83 | sub r0, r1 84 | 85 | 1: svc 0x1b 86 | 87 | @ TODO: is casting to u16 really necessary? 88 | lsl r0, #16 89 | lsr r0, #16 90 | 91 | bx lr 92 | FUNC_END 93 | 94 | FUNC_START16 svcCustomHalt 95 | mov r2, r0 96 | svc 0x1f 97 | bx lr 98 | FUNC_END 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /source/nds/bios.twl.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | 5 | .macro BIOSFUNC id, name 6 | FUNC_START16 svc\name 7 | svc \id 8 | bx lr 9 | FUNC_END 10 | .endm 11 | 12 | BIOSFUNC 0x01, LZ77UncompWramCallbackTWL 13 | @ 0x02: LZ77UncompVramCallbackTWL (not here because it's wrapped) 14 | @ 0x19: Copy of LZ77UncompVramCallbackTWL 15 | 16 | BIOSFUNC 0x20, RsaHeapInitTWL 17 | BIOSFUNC 0x21, RsaDecryptRawTWL 18 | BIOSFUNC 0x22, RsaDecryptUnpadTWL 19 | BIOSFUNC 0x23, RsaDecryptDerSha1TWL 20 | 21 | BIOSFUNC 0x24, Sha1InitTWL 22 | BIOSFUNC 0x25, Sha1UpdateTWL 23 | BIOSFUNC 0x26, Sha1DigestTWL 24 | BIOSFUNC 0x27, Sha1CalcTWL 25 | BIOSFUNC 0x28, Sha1VerifyTWL 26 | BIOSFUNC 0x29, Sha1RandomTWL 27 | -------------------------------------------------------------------------------- /source/nds/crt0.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | 6 | #define CRT0_MAGIC_ARM7 0x37444f4d // MOD7 7 | #define CRT0_MAGIC_ARM9 0x39444f4d // MOD9 8 | 9 | typedef struct Crt0LoadListEntry { 10 | uptr start; 11 | uptr end; 12 | uptr bss_end; 13 | } Crt0LoadListEntry; 14 | 15 | typedef struct Crt0LoadList { 16 | uptr lma; 17 | Crt0LoadListEntry const* start; 18 | Crt0LoadListEntry const* end; 19 | } Crt0LoadList; 20 | 21 | typedef struct Crt0Header { 22 | u32 magic; 23 | u16 flags; 24 | u16 hdr_sz; 25 | Crt0LoadList ll_ntr; 26 | Crt0LoadList ll_twl; 27 | } Crt0Header; 28 | 29 | typedef struct Crt0Header9 { 30 | Crt0Header base; 31 | u32 stack_size; 32 | uptr dldi_addr; 33 | } Crt0Header9; 34 | 35 | MK_EXTERN32 void crt0CopyMem32(uptr dst, uptr src, uptr size); 36 | MK_EXTERN32 void crt0FillMem32(uptr dst, u32 value, uptr size); 37 | 38 | MK_INLINE bool crt0IsValidHeader(Crt0Header const* hdr, u32 magic) 39 | { 40 | return hdr->magic == magic && (hdr->flags & 1) != 0; 41 | } 42 | -------------------------------------------------------------------------------- /source/nds/gbacart.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #if defined(ARM9) 6 | #include 7 | #include 8 | #endif 9 | #include 10 | #include 11 | #include 12 | #include "transfer.h" 13 | 14 | static struct { 15 | Mutex mutex; 16 | u8 timing; 17 | u8 timing_backup; 18 | } s_gbacartState; 19 | 20 | MK_INLINE bool _gbacartIsOpenByArm9(void) 21 | { 22 | return (REG_EXMEMCNT & EXMEMCNT_GBA_SLOT_ARM7) == 0; 23 | } 24 | 25 | MK_INLINE bool _gbacartIsOpenByArm7(void) 26 | { 27 | return (s_transferRegion->exmemcnt_mirror & EXMEMCNT_GBA_SLOT_ARM7) != 0; 28 | } 29 | 30 | #if defined(ARM9) 31 | #define _gbacartIsOpenBySelf _gbacartIsOpenByArm9 32 | #define _gbacartIsOpenByOther _gbacartIsOpenByArm7 33 | #elif defined(ARM7) 34 | #define _gbacartIsOpenBySelf _gbacartIsOpenByArm7 35 | #define _gbacartIsOpenByOther _gbacartIsOpenByArm9 36 | #endif 37 | 38 | static unsigned _gbacartSetTiming(unsigned mask, unsigned timing, bool force) 39 | { 40 | if (!force && !_gbacartIsOpenBySelf()) { 41 | return 0; 42 | } 43 | 44 | unsigned old = REG_EXMEMCNT; 45 | unsigned new = (old &~ mask) | (timing & mask); 46 | if (mask) { 47 | REG_EXMEMCNT = new; 48 | } 49 | return old & 0x7f; 50 | } 51 | 52 | static bool _gbacartOpen(void) 53 | { 54 | if (_gbacartIsOpenBySelf()) { 55 | return true; 56 | } 57 | 58 | if (_gbacartIsOpenByOther()) { 59 | return false; 60 | } 61 | 62 | #if defined(ARM9) 63 | REG_EXMEMCNT &= ~EXMEMCNT_GBA_SLOT_ARM7; 64 | #elif defined(ARM7) 65 | s_transferRegion->exmemcnt_mirror |= EXMEMCNT_GBA_SLOT_ARM7; 66 | #endif 67 | 68 | // Set initial identification timings 69 | s_gbacartState.timing_backup = _gbacartSetTiming(GBA_ALL_MASK, GBA_WAIT_ROM_N_18, true); 70 | 71 | #if defined(ARM9) 72 | armMpuSetRegionDataPerm(2, CP15_PU_PERM_RW); 73 | armMpuSetRegionAddrSize(2, MM_CARTROM, CP15_PU_64M); 74 | #endif 75 | 76 | return true; 77 | } 78 | 79 | static void _gbacartClose(void) 80 | { 81 | if (!_gbacartIsOpenBySelf()) { 82 | return; 83 | } 84 | 85 | _gbacartSetTiming(GBA_ALL_MASK, s_gbacartState.timing_backup, true); 86 | 87 | #if defined(ARM9) 88 | armMpuClearRegion(2); 89 | 90 | REG_EXMEMCNT |= EXMEMCNT_GBA_SLOT_ARM7; 91 | #elif defined(ARM7) 92 | s_transferRegion->exmemcnt_mirror &= ~EXMEMCNT_GBA_SLOT_ARM7; 93 | #endif 94 | } 95 | 96 | bool gbacartOpen(void) 97 | { 98 | if (systemIsTwlMode()) { 99 | return false; 100 | } 101 | 102 | mutexLock(&s_gbacartState.mutex); 103 | bool rc = _gbacartOpen(); 104 | mutexUnlock(&s_gbacartState.mutex); 105 | return rc; 106 | } 107 | 108 | void gbacartClose(void) 109 | { 110 | mutexLock(&s_gbacartState.mutex); 111 | _gbacartClose(); 112 | mutexUnlock(&s_gbacartState.mutex); 113 | } 114 | 115 | bool gbacartIsOpen(void) 116 | { 117 | return _gbacartIsOpenBySelf(); 118 | } 119 | 120 | unsigned gbacartSetTiming(unsigned mask, unsigned timing) 121 | { 122 | mask &= GBA_ALL_MASK; 123 | mutexLock(&s_gbacartState.mutex); 124 | unsigned old = _gbacartSetTiming(mask, timing, false); 125 | mutexUnlock(&s_gbacartState.mutex); 126 | return old; 127 | } 128 | -------------------------------------------------------------------------------- /source/nds/keypad.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "transfer.h" 8 | 9 | #if defined(ARM9) 10 | 11 | unsigned keypadGetState(void) 12 | { 13 | return keypadGetInState() | s_transferRegion->keypad_ext; 14 | } 15 | 16 | #elif defined(ARM7) 17 | 18 | static TickTask s_keypadTask; 19 | 20 | static void _keypadSendExtToArm9(TickTask* t) 21 | { 22 | s_transferRegion->keypad_ext = keypadGetExtState(); 23 | } 24 | 25 | void keypadStartExtServer(void) 26 | { 27 | // XX: Wait for RCNT_EXT to stabilize immediately after bootup. 28 | // This behavior has only been observed on emulator so far. 29 | while (REG_RCNT_EXT == 0) { 30 | svcWaitByLoop(0x1000); 31 | } 32 | 33 | tickTaskStart(&s_keypadTask, _keypadSendExtToArm9, 0, ticksFromUsec(4000)); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /source/nds/pxi/blkdev.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | 7 | typedef enum PxiBlkDevMsgType { 8 | // ARM9 -> ARM7 9 | PxiBlkDevMsg_IsPresent = 0, 10 | PxiBlkDevMsg_Init = 1, 11 | PxiBlkDevMsg_ReadSectors = 2, 12 | PxiBlkDevMsg_WriteSectors = 3, 13 | PxiBlkDevMsg_DumpDldi = 4, 14 | 15 | // ARM7 -> ARM9 16 | PxiBlkDevMsg_Removed = 0x1e, 17 | PxiBlkDevMsg_Inserted = 0x1f, 18 | } PxiBlkDevMsgType; 19 | 20 | MK_CONSTEXPR u32 pxiBlkDevMakeMsg(PxiBlkDevMsgType type, unsigned imm) 21 | { 22 | return (type & 0x1f) | ((imm & 0x7ff) << 5); 23 | } 24 | 25 | MK_CONSTEXPR PxiBlkDevMsgType pxiBlkDevMsgGetType(u32 msg) 26 | { 27 | return (PxiBlkDevMsgType)(msg & 0x1f); 28 | } 29 | 30 | MK_CONSTEXPR unsigned pxiBlkDevMsgGetImmediate(u32 msg) 31 | { 32 | return (msg >> 5) & 0x7ff; 33 | } 34 | -------------------------------------------------------------------------------- /source/nds/pxi/mic.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | 6 | typedef enum PxiMicCmd { 7 | PxiMicCmd_SetCpuTimer = 0, 8 | PxiMicCmd_SetDmaRate = 1, 9 | PxiMicCmd_Start = 2, 10 | PxiMicCmd_Stop = 3, 11 | } PxiMicCmd; 12 | 13 | typedef union PxiMicImmDivTimer { 14 | unsigned imm; 15 | struct { 16 | unsigned div : 2; 17 | unsigned timer : 16; 18 | }; 19 | } PxiMicImmDivTimer; 20 | 21 | typedef union PxiMicImmStart { 22 | unsigned imm; 23 | struct { 24 | unsigned is_16bit : 1; 25 | unsigned mode : 2; 26 | }; 27 | } PxiMicImmStart; 28 | 29 | typedef struct PxiMicArgStart { 30 | u32 dest_addr; 31 | u32 dest_sz; 32 | } PxiMicArgStart; 33 | 34 | MK_CONSTEXPR u32 pxiMicMakeCmdMsg(PxiMicCmd cmd, unsigned imm) 35 | { 36 | return (cmd & 7) | (imm << 3); 37 | } 38 | 39 | MK_CONSTEXPR PxiMicCmd pxiMicCmdGetType(u32 msg) 40 | { 41 | return (PxiMicCmd)(msg & 7); 42 | } 43 | 44 | MK_CONSTEXPR unsigned pxiMicCmdGetImm(u32 msg) 45 | { 46 | return msg >> 3; 47 | } 48 | -------------------------------------------------------------------------------- /source/nds/pxi/pm.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include 6 | 7 | typedef enum PxiPmMsgType { 8 | 9 | PxiPmMsg_GetBatteryState = 0, 10 | PxiPmMsg_Sleep = 1, 11 | PxiPmMsg_Wakeup = 2, 12 | PxiPmMsg_ReadNvram = 3, 13 | PxiPmMsg_MicSetAmp = 4, 14 | PxiPmMsg_SetPowerLed = 5, 15 | PxiPmMsg_SetMcPower = 6, 16 | 17 | } PxiPmMsgType; 18 | 19 | MK_CONSTEXPR u32 pxiPmMakeMsg(PxiPmMsgType type, unsigned imm) 20 | { 21 | return (type & 0xff) | (imm << 8); 22 | } 23 | 24 | MK_CONSTEXPR PxiPmMsgType pxiPmGetType(u32 msg) 25 | { 26 | return (PxiPmMsgType)(msg & 0xff); 27 | } 28 | 29 | MK_CONSTEXPR unsigned pxiPmGetImmediate(u32 msg) 30 | { 31 | return msg >> 8; 32 | } 33 | -------------------------------------------------------------------------------- /source/nds/pxi/reset.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | 6 | #define PXI_LIBNDS_FIFO_DATAMSG (0U << 20) 7 | #define PXI_LIBNDS_FIFO_VALUE32 (1U << 20) 8 | #define PXI_LIBNDS_FIFO_ADDRESS (2U << 20) 9 | #define PXI_LIBNDS_FIFO_SPECIAL (3U << 20) 10 | 11 | typedef enum PxiResetMsgType { 12 | PxiResetMsgType_Reset = 0x10, 13 | PxiResetMsgType_Abort = 0x20, 14 | } PxiResetMsgType; 15 | 16 | MK_CONSTEXPR u32 pxiResetMakeMsg(PxiResetMsgType type) 17 | { 18 | return ((type & 0x7f) << 8) | PXI_LIBNDS_FIFO_SPECIAL; 19 | } 20 | 21 | MK_CONSTEXPR PxiResetMsgType pxiResetGetType(u32 msg) 22 | { 23 | return (PxiResetMsgType)((msg >> 8) & 0x7f); 24 | } 25 | -------------------------------------------------------------------------------- /source/nds/pxi/wlmgr.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include 6 | 7 | #define PXI_WLMGR_NUM_CREDITS 32 8 | 9 | typedef enum PxiWlMgrCmd { 10 | PxiWlMgrCmd_Start = 0, 11 | PxiWlMgrCmd_Stop = 1, 12 | PxiWlMgrCmd_StartScan = 2, 13 | PxiWlMgrCmd_Associate = 3, 14 | PxiWlMgrCmd_Disassociate = 4, 15 | } PxiWlMgrCmd; 16 | 17 | typedef struct PxiWlMgrArgAssociate { 18 | WlanBssDesc const* bss; 19 | WlanAuthData const* auth; 20 | } PxiWlMgrArgAssociate; 21 | 22 | MK_CONSTEXPR u32 pxiWlMgrMakeCmd(PxiWlMgrCmd type, unsigned imm) 23 | { 24 | return (type & 0x1f) | (imm << 5); 25 | } 26 | 27 | MK_CONSTEXPR PxiWlMgrCmd pxiWlMgrCmdGetType(u32 msg) 28 | { 29 | return (PxiWlMgrCmd)(msg & 0x1f); 30 | } 31 | 32 | MK_CONSTEXPR unsigned pxiWlMgrCmdGetImm(u32 msg) 33 | { 34 | return msg >> 5; 35 | } 36 | 37 | MK_CONSTEXPR u32 pxiWlMgrMakeEvent(WlMgrEvent type, unsigned imm) 38 | { 39 | return (type & 0xf) | (imm << 4); 40 | } 41 | 42 | MK_CONSTEXPR WlMgrEvent pxiWlMgrEventGetType(u32 msg) 43 | { 44 | return (WlMgrEvent)(msg & 0xf); 45 | } 46 | 47 | MK_CONSTEXPR unsigned pxiWlMgrEventGetImm(u32 msg) 48 | { 49 | return msg >> 4; 50 | } 51 | -------------------------------------------------------------------------------- /source/nds/smutex.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static ThrListNode s_smutexWaitList; 10 | 11 | void smutexLock(SMutex* m) 12 | { 13 | uptr self = (uptr)threadGetSelf(); 14 | ArmIrqState st = armIrqLockByPsr(); 15 | 16 | bool try_again; 17 | do { 18 | while (m->cpu_id != SMUTEX_MY_CPU_ID) { 19 | if (armSwapWord(1, &m->spinner) == 0) { 20 | m->cpu_id = SMUTEX_MY_CPU_ID; 21 | break; 22 | } 23 | pxiWaitForPing(); 24 | } 25 | 26 | try_again = m->thread_ptr != 0; 27 | if (try_again) { 28 | threadBlock(&s_smutexWaitList, (u32)m); 29 | } else { 30 | m->thread_ptr = self; 31 | } 32 | } while (try_again); 33 | 34 | armIrqUnlockByPsr(st); 35 | } 36 | 37 | bool smutexTryLock(SMutex* m) 38 | { 39 | uptr self = (uptr)threadGetSelf(); 40 | ArmIrqState st = armIrqLockByPsr(); 41 | 42 | bool rc = m->cpu_id == SMUTEX_MY_CPU_ID; 43 | if_likely (!rc) { 44 | rc = armSwapWord(1, &m->spinner) == 0; 45 | if_likely (rc) { 46 | m->cpu_id = SMUTEX_MY_CPU_ID; 47 | } 48 | } 49 | if_likely (rc) { 50 | rc = m->thread_ptr == 0; 51 | if_likely (rc) { 52 | m->thread_ptr = self; 53 | } 54 | } 55 | 56 | armIrqUnlockByPsr(st); 57 | return rc; 58 | } 59 | 60 | void smutexUnlock(SMutex* m) 61 | { 62 | uptr self = (uptr)threadGetSelf(); 63 | ArmIrqState st = armIrqLockByPsr(); 64 | 65 | // Check for naughty callers 66 | if (m->cpu_id != SMUTEX_MY_CPU_ID || m->thread_ptr != self) { 67 | armIrqUnlockByPsr(st); 68 | return; 69 | } 70 | 71 | m->thread_ptr = 0; 72 | m->cpu_id = 0; 73 | armCompilerBarrier(); // Make sure the spinner is cleared *after* the control word 74 | m->spinner = 0; 75 | pxiPing(); 76 | threadUnblockAllByValue(&s_smutexWaitList, (u32)m); 77 | armIrqUnlockByPsr(st); 78 | } 79 | -------------------------------------------------------------------------------- /source/nds/transfer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define s_debugBuf ((DebugBuffer*) MM_ENV_FREE_D000) 9 | 10 | #define s_transferRegion ((TransferRegion*) MM_ENV_FREE_FF60) 11 | #if defined(ARM9) 12 | #define s_pxiLocalPxiMask s_transferRegion->arm9_pxi_mask 13 | #define s_pxiRemotePxiMask s_transferRegion->arm7_pxi_mask 14 | #elif defined(ARM7) 15 | #define s_pxiLocalPxiMask s_transferRegion->arm7_pxi_mask 16 | #define s_pxiRemotePxiMask s_transferRegion->arm9_pxi_mask 17 | #else 18 | #error "Must be ARM9 or ARM7" 19 | #endif 20 | 21 | #define DBG_BUF_ALIVE (1U << 0) 22 | #define DBG_BUF_BUSY (1U << 1) 23 | 24 | #define TOUCH_BUF (1U << 0) 25 | #define TOUCH_VALID (1U << 1) 26 | 27 | typedef struct DebugBuffer { 28 | vu16 flags; 29 | u16 size; 30 | char data[MM_ENV_FREE_D000_SZ - 4]; 31 | } DebugBuffer; 32 | 33 | typedef struct TransferRegion { 34 | u32 arm9_pxi_mask; 35 | u32 arm7_pxi_mask; 36 | 37 | u32 unix_time; 38 | u16 keypad_ext; 39 | 40 | vu16 touch_state; 41 | u16 touch_data[2][4]; 42 | 43 | u32 blkdev_sector_count[3]; 44 | 45 | u16 sound_active_ch_mask; 46 | u16 sound_reserved; 47 | 48 | u16 exmemcnt_mirror; 49 | } TransferRegion; 50 | -------------------------------------------------------------------------------- /source/nds/utils.crt0.s: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #define armCopyMem32 crt0CopyMem32 4 | #define armFillMem32 crt0FillMem32 5 | #include "../arm/arm-copy-fill.32.s" 6 | -------------------------------------------------------------------------------- /source/system/irq.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | 6 | extern IrqHandler __irq_table[MK_IRQ_NUM_HANDLERS]; 7 | 8 | MK_INLINE bool _irqMaskUnpack(IrqMask* pmask, unsigned* pid) 9 | { 10 | #if (__ARM_ARCH < 5) || __thumb__ 11 | if (!*pmask) 12 | return false; 13 | while (!(*pmask & (1U << *pid))) 14 | ++*pid; 15 | #else 16 | int id = __builtin_ffs(*pmask)-1; 17 | if (id < 0) 18 | return false; 19 | *pid = id; 20 | #endif 21 | *pmask &= ~(1U << *pid); 22 | return true; 23 | } 24 | 25 | void irqSet(IrqMask mask, IrqHandler handler) 26 | { 27 | IrqState st = irqLock(); 28 | unsigned id = 0; 29 | while (_irqMaskUnpack(&mask, &id)) 30 | __irq_table[id] = handler; 31 | irqUnlock(st); 32 | } 33 | 34 | #if MK_IRQ_NUM_HANDLERS > 32 35 | 36 | void irqSet2(IrqMask mask, IrqHandler handler) 37 | { 38 | IrqState st = irqLock(); 39 | unsigned id = 0; 40 | while (_irqMaskUnpack(&mask, &id)) 41 | __irq_table[id+32] = handler; 42 | irqUnlock(st); 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /source/system/mailbox.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static ThrListNode s_mailboxRecvQueue; 9 | 10 | bool mailboxTrySend(Mailbox* mb, u32 message) 11 | { 12 | ArmIrqState st = armIrqLockByPsr(); 13 | 14 | if_unlikely (mb->pending_slots == mb->num_slots) { 15 | armIrqUnlockByPsr(st); 16 | return false; 17 | } 18 | 19 | unsigned next_slot = mb->cur_slot + mb->pending_slots++; 20 | if (next_slot >= mb->num_slots) { 21 | next_slot -= mb->num_slots; 22 | } 23 | 24 | mb->slots[next_slot] = message; 25 | if_likely (mb->recv_waiters) { 26 | mb->recv_waiters --; 27 | threadUnblockOneByValue(&s_mailboxRecvQueue, (u32)mb); 28 | } 29 | 30 | armIrqUnlockByPsr(st); 31 | return true; 32 | } 33 | 34 | bool mailboxTryRecv(Mailbox* mb, u32* out) 35 | { 36 | ArmIrqState st = armIrqLockByPsr(); 37 | 38 | if_unlikely (!mb->pending_slots) { 39 | armIrqUnlockByPsr(st); 40 | return false; 41 | } 42 | 43 | *out = mb->slots[mb->cur_slot++]; 44 | mb->pending_slots --; 45 | if (mb->cur_slot >= mb->num_slots) { 46 | mb->cur_slot -= mb->num_slots; 47 | } 48 | 49 | armIrqUnlockByPsr(st); 50 | return true; 51 | } 52 | 53 | u32 mailboxRecv(Mailbox* mb) 54 | { 55 | ArmIrqState st = armIrqLockByPsr(); 56 | 57 | if_unlikely (!mb->pending_slots) { 58 | mb->recv_waiters ++; 59 | threadBlock(&s_mailboxRecvQueue, (u32)mb); 60 | } 61 | 62 | u32 message = mb->slots[mb->cur_slot++]; 63 | mb->pending_slots --; 64 | if (mb->cur_slot >= mb->num_slots) { 65 | mb->cur_slot -= mb->num_slots; 66 | } 67 | 68 | armIrqUnlockByPsr(st); 69 | return message; 70 | } 71 | -------------------------------------------------------------------------------- /source/system/thread-priv.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern ThrSchedState __sched_state; 11 | 12 | #define s_curThread __sched_state.cur 13 | #define s_deferredThread __sched_state.deferred 14 | #define s_firstThread __sched_state.first 15 | #define s_irqWaitMask __sched_state.irqWaitMask 16 | #define s_irqWaitList __sched_state.irqWaitList 17 | #if MK_IRQ_NUM_HANDLERS > 32 18 | #define s_irqWaitMask2 __sched_state.irqWaitMask2 19 | #define s_irqWaitList2 __sched_state.irqWaitList2 20 | #endif 21 | 22 | MK_INLINE Thread* threadGetInsertPosition(Thread* t) 23 | { 24 | Thread* pos = NULL; 25 | for (Thread* cur = s_firstThread; cur && cur->prio <= t->prio; cur = cur->next) 26 | pos = cur; 27 | return pos; 28 | } 29 | 30 | MK_INLINE Thread* threadGetPrevious(Thread* t) 31 | { 32 | Thread* pos = NULL; 33 | for (Thread* cur = s_firstThread; cur && cur != t; cur = cur->next) 34 | pos = cur; 35 | return pos; 36 | } 37 | 38 | MK_INLINE void threadEnqueue(Thread* t) 39 | { 40 | Thread* pos = threadGetInsertPosition(t); 41 | if (pos) { 42 | t->next = pos->next; 43 | pos->next = t; 44 | } else { 45 | t->next = s_firstThread; 46 | s_firstThread = t; 47 | } 48 | } 49 | 50 | MK_INLINE void threadDequeue(Thread* t) 51 | { 52 | Thread* prev = threadGetPrevious(t); 53 | if (prev) 54 | prev->next = t->next; 55 | else 56 | s_firstThread = t->next; 57 | } 58 | 59 | MK_INLINE Thread* threadFindRunnable(Thread* first) 60 | { 61 | Thread* t; 62 | for (t = first; t && !threadIsRunning(t); t = t->next); 63 | return t; 64 | } 65 | 66 | MK_INLINE void threadSwitchTo(Thread* t, ArmIrqState st) 67 | { 68 | if (!armContextSave(&__sched_state.cur->ctx, st, 1)) { 69 | s_curThread = t; 70 | armContextLoad(&t->ctx); 71 | } 72 | } 73 | 74 | MK_INLINE Thread* threadLinkGetInsertPosition(ThrListNode* queue, Thread* t) 75 | { 76 | Thread* pos; 77 | for (pos = queue->next; pos && pos->prio <= t->prio; pos = pos->link.next); 78 | return pos ? pos->link.prev : queue->prev; 79 | } 80 | 81 | MK_INLINE void threadLinkEnqueue(ThrListNode* queue, Thread* t) 82 | { 83 | Thread* pos = threadLinkGetInsertPosition(queue, t); 84 | if (pos) { 85 | t->link.next = pos->link.next; 86 | t->link.prev = pos; 87 | pos->link.next = t; 88 | } else { 89 | t->link.next = queue->next; 90 | t->link.prev = NULL; 91 | queue->next = t; 92 | } 93 | if (t->link.next) 94 | t->link.next->link.prev = t; 95 | else 96 | queue->prev = t; 97 | t->queue = queue; 98 | } 99 | 100 | MK_INLINE void threadLinkDequeue(ThrListNode* queue, Thread* t) 101 | { 102 | if (t->queue != queue) 103 | return; 104 | t->queue = NULL; 105 | (t->link.prev ? &t->link.prev->link : queue)->next = t->link.next; 106 | (t->link.next ? &t->link.next->link : queue)->prev = t->link.prev; 107 | } 108 | 109 | MK_INLINE bool threadTestUnblock(Thread* t, ThrUnblockMode mode, u32 ref) 110 | { 111 | switch (mode) { 112 | default: 113 | case ThrUnblockMode_Any: 114 | return true; 115 | case ThrUnblockMode_ByValue: 116 | return t->token == ref; 117 | case ThrUnblockMode_ByMask: 118 | return (t->token & ref) != 0; 119 | } 120 | } 121 | 122 | //MK_EXTERN32 void _threadReschedule(Thread* t, ArmIrqState st); 123 | -------------------------------------------------------------------------------- /source/system/thread_hot.32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ZPL-2.1 2 | // SPDX-FileCopyrightText: Copyright fincs, devkitPro 3 | #include "thread-priv.h" 4 | 5 | ThrSchedState __sched_state; 6 | IrqHandler __irq_table[MK_IRQ_NUM_HANDLERS]; 7 | 8 | static void threadReschedule(Thread* t, ArmIrqState st) 9 | { 10 | if_unlikely (s_curThread->status == ThrStatus_Finished) 11 | return; 12 | 13 | if_likely ((armGetCpsr() & ARM_PSR_MODE_MASK) == ARM_PSR_MODE_IRQ) { 14 | if (!s_deferredThread || t->prio < s_deferredThread->prio) 15 | s_deferredThread = t; 16 | armIrqUnlockByPsr(st); 17 | return; 18 | } 19 | 20 | threadSwitchTo(t, st); 21 | } 22 | 23 | void threadBlock(ThrListNode* queue, u32 token) 24 | { 25 | ArmIrqState st = armIrqLockByPsr(); 26 | s_curThread->status = ThrStatus_Waiting; 27 | s_curThread->token = token; 28 | threadLinkEnqueue(queue, s_curThread); 29 | threadReschedule(threadFindRunnable(s_firstThread), st); 30 | } 31 | 32 | MK_INLINE void _threadUnblockCommon(ThrListNode* queue, int max, ThrUnblockMode mode, u32 ref) 33 | { 34 | //if (max == 0) return; 35 | //if (max < 0) max = -1; 36 | 37 | ArmIrqState st = armIrqLockByPsr(); 38 | Thread* resched = NULL; 39 | Thread* next; 40 | 41 | for (Thread* cur = queue->next; max != 0 && cur; cur = next) { 42 | next = cur->link.next; 43 | if (threadTestUnblock(cur, mode, ref)) { 44 | if (!resched) 45 | resched = cur; // Remember the first unblocked (highest priority) thread 46 | cur->status = ThrStatus_Running; 47 | if (mode == ThrUnblockMode_ByMask) 48 | cur->token &= ref; 49 | threadLinkDequeue(queue, cur); 50 | if (max > 0) --max; 51 | //max = (max > 0) ? (max - 1) : max; 52 | } 53 | } 54 | 55 | if (resched && resched->prio < s_curThread->prio) 56 | threadReschedule(resched, st); 57 | else 58 | armIrqUnlockByPsr(st); 59 | } 60 | 61 | void threadUnblock(ThrListNode* queue, int max, ThrUnblockMode mode, u32 ref) 62 | { 63 | _threadUnblockCommon(queue, max, mode, ref); 64 | } 65 | 66 | void threadUnblockOneByValue(ThrListNode* queue, u32 ref) 67 | { 68 | _threadUnblockCommon(queue, +1, ThrUnblockMode_ByValue, ref); 69 | } 70 | 71 | void threadUnblockOneByMask(ThrListNode* queue, u32 ref) 72 | { 73 | _threadUnblockCommon(queue, +1, ThrUnblockMode_ByMask, ref); 74 | } 75 | 76 | void threadUnblockAllByValue(ThrListNode* queue, u32 ref) 77 | { 78 | _threadUnblockCommon(queue, -1, ThrUnblockMode_ByValue, ref); 79 | } 80 | 81 | void threadUnblockAllByMask(ThrListNode* queue, u32 ref) 82 | { 83 | _threadUnblockCommon(queue, -1, ThrUnblockMode_ByMask, ref); 84 | } 85 | --------------------------------------------------------------------------------