├── .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 |
--------------------------------------------------------------------------------