diff --git a/arm11/Makefile b/arm11/Makefile index 154d924..2333e5b 100644 --- a/arm11/Makefile +++ b/arm11/Makefile @@ -18,7 +18,9 @@ #--------------------------------------------------------------------------------- #TARGET := $(notdir $(CURDIR)) BUILD := build -SOURCES := ../source ../source/hardware ../source/arm11 ../source/arm11/hardware ../source/arm11/menu +SOURCES := ../source ../source/hardware ../source/arm11 \ + ../source/arm11/allocator ../source/arm11/hardware \ + ../source/arm11/menu ../source/arm11/util/rbtree DATA := INCLUDES := ../include ../thirdparty DEFINES := -DARM11 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \ diff --git a/include/arm11/allocator/vram.h b/include/arm11/allocator/vram.h new file mode 100644 index 0000000..3658699 --- /dev/null +++ b/include/arm11/allocator/vram.h @@ -0,0 +1,47 @@ +/** + * @file vram.h + * @brief VRAM allocator. + */ +#pragma once + +/** + * @brief Allocates a 0x80-byte aligned buffer. + * @param size Size of the buffer to allocate. + * @return The allocated buffer. + */ +void* vramAlloc(size_t size); + +/** + * @brief Allocates a buffer aligned to the given size. + * @param size Size of the buffer to allocate. + * @param alignment Alignment to use. + * @return The allocated buffer. + */ +void* vramMemAlign(size_t size, size_t alignment); + +/** + * @brief Reallocates a buffer. + * Note: Not implemented yet. + * @param mem Buffer to reallocate. + * @param size Size of the buffer to allocate. + * @return The reallocated buffer. + */ +void* vramRealloc(void* mem, size_t size); + +/** + * @brief Retrieves the allocated size of a buffer. + * @return The size of the buffer. + */ +size_t vramGetSize(void* mem); + +/** + * @brief Frees a buffer. + * @param mem Buffer to free. + */ +void vramFree(void* mem); + +/** + * @brief Gets the current VRAM free space. + * @return The current VRAM free space. + */ +u32 vramSpaceFree(void); diff --git a/include/arm11/hardware/codec.h b/include/arm11/hardware/codec.h index 59a4aa5..d061820 100644 --- a/include/arm11/hardware/codec.h +++ b/include/arm11/hardware/codec.h @@ -21,6 +21,15 @@ #include "types.h" +typedef struct +{ + u16 touchX[5]; + u16 touchY[5]; + u16 cpadY[8]; + u16 cpadX[8]; +} CdcAdcData; + + /** * @brief Initialize CODEC for Circle-Pad/Touchscreen/Sound. @@ -40,6 +49,8 @@ /** * @brief Get raw ADC data for Circle-Pad/Touchscreen. * - * @param[in] buf The buffer to write the data to. + * @param data The output data pointer. Must be 4 bytes aligned. + * + * @return Returns true if data was available and false otherwise. */ -void CODEC_getRawAdcData(u32 buf[13]); +bool CODEC_getRawAdcData(CdcAdcData *data); diff --git a/include/arm11/hardware/hid.h b/include/arm11/hardware/hid.h index 3ea4338..4b9e771 100644 --- a/include/arm11/hardware/hid.h +++ b/include/arm11/hardware/hid.h @@ -23,12 +23,15 @@ */ #include "types.h" +#include "mem_map.h" -#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) +#define HID_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x46000) +#define REG_HID_PAD (*((vu16*)(HID_REGS_BASE + 0x0)) ^ 0xFFFFu) +#define REG_HID_PADCNT *((vu16*)(HID_REGS_BASE + 0x2)) -#define HID_KEY_MASK_ALL ((1u<<12) - 1) +#define HID_KEY_MASK_ALL ((1u<<12) - 1) enum { @@ -61,6 +64,11 @@ KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, // D-Pad Down or Circle Pad Down KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, // D-Pad Left or Circle Pad Left KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT, // D-Pad Right or Circle Pad Right + + // Masks + KEY_DPAD = KEY_DDOWN | KEY_DUP | KEY_DLEFT | KEY_DRIGHT, + KEY_CSTICK = KEY_CSTICK_DOWN | KEY_CSTICK_UP | KEY_CSTICK_LEFT | KEY_CSTICK_RIGHT, + KEY_CPAD = KEY_CPAD_DOWN | KEY_CPAD_UP | KEY_CPAD_LEFT | KEY_CPAD_RIGHT }; // Extra keys use with hidGetExtraKeys() diff --git a/include/arm11/hardware/interrupt.h b/include/arm11/hardware/interrupt.h index 7ce116d..82f2838 100644 --- a/include/arm11/hardware/interrupt.h +++ b/include/arm11/hardware/interrupt.h @@ -82,6 +82,24 @@ IRQ_PDC1 = 43u, // aka VBlank1 IRQ_PPF = 44u, IRQ_P3D = 45u, + IRQ_CDMA_EVENT0 = 48u, // Old 3DS CDMA + IRQ_CDMA_EVENT1 = 49u, // Old 3DS CDMA + IRQ_CDMA_EVENT2 = 50u, // Old 3DS CDMA + IRQ_CDMA_EVENT3 = 51u, // Old 3DS CDMA + IRQ_CDMA_EVENT4 = 52u, // Old 3DS CDMA + IRQ_CDMA_EVENT5 = 53u, // Old 3DS CDMA + IRQ_CDMA_EVENT6 = 54u, // Old 3DS CDMA + IRQ_CDMA_EVENT7 = 55u, // Old 3DS CDMA + IRQ_CDMA_EVENT8 = 56u, // Old 3DS CDMA + IRQ_CDMA_FAULT = 57u, // Old 3DS CDMA + IRQ_CDMA2_EVENT = 58u, // New 3DS CDMA + IRQ_CDMA2_FAULT = 59u, // New 3DS CDMA + IRQ_SDIO = 64u, // SDIO controller (WiFi) + IRQ_SDIO_IRQ = 65u, // SDIO IRQ pin (WiFi) + IRQ_CAM0 = 72u, // Camera 0 (DSi) + IRQ_CAM1 = 73u, // Camera 1 (left eye) + IRQ_LGYFB_BOT = 76u, // Legacy framebuffer bottom screen + IRQ_LGYFB_TOP = 77u, // Legacy framebuffer top screen IRQ_PXI_SYNC = 80u, IRQ_PXI_SYNC2 = 81u, IRQ_PXI_NOT_FULL = 82u, @@ -91,6 +109,8 @@ IRQ_SPI3 = 86u, // SPI bus 3 interrupt status update IRQ_SPI1 = 87u, // SPI bus 1 interrupt status update IRQ_PDN = 88u, + IRQ_LGY_SLEEP = 89u, // Triggers if legacy mode enters sleep. + IRQ_HID_PADCNT = 91u, IRQ_I2C3 = 92u, IRQ_GPIO_1_2 = 96u, IRQ_SHELL_CLOSED = 98u, // GPIO_1_0? diff --git a/include/arm11/hardware/mcu.h b/include/arm11/hardware/mcu.h index 181cdaa..a3e3dbb 100644 --- a/include/arm11/hardware/mcu.h +++ b/include/arm11/hardware/mcu.h @@ -19,19 +19,33 @@ */ #include "types.h" +#include "arm11/hardware/i2c.h" -#define MCU_HID_POWER_BUTTON_PRESSED (1u) -#define MCU_HID_POWER_BUTTON_LONG_PRESSED (1u<<1) -#define MCU_HID_HOME_BUTTON_PRESSED (1u<<2) -#define MCU_HID_HOME_BUTTON_RELEASED (1u<<3) -#define MCU_HID_HOME_BUTTON_NOT_HELD (1u<<1) -#define MCU_HID_SHELL_GOT_CLOSED (1u<<5) -#define MCU_HID_SHELL_GOT_OPENED (1u<<6) - typedef enum { - PWLED_NORMAL = 0u, + MCU_REG_VERS_HIGH = 0x00u, + MCU_REG_VERS_LOW = 0x01u, + MCU_REG_3D_SLIDER = 0x08u, + MCU_REG_VOL_SLIDER = 0x09u, // 0-0x3F + MCU_REG_BATTERY = 0x0Bu, + MCU_REG_EX_HW_STATE = 0x0Fu, + MCU_REG_EVENTS = 0x10u, + MCU_REG_EVENT_MASK = 0x18u, + MCU_REG_POWER = 0x20u, + MCU_REG_LCDs = 0x22u, + MCU_REG_POWER_LED = 0x29u, + MCU_REG_WIFI_LED = 0x2Au, + MCU_REG_CAM_LED = 0x2Bu, + MCU_REG_3D_LED = 0x2Cu, + MCU_REG_RTC_TIME = 0x30u, + MCU_REG_RAW_STATE = 0x7Fu +} McuReg; + +typedef enum +{ + PWLED_AUTO = 0u, + //PWLED_BLUE = 1u, // wtf is "forced default blue"? PWLED_SLEEP = 2u, PWLED_OFF = 3u, PWLED_RED = 4u, @@ -42,17 +56,77 @@ void MCU_init(void); -void MCU_disableLEDs(void); -void MCU_powerOnLCDs(void); -void MCU_powerOffLCDs(void); -void MCU_triggerPowerOff(void); -void MCU_triggerReboot(void); -u8 MCU_readBatteryLevel(void); -u8 MCU_readExternalHwState(void); -u8 MCU_readSystemModel(void); -void MCU_readRTC(void *rtc); -u32 MCU_readReceivedIrqs(void); -bool MCU_setIrqBitmask(u32 mask); -u8 MCU_readHidHeld(void); -bool MCU_powerOnLcdBacklights(void); -bool MCU_setPowerLedState(PwLedState state); + +bool MCU_setEventMask(u32 mask); + +u32 MCU_getEvents(u32 mask); + +u32 MCU_waitEvents(u32 mask); + +u8 MCU_readReg(McuReg reg); + +bool MCU_writeReg(McuReg reg, u8 data); + +bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size); + +bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size); + + +static inline u8 MCU_getBatteryLevel(void) +{ + u8 state; + + if(!MCU_readRegBuf(MCU_REG_BATTERY, &state, 1)) return 0; + + return state; +} + +static inline u8 MCU_getExternalHwState(void) +{ + return MCU_readReg(MCU_REG_EX_HW_STATE); +} + +static inline void MCU_powerOffSys(void) +{ + I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u); +} + +static inline void MCU_rebootSys(void) +{ + I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u<<2); +} + +static inline void MCU_controlLCDPower(u8 bits) +{ + MCU_writeReg(MCU_REG_LCDs, bits); +} + +static inline bool MCU_setPowerLedState(PwLedState state) +{ + return MCU_writeReg(MCU_REG_POWER_LED, state); +} + +static inline bool MCU_getRTCTime(u8 *rtc) +{ + if(!rtc) return true; + + return MCU_readRegBuf(MCU_REG_RTC_TIME, rtc, 8); +} + +static inline u8 MCU_getSystemModel(void) +{ + u8 buf[10]; + + if(!MCU_readRegBuf(MCU_REG_RAW_STATE, buf, sizeof(buf))) return 0xFF; + + return buf[9]; +} + +static inline u8 MCU_getHidHeld(void) +{ + u8 data[19]; + + if(!MCU_readRegBuf(MCU_REG_RAW_STATE, data, sizeof(data))) return 0xFF; + + return data[18]; +} diff --git a/include/arm11/util/rbtree.h b/include/arm11/util/rbtree.h new file mode 100644 index 0000000..08778b9 --- /dev/null +++ b/include/arm11/util/rbtree.h @@ -0,0 +1,149 @@ +/** + * @file rbtree.h + * @brief Red-black trees. + */ +#pragma once + +#include +#include + +/// Retrieves an rbtree item. +#define rbtree_item(ptr, type, member) \ + ((type*)(((char*)ptr) - offsetof(type, member))) + +typedef struct rbtree rbtree_t; ///< rbtree type. +typedef struct rbtree_node rbtree_node_t; ///< rbtree node type. + +typedef void (*rbtree_node_destructor_t)(rbtree_node_t *Node); ///< rbtree node destructor. +typedef int (*rbtree_node_comparator_t)(const rbtree_node_t *lhs, + const rbtree_node_t *rhs); ///< rbtree node comparator. + +/// An rbtree node. +struct rbtree_node +{ + uintptr_t parent_color; ///< Parent color. + rbtree_node_t *child[2]; ///< Node children. +}; + +/// An rbtree. +struct rbtree +{ + rbtree_node_t *root; ///< Root node. + rbtree_node_comparator_t comparator; ///< Node comparator. + size_t size; ///< Size. +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initializes an rbtree. + * @param tree Pointer to the tree. + * @param comparator Comparator to use. + */ +void +rbtree_init(rbtree_t *tree, + rbtree_node_comparator_t comparator); + +/** + * @brief Gets whether an rbtree is empty + * @param tree Pointer to the tree. + * @return A non-zero value if the tree is not empty. + */ +int +rbtree_empty(const rbtree_t *tree); + +/** + * @brief Gets the size of an rbtree. + * @param tree Pointer to the tree. + */ +size_t +rbtree_size(const rbtree_t *tree); + +/** + * @brief Inserts a node into an rbtree. + * @param tree Pointer to the tree. + * @param node Pointer to the node. + * @return The inserted node. + */ +__attribute__((warn_unused_result)) +rbtree_node_t* +rbtree_insert(rbtree_t *tree, + rbtree_node_t *node); + +/** + * @brief Inserts multiple nodes into an rbtree. + * @param tree Pointer to the tree. + * @param node Pointer to the nodes. + */ +void +rbtree_insert_multi(rbtree_t *tree, + rbtree_node_t *node); + +/** + * @brief Finds a node within an rbtree. + * @param tree Pointer to the tree. + * @param node Pointer to the node. + * @return The located node. + */ +rbtree_node_t* +rbtree_find(const rbtree_t *tree, + const rbtree_node_t *node); + +/** + * @brief Gets the minimum node of an rbtree. + * @param tree Pointer to the tree. + * @return The minimum node. + */ +rbtree_node_t* +rbtree_min(const rbtree_t *tree); + +/** + * @brief Gets the maximum node of an rbtree. + * @param tree Pointer to the tree. + * @return The maximum node. + */ +rbtree_node_t* +rbtree_max(const rbtree_t *tree); + +/** + * @brief Gets the next node from an rbtree node. + * @param node Pointer to the node. + * @return The next node. + */ +rbtree_node_t* +rbtree_node_next(const rbtree_node_t *node); + +/** + * @brief Gets the previous node from an rbtree node. + * @param node Pointer to the node. + * @return The previous node. + */ +rbtree_node_t* +rbtree_node_prev(const rbtree_node_t *node); + +/** + * @brief Removes a node from an rbtree. + * @param tree Pointer to the tree. + * @param node Pointer to the node. + * @param destructor Destructor to use when removing the node. + * @return The removed node. + */ +rbtree_node_t* +rbtree_remove(rbtree_t *tree, + rbtree_node_t *node, + rbtree_node_destructor_t destructor); + +/** + * @brief Clears an rbtree. + * @param tree Pointer to the tree. + * @param destructor Destructor to use when clearing the tree's nodes. + */ +void +rbtree_clear(rbtree_t *tree, + rbtree_node_destructor_t destructor); + +#ifdef __cplusplus +} +#endif diff --git a/include/hardware/gfx.h b/include/hardware/gfx.h index c2a8c54..d39ed70 100644 --- a/include/hardware/gfx.h +++ b/include/hardware/gfx.h @@ -22,23 +22,23 @@ #include "types.h" -#define SCREEN_TOP (1) -#define SCREEN_SUB (0) +#define SCREEN_TOP (0u) +#define SCREEN_BOT (1u) -#define SCREEN_WIDTH_TOP (400) -#define SCREEN_HEIGHT_TOP (240) +#define SCREEN_WIDTH_TOP (400u) +#define SCREEN_HEIGHT_TOP (240u) #define SCREEN_SIZE_TOP (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2) -#define SCREEN_WIDTH_SUB (320) -#define SCREEN_HEIGHT_SUB (240) -#define SCREEN_SIZE_SUB (SCREEN_WIDTH_SUB * SCREEN_HEIGHT_SUB * 2) +#define SCREEN_WIDTH_BOT (320u) +#define SCREEN_HEIGHT_BOT (240u) +#define SCREEN_SIZE_BOT (SCREEN_WIDTH_BOT * SCREEN_HEIGHT_BOT * 2) -#define FRAMEBUF_TOP_A_1 (VRAM_BASE) -#define FRAMEBUF_SUB_A_1 (FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP) -#define FRAMEBUF_TOP_A_2 (VRAM_BASE + 0x100000) -#define FRAMEBUF_SUB_A_2 (FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP) +#define FRAMEBUF_TOP_A_1 ((void*)VRAM_BASE) +#define FRAMEBUF_BOT_A_1 ((void*)FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP) +#define FRAMEBUF_TOP_A_2 ((void*)VRAM_BASE + 0x100000) +#define FRAMEBUF_BOT_A_2 ((void*)FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP) -#define RENDERBUF_TOP (VRAM_BASE + 0x200000 - SCREEN_SIZE_TOP - SCREEN_SIZE_SUB) -#define RENDERBUF_SUB (VRAM_BASE + 0x200000 - SCREEN_SIZE_SUB) +#define RENDERBUF_TOP ((void*)VRAM_BASE + 0x200000 - SCREEN_SIZE_TOP - SCREEN_SIZE_BOT) +#define RENDERBUF_BOT ((void*)VRAM_BASE + 0x200000 - SCREEN_SIZE_BOT) #define DEFAULT_BRIGHTNESS (0x30) @@ -46,6 +46,17 @@ #define RGB8_to_565(r,g,b) (((b)>>3)&0x1f)|((((g)>>2)&0x3f)<<5)|((((r)>>3)&0x1f)<<11) +/// Framebuffer format. +typedef enum +{ + GFX_RGBA8 = 0, ///< RGBA8. (4 bytes) + GFX_BGR8 = 1, ///< BGR8. (3 bytes) + GFX_RGB565 = 2, ///< RGB565. (2 bytes) + GFX_RGB5A1 = 3, ///< RGB5A1. (2 bytes) + GFX_RGBA4 = 4 ///< RGBA4. (2 bytes) +} GfxFbFmt; + + #ifdef ARM11 typedef enum { @@ -59,16 +70,39 @@ -void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1); -void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags); -void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size); -void GFX_setBrightness(u32 top, u32 sub); +void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot); + +static inline void GFX_initDefault(void) +{ + GFX_init(GFX_BGR8, GFX_BGR8); +} + +void GFX_deinit(void); + +void GFX_gpuInit(void); + +void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot); + +void GFX_setBrightness(u8 top, u8 bot); + +void GFX_setForceBlack(bool top, bool bot); + void* GFX_getFramebuffer(u8 screen); + void GFX_swapFramebufs(void); + void GFX_waitForEvent(GfxEvent event, bool discard); -void GFX_init(bool clearScreens); -void GFX_enterLowPowerState(void); -void GFX_returnFromLowPowerState(void); -void GFX_deinit(bool keepLcdsOn); + +void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1); + +void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags); + +void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size); + +void GX_processCommandList(u32 size, const u32 *const cmdList); + +//void GFX_enterLowPowerState(void); + +//void GFX_returnFromLowPowerState(void); #endif diff --git a/source/arm11/allocator/addrmap.h b/source/arm11/allocator/addrmap.h new file mode 100644 index 0000000..11e8183 --- /dev/null +++ b/source/arm11/allocator/addrmap.h @@ -0,0 +1,48 @@ +#pragma once + +static rbtree_t sAddrMap; + +struct addrMapNode +{ + rbtree_node node; + MemChunk chunk; +}; + +#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node) + +static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs) +{ + auto lhs = getAddrMapNode(_lhs)->chunk.addr; + auto rhs = getAddrMapNode(_rhs)->chunk.addr; + if (lhs < rhs) + return -1; + if (lhs > rhs) + return 1; + return 0; +} + +static void addrMapNodeDestructor(rbtree_node_t* a) +{ + free(getAddrMapNode(a)); +} + +static addrMapNode* getNode(void* addr) +{ + addrMapNode n; + n.chunk.addr = (u8*)addr; + auto p = rbtree_find(&sAddrMap, &n.node); + return p ? getAddrMapNode(p) : nullptr; +} + +static addrMapNode* newNode(const MemChunk& chunk) +{ + auto p = (addrMapNode*)malloc(sizeof(addrMapNode)); + if (!p) return nullptr; + p->chunk = chunk; + return p; +} + +static void delNode(addrMapNode* node) +{ + rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor); +} diff --git a/source/arm11/allocator/mem_pool.cpp b/source/arm11/allocator/mem_pool.cpp new file mode 100644 index 0000000..7482cc6 --- /dev/null +++ b/source/arm11/allocator/mem_pool.cpp @@ -0,0 +1,154 @@ +#include "mem_pool.h" + +/* +// This method is currently unused +void MemPool::CoalesceLeft(MemBlock* b) +{ + auto curPtr = b->base; + for (auto p = b->prev; p; p = p->prev) + { + if ((p->base + p->size) != curPtr) break; + curPtr = p->base; + p->size += b->size; + DelBlock(b); + b = p; + } +} +*/ + +void MemPool::CoalesceRight(MemBlock* b) +{ + auto curPtr = b->base + b->size; + auto next = b->next; + for (auto n = next; n; n = next) + { + next = n->next; + if (n->base != curPtr) break; + b->size += n->size; + curPtr += n->size; + DelBlock(n); + } +} + +bool MemPool::Allocate(MemChunk& chunk, u32 size, int align) +{ + // Don't shift out of bounds (CERT INT34-C) + if(align >= 32 || align < 0) + return false; + + // Alignment must not be 0 + if(align == 0) + return false; + + u32 alignMask = (1 << align) - 1; + + // Check if size doesn't fit neatly in alignment + if(size & alignMask) + { + // Make sure addition won't overflow (CERT INT30-C) + if(size > UINT32_MAX - alignMask) + return false; + + // Pad size to next alignment + size = (size + alignMask) &~ alignMask; + } + + // Find the first suitable block + for (auto b = first; b; b = b->next) + { + auto addr = b->base; + u32 begWaste = (u32)addr & alignMask; + if (begWaste > 0) begWaste = alignMask + 1 - begWaste; + if (begWaste > b->size) continue; + addr += begWaste; + u32 bSize = b->size - begWaste; + if (bSize < size) continue; + + // Found space! + chunk.addr = addr; + chunk.size = size; + + // Resize the block + if (!begWaste) + { + b->base += size; + b->size -= size; + if (!b->size) + DelBlock(b); + } else + { + auto nAddr = addr + size; + auto nSize = bSize - size; + b->size = begWaste; + if (nSize) + { + // We need to add the tail chunk that wasn't used to the list + auto n = MemBlock::Create(nAddr, nSize); + if (n) InsertAfter(b, n); + else chunk.size += nSize; // we have no choice but to waste the space. + } + } + return true; + } + + return false; +} + +void MemPool::Deallocate(const MemChunk& chunk) +{ + u8* cAddr = chunk.addr; + auto cSize = chunk.size; + bool done = false; + + // Try to merge the chunk somewhere into the list + for (auto b = first; !done && b; b = b->next) + { + auto addr = b->base; + if (addr > cAddr) + { + if ((cAddr + cSize) == addr) + { + // Merge the chunk to the left of the block + b->base = cAddr; + b->size += cSize; + } else + { + // We need to insert a new block + auto c = MemBlock::Create(cAddr, cSize); + if (c) InsertBefore(b, c); + } + done = true; + } else if ((b->base + b->size) == cAddr) + { + // Coalesce to the right + b->size += cSize; + CoalesceRight(b); + done = true; + } + } + + if (!done) + { + // Either the list is empty or the chunk address is past the end + // address of the last block -- let's add a new block at the end + auto b = MemBlock::Create(cAddr, cSize); + if (b) AddBlock(b); + } +} + +/* +void MemPool::Dump(const char* title) +{ + printf("<%s> VRAM Pool Dump\n", title); + for (auto b = first; b; b = b->next) + printf(" - %p (%u bytes)\n", b->base, b->size); +} +*/ + +u32 MemPool::GetFreeSpace() +{ + u32 acc = 0; + for (auto b = first; b; b = b->next) + acc += b->size; + return acc; +} diff --git a/source/arm11/allocator/mem_pool.h b/source/arm11/allocator/mem_pool.h new file mode 100644 index 0000000..34cd0a5 --- /dev/null +++ b/source/arm11/allocator/mem_pool.h @@ -0,0 +1,90 @@ +#pragma once +#include "types.h" +#include + +struct MemChunk +{ + u8* addr; + u32 size; +}; + +struct MemBlock +{ + MemBlock *prev, *next; + u8* base; + u32 size; + + static MemBlock* Create(u8* base, u32 size) + { + auto b = (MemBlock*)malloc(sizeof(MemBlock)); + if (!b) return nullptr; + b->prev = nullptr; + b->next = nullptr; + b->base = base; + b->size = size; + return b; + } +}; + +struct MemPool +{ + MemBlock *first, *last; + + bool Ready() { return first != nullptr; } + + void AddBlock(MemBlock* blk) + { + blk->prev = last; + if (last) last->next = blk; + if (!first) first = blk; + last = blk; + } + + void DelBlock(MemBlock* b) + { + auto prev = b->prev, &pNext = prev ? prev->next : first; + auto next = b->next, &nPrev = next ? next->prev : last; + pNext = next; + nPrev = prev; + free(b); + } + + void InsertBefore(MemBlock* b, MemBlock* p) + { + auto prev = b->prev, &pNext = prev ? prev->next : first; + b->prev = p; + p->next = b; + p->prev = prev; + pNext = p; + } + + void InsertAfter(MemBlock* b, MemBlock* n) + { + auto next = b->next, &nPrev = next ? next->prev : last; + b->next = n; + n->prev = b; + n->next = next; + nPrev = n; + } + + //void CoalesceLeft(MemBlock* b); + void CoalesceRight(MemBlock* b); + + bool Allocate(MemChunk& chunk, u32 size, int align); + void Deallocate(const MemChunk& chunk); + + void Destroy() + { + MemBlock* next = nullptr; + for (auto b = first; b; b = next) + { + next = b->next; + free(b); + } + first = nullptr; + last = nullptr; + } + + //void Dump(const char* title); + u32 GetFreeSpace(); +}; diff --git a/source/arm11/allocator/vram.cpp b/source/arm11/allocator/vram.cpp new file mode 100644 index 0000000..7abe918 --- /dev/null +++ b/source/arm11/allocator/vram.cpp @@ -0,0 +1,95 @@ +extern "C" +{ + #include "types.h" + #include "arm11/allocator/vram.h" + #include "arm11/util/rbtree.h" +} + +#include "mem_pool.h" +#include "addrmap.h" + +static MemPool sVramPool; + +static bool vramInit() +{ + auto blk = MemBlock::Create((u8*)0x18000000, 0x00600000); + if (blk) + { + sVramPool.AddBlock(blk); + rbtree_init(&sAddrMap, addrMapNodeComparator); + return true; + } + return false; +} + +void* vramMemAlign(size_t size, size_t alignment) +{ + // Enforce minimum alignment + if (alignment < 16) + alignment = 16; + + // Convert alignment to shift amount + int shift; + for (shift = 4; shift < 32; shift ++) + { + if ((1U<node)) {} + return chunk.addr; +} + +void* vramAlloc(size_t size) +{ + return vramMemAlign(size, 0x80); +} + +void* vramRealloc(void* mem, size_t size) +{ + (void)mem; + (void)size; + + // TODO + return NULL; +} + +size_t vramGetSize(void* mem) +{ + auto node = getNode(mem); + return node ? node->chunk.size : 0; +} + +void vramFree(void* mem) +{ + auto node = getNode(mem); + if (!node) return; + + // Free the chunk + sVramPool.Deallocate(node->chunk); + + // Free the node + delNode(node); +} + +u32 vramSpaceFree() +{ + return sVramPool.GetFreeSpace(); +} diff --git a/source/arm11/console.c b/source/arm11/console.c index 7aee7c6..bd640d2 100644 --- a/source/arm11/console.c +++ b/source/arm11/console.c @@ -526,12 +526,12 @@ console->consoleInitialised = 1; - if(screen==1) { + if(screen==0) { console->frameBuffer = (u16*)RENDERBUF_TOP; console->consoleWidth = 66; console->windowWidth = 66; } - else console->frameBuffer = (u16*)RENDERBUF_SUB; + else console->frameBuffer = (u16*)RENDERBUF_BOT; if(clear) consoleCls('2'); diff --git a/source/arm11/debug.c b/source/arm11/debug.c index 4b52211..11928e0 100644 --- a/source/arm11/debug.c +++ b/source/arm11/debug.c @@ -37,10 +37,10 @@ { enterCriticalSection(); - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n"); - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + GX_textureCopy(RENDERBUF_TOP, 0, GFX_getFramebuffer(SCREEN_TOP), + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); PXI_sendPanicCmd(IPC_CMD9_PANIC); @@ -51,7 +51,7 @@ hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } @@ -59,11 +59,11 @@ { enterCriticalSection(); - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\n"); ee_printf("\nERROR MESSAGE:\n%s\n", msg); - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + GX_textureCopy(RENDERBUF_TOP, 0, GFX_getFramebuffer(SCREEN_TOP), + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); PXI_sendPanicCmd(IPC_CMD9_PANIC); @@ -74,7 +74,7 @@ hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } @@ -93,7 +93,7 @@ if(prevHash != debugHash) codeChanged = true;*/ - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); if(excStack[16] & 0x20) instSize = 2; // Processor was in Thumb mode? if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort @@ -131,8 +131,8 @@ } //if(codeChanged) ee_printf("Attention: RO section data changed!!"); - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + GX_textureCopy(RENDERBUF_TOP, 0, GFX_getFramebuffer(SCREEN_TOP), + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); PXI_sendPanicCmd(IPC_CMD9_EXCEPTION); @@ -143,7 +143,7 @@ hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } diff --git a/source/arm11/hardware/codec.c b/source/arm11/hardware/codec.c index a068443..e60b981 100644 --- a/source/arm11/hardware/codec.c +++ b/source/arm11/hardware/codec.c @@ -19,6 +19,7 @@ // Based on code from https://github.com/xerpi/linux_3ds/blob/master/drivers/input/misc/nintendo3ds_codec_hid.c #include "types.h" +#include "arm11/hardware/codec.h" #include "arm11/hardware/spi.h" #include "arm11/hardware/timer.h" #include "arm11/hardware/gpio.h" @@ -278,7 +279,7 @@ GPIO_config(GPIO_4_0, GPIO_OUTPUT); GPIO_write(GPIO_4_0, 1); // GPIO bitmask 0x40 TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO. - *((vu16*)0x10145000) = 0xE800u; // 47.61 kHz. codec module writes 0xC800 instead. + *((vu16*)0x10145000) = 0xC800u | 0x20u<<6; *((vu16*)0x10145002) = 0xE000u; codecMaskReg(0x65, 0x11, 0x10, 0x1C); codecWriteReg(0x64, 0x7A, 0); @@ -440,11 +441,17 @@ TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO. } -void CODEC_getRawAdcData(u32 buf[13]) +bool CODEC_getRawAdcData(CdcAdcData *data) { - //codecSwitchBank(0x67); - // This reg read seems useless and doesn't affect funtionality. - //codecReadReg(0x26); + if((codecReadReg(0x67, 0x26) & 2u) == 0) + { + codecReadRegBuf(0xFB, 1, (u32*)data, sizeof(CdcAdcData)); - codecReadRegBuf(0xFB, 1, buf, 52); + return true; + } + + // Codec module does this when data is unavailable. Why? + //codecSwitchBank(0); + + return false; } diff --git a/source/arm11/hardware/gfx.c b/source/arm11/hardware/gfx.c index 3ce3533..f864e8b 100644 --- a/source/arm11/hardware/gfx.c +++ b/source/arm11/hardware/gfx.c @@ -16,163 +16,492 @@ * along with this program. If not, see . */ -/* - * Based on code from https://github.com/AuroraWright/Luma3DS - * for compatibility. - * - * Credits go to the Luma3DS devs and derrek for reverse engineering boot11. -*/ - +#include +#include #include "types.h" #include "mem_map.h" #include "hardware/gfx.h" +#include "mmio.h" +#include "arm11/hardware/i2c.h" #include "arm11/hardware/mcu.h" +#include "arm11/debug.h" #include "arm11/hardware/interrupt.h" #include "arm11/hardware/timer.h" #include "arm.h" -//#include "util.h" +#include "util.h" +#include "arm11/allocator/vram.h" -#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000) -#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x1200)) -#define REG_PDN_GPU_CNT2 *((vu32*)(PDN_REGS_BASE + 0x1204)) -#define REG_PDN_GPU_CNT2_8BIT *((vu8* )(PDN_REGS_BASE + 0x1204)) -#define REG_PDN_GPU_CNT4 *((vu8* )(PDN_REGS_BASE + 0x1208)) -#define REG_PDN_GPU_CNT3 *((vu16*)(PDN_REGS_BASE + 0x1210)) +#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000) +#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x1200)) -#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000) -#define REG_LCD_COLORFILL_MAIN *((vu32*)(LCD_REGS_BASE + 0x204)) -#define REG_LCD_COLORFILL_SUB *((vu32*)(LCD_REGS_BASE + 0xA04)) -#define REG_LCD_BACKLIGHT_MAIN *((vu32*)(LCD_REGS_BASE + 0x240)) -#define REG_LCD_BACKLIGHT_SUB *((vu32*)(LCD_REGS_BASE + 0xA40)) +// LCD/ABL regs. +#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000) +#define REG_LCD_ABL0_CNT *((vu32*)(LCD_REGS_BASE + 0x200)) // Bit 0 enables ABL aka power saving mode. +#define REG_LCD_ABL0_FILL *((vu32*)(LCD_REGS_BASE + 0x204)) +#define REG_LCD_ABL0_LIGHT *((vu32*)(LCD_REGS_BASE + 0x240)) +#define REG_LCD_ABL0_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0x244)) -#define GX_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000) -#define REG_GX_PSC_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ? +#define REG_LCD_ABL1_CNT *((vu32*)(LCD_REGS_BASE + 0xA00)) // Bit 0 enables ABL aka power saving mode. +#define REG_LCD_ABL1_FILL *((vu32*)(LCD_REGS_BASE + 0xA04)) +#define REG_LCD_ABL1_LIGHT *((vu32*)(LCD_REGS_BASE + 0xA40)) +#define REG_LCD_ABL1_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0xA44)) -#define REG_GX_PSC_FILL0_S_ADR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address -#define REG_GX_PSC_FILL0_E_ADR *((vu32*)(GX_REGS_BASE + 0x0014)) // End address -#define REG_GX_PSC_FILL0_VAL *((vu32*)(GX_REGS_BASE + 0x0018)) // Fill value -#define REG_GX_PSC_FILL0_CNT *((vu32*)(GX_REGS_BASE + 0x001C)) +#define GX_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000) +#define REG_GX_GPU_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ? -#define REG_GX_PSC_FILL1_S_ADR *((vu32*)(GX_REGS_BASE + 0x0020)) -#define REG_GX_PSC_FILL1_E_ADR *((vu32*)(GX_REGS_BASE + 0x0024)) -#define REG_GX_PSC_FILL1_VAL *((vu32*)(GX_REGS_BASE + 0x0028)) -#define REG_GX_PSC_FILL1_CNT *((vu32*)(GX_REGS_BASE + 0x002C)) +// PSC (memory fill) regs. +#define REG_GX_PSC_FILL0_S_ADR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address +#define REG_GX_PSC_FILL0_E_ADR *((vu32*)(GX_REGS_BASE + 0x0014)) // End address +#define REG_GX_PSC_FILL0_VAL *((vu32*)(GX_REGS_BASE + 0x0018)) // Fill value +#define REG_GX_PSC_FILL0_CNT *((vu32*)(GX_REGS_BASE + 0x001C)) -#define REG_GX_PSC_UNK *((vu32*)(GX_REGS_BASE + 0x0030)) // ? gsp mudule only changes bit 8-11. +#define REG_GX_PSC_FILL1_S_ADR *((vu32*)(GX_REGS_BASE + 0x0020)) +#define REG_GX_PSC_FILL1_E_ADR *((vu32*)(GX_REGS_BASE + 0x0024)) +#define REG_GX_PSC_FILL1_VAL *((vu32*)(GX_REGS_BASE + 0x0028)) +#define REG_GX_PSC_FILL1_CNT *((vu32*)(GX_REGS_BASE + 0x002C)) -#define REGs_GX_PPF ((vu32*)(GX_REGS_BASE + 0x0C00)) +#define REG_GX_PSC_UNK *((vu32*)(GX_REGS_BASE + 0x0030)) // ? gsp mudule only changes bit 8-11. +#define REG_GX_PSC_STAT *((vu32*)(GX_REGS_BASE + 0x0034)) + +// PDC0 (top screen display controller) regs. +#define REG_LCD_PDC0_G_TBL_IDX *((vu32*)(GX_REGS_BASE + 0x0480)) // Gamma table index. +#define REG_LCD_PDC0_G_TBL_FIFO *((vu32*)(GX_REGS_BASE + 0x0484)) // Gamma table FIFO. + +// PDC1 (bottom screen display controller) regs. +#define REG_LCD_PDC1_G_TBL_IDX *((vu32*)(GX_REGS_BASE + 0x0580)) // Gamma table index. +#define REG_LCD_PDC1_G_TBL_FIFO *((vu32*)(GX_REGS_BASE + 0x0584)) // Gamma table FIFO. + +// PPF (transfer engine) regs. +#define REG_GX_PPF_IN_ADR *((vu32*)(GX_REGS_BASE + 0x0C00)) +#define REG_GX_PPF_OUT_ADR *((vu32*)(GX_REGS_BASE + 0x0C04)) +#define REG_GX_PPF_DT_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C08)) // Display transfer output dimensions. +#define REG_GX_PPF_DT_INDIM *((vu32*)(GX_REGS_BASE + 0x0C0C)) // Display transfer input dimensions. +#define REG_GX_PPF_CFG *((vu32*)(GX_REGS_BASE + 0x0C10)) +#define REG_GX_PPF_UNK14 *((vu32*)(GX_REGS_BASE + 0x0C14)) // Transfer interval? +#define REG_GX_PPF_CNT *((vu32*)(GX_REGS_BASE + 0x0C18)) +#define REG_GX_PPF_UNK1C *((vu32*)(GX_REGS_BASE + 0x0C1C)) // ? +#define REG_GX_PPF_LEN *((vu32*)(GX_REGS_BASE + 0x0C20)) // Texture copy size in bytes. +#define REG_GX_PPF_TC_INDIM *((vu32*)(GX_REGS_BASE + 0x0C24)) // Texture copy input width and gap in 16 byte units. +#define REG_GX_PPF_TC_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C28)) // Texture copy output width and gap in 16 byte units. + +// P3D (GPU) regs. +#define REG_GX_P3D_UNK *((vu32*)(GX_REGS_BASE + 0x1000)) // GSP writes 0 before running a cmd list. +#define REG_GX_P3D_LIST_SIZE *((vu32*)(GX_REGS_BASE + 0x18E0)) // cmd list length in 8 bytes units. Must be aligned to 16. +#define REG_GX_P3D_LIST_ADR *((vu32*)(GX_REGS_BASE + 0x18E8)) // cmd list address / 8. Must be aligned to 16. +#define REG_GX_P3D_LIST_RUN *((vu32*)(GX_REGS_BASE + 0x18F0)) // Start list processing by writing 1. -static u32 activeFb = 0; -static volatile bool eventTable[6] = {false}; - - - -static void gfxSetupLcdTop(void) +static struct { - *((vu32*)(0x10400400+0x00)) = 0x000001C2; - *((vu32*)(0x10400400+0x04)) = 0x000000D1; - *((vu32*)(0x10400400+0x08)) = 0x000001C1; - *((vu32*)(0x10400400+0x0C)) = 0x000001C1; - *((vu32*)(0x10400400+0x10)) = 0x00000000; - *((vu32*)(0x10400400+0x14)) = 0x000000CF; - *((vu32*)(0x10400400+0x18)) = 0x000000d1; - *((vu32*)(0x10400400+0x1C)) = 0x01C501C1; - *((vu32*)(0x10400400+0x20)) = 0x00010000; - *((vu32*)(0x10400400+0x24)) = 0x0000019D; - *((vu32*)(0x10400400+0x28)) = 0x00000002; - *((vu32*)(0x10400400+0x2C)) = 0x00000192; - *((vu32*)(0x10400400+0x30)) = 0x00000192; - *((vu32*)(0x10400400+0x34)) = 0x00000192; - *((vu32*)(0x10400400+0x38)) = 0x00000001; - *((vu32*)(0x10400400+0x3C)) = 0x00000002; - *((vu32*)(0x10400400+0x40)) = 0x01960192; - *((vu32*)(0x10400400+0x44)) = 0x00000000; - *((vu32*)(0x10400400+0x48)) = 0x00000000; - *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height - *((vu32*)(0x10400400+0x60)) = 0x01C100D1; - *((vu32*)(0x10400400+0x64)) = 0x01920002; - *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address - *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address - *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES - *((vu32*)(0x10400400+0x74)) = 0x00010501; - *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 - *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address - *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address - *((vu32*)(0x10400400+0x9C)) = 0x00000000; + u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen. + bool lcdIdsRead; + u8 lcdPower; // 1 = on. Bit 4 top light, bit 2 bottom light, bit 0 LCDs. + u8 lcdLights[2]; // LCD backlight brightness. Top, bottom. + bool events[6]; + u32 swap; // Currently active framebuffer. + void *framebufs[2][4]; // For each screen A1, A2, B1, B2 + u32 strides[2]; // Top, bottom + u32 formats[2]; // Top, bottom +} g_gfxState = {0}; - for(u32 i = 0; i < 0x100; i++) - { - u32 val = 0x10101; - val *= i; - *((vu32*)(0x10400400+0x84)) = val; - } + + +static u32 fmt2PixSize(GfxFbFmt fmt); +static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot); +static void deallocFramebufs(void); +static void setupDislayController(u8 lcd); +static void resetLcdsMaybe(void); +static void waitLcdsReady(void); +static void gfxIrqHandler(u32 intSource); + +void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot) +{ + setupFramebufs(fmtTop, fmtBot); + + *((vu32*)0x10140140) = 0; // REG_CFG11_GPUPROT + + // Reset + REG_PDN_GPU_CNT = 0x10000; + wait(12); + REG_PDN_GPU_CNT = 0x1007F; + REG_GX_GPU_CLK = 0x100; + REG_GX_PSC_UNK = 0; + REG_GX_PSC_FILL0_CNT = 0; + REG_GX_PSC_FILL1_CNT = 0; + REG_GX_PPF_CNT = 0; + + // LCD framebuffer setup. + setupDislayController(0); + setupDislayController(1); + *((vu32*)0x10400478) = 0x70100; // Framebuffer select 0. + *((vu32*)0x10400578) = 0x70100; // Framebuffer select 0. + *((vu32*)0x10400474) = 0x10501; // Start + *((vu32*)0x10400574) = 0x10501; // Start + + // LCD reg setup. + REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen + REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen + *((vu32*)0x10202000) = 0; + *((vu32*)0x10202004) = 0xA390A39; + *((vu32*)0x10202014) = 0; + *((vu32*)0x1020200C) = 0x10001; + + // Register IRQ handlers. + IRQ_registerHandler(IRQ_PSC0, 14, 0, true, gfxIrqHandler); + IRQ_registerHandler(IRQ_PSC1, 14, 0, true, gfxIrqHandler); + IRQ_registerHandler(IRQ_PDC0, 14, 0, true, gfxIrqHandler); + //IRQ_registerHandler(IRQ_PDC1, 14, 0, true, gfxIrqHandler); + IRQ_registerHandler(IRQ_PPF, 14, 0, true, gfxIrqHandler); + IRQ_registerHandler(IRQ_P3D, 14, 0, true, gfxIrqHandler); + + // Clear entire VRAM. + GX_memoryFill((u32*)VRAM_BANK0, 1u<<9, VRAM_SIZE / 2, 0, + (u32*)VRAM_BANK1, 1u<<9, VRAM_SIZE / 2, 0); + + // Backlight and other stuff. + REG_LCD_ABL0_LIGHT = 0; + REG_LCD_ABL0_CNT = 0; + REG_LCD_ABL0_LIGHT_PWM = 0; + REG_LCD_ABL1_LIGHT = 0; + REG_LCD_ABL1_CNT = 0; + REG_LCD_ABL1_LIGHT_PWM = 0; + + *((vu32*)0x10202014) = 1; + *((vu32*)0x1020200C) = 0; + TIMER_sleepMs(10); + resetLcdsMaybe(); + MCU_controlLCDPower(2u); // Power on LCDs. + if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) panic(); + + // The transfer engine is (sometimes) borked on screen init. + // Doing a dummy texture copy fixes it. + // TODO: Proper fix. + GX_textureCopy((u32*)RENDERBUF_TOP, 0, (u32*)RENDERBUF_BOT, 0, 16); + + waitLcdsReady(); + REG_LCD_ABL0_LIGHT_PWM = 0x1023E; + REG_LCD_ABL1_LIGHT_PWM = 0x1023E; + MCU_controlLCDPower(0x28u); // Power on backlights. + if(MCU_waitEvents(0x3Fu<<24) != 0x28u<<24) panic(); + g_gfxState.lcdPower = 0x15; // All on. + + // Make sure the fills finished. + GFX_waitForEvent(GFX_EVENT_PSC0, false); + GFX_waitForEvent(GFX_EVENT_PSC1, false); + REG_LCD_ABL0_FILL = 0; + REG_LCD_ABL1_FILL = 0; + + GFX_setBrightness(DEFAULT_BRIGHTNESS, DEFAULT_BRIGHTNESS); } -static void gfxSetupLcdSub(void) +void GFX_deinit(void) { - *((vu32*)(0x10400500+0x00)) = 0x000001C2; - *((vu32*)(0x10400500+0x04)) = 0x000000D1; - *((vu32*)(0x10400500+0x08)) = 0x000001C1; - *((vu32*)(0x10400500+0x0C)) = 0x000001C1; - *((vu32*)(0x10400500+0x10)) = 0x000000CD; - *((vu32*)(0x10400500+0x14)) = 0x000000CF; - *((vu32*)(0x10400500+0x18)) = 0x000000D1; - *((vu32*)(0x10400500+0x1C)) = 0x01C501C1; - *((vu32*)(0x10400500+0x20)) = 0x00010000; - *((vu32*)(0x10400500+0x24)) = 0x0000019D; - *((vu32*)(0x10400500+0x28)) = 0x00000052; - *((vu32*)(0x10400500+0x2C)) = 0x00000192; - *((vu32*)(0x10400500+0x30)) = 0x00000192; - *((vu32*)(0x10400500+0x34)) = 0x0000004F; - *((vu32*)(0x10400500+0x38)) = 0x00000050; - *((vu32*)(0x10400500+0x3C)) = 0x00000052; - *((vu32*)(0x10400500+0x40)) = 0x01980194; - *((vu32*)(0x10400500+0x44)) = 0x00000000; - *((vu32*)(0x10400500+0x48)) = 0x00000011; - *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height - *((vu32*)(0x10400500+0x60)) = 0x01C100D1; - *((vu32*)(0x10400500+0x64)) = 0x01920052; - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address - *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES - *((vu32*)(0x10400500+0x74)) = 0x00010501; - *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 - *((vu32*)(0x10400500+0x9C)) = 0x00000000; - - for(u32 i = 0; i < 0x100; i++) + const u8 power = g_gfxState.lcdPower; + if(power & ~1u) // Poweroff backlights if on. { - u32 val = 0x10101; - val *= i; - *((vu32*)(0x10400500+0x84)) = val; + MCU_controlLCDPower(power & ~1u); + if(MCU_waitEvents(0x3Fu<<24) != (power & ~1u)<<24) panic(); } + if(power & 1u) // Poweroff LCDs if on. + { + MCU_controlLCDPower(1u); + if(MCU_waitEvents(0x3Fu<<24) != 1u<<24) panic(); + } + GFX_setBrightness(0, 0); + REG_LCD_ABL0_LIGHT_PWM = 0; + REG_LCD_ABL1_LIGHT_PWM = 0; + *((vu32*)0x1020200C) = 0x10001; + *((vu32*)0x10202014) = 0; + //REG_GX_PSC_UNK = 0xF00; // Make the VRAM inaccessible. + REG_GX_GPU_CLK = 0; + REG_PDN_GPU_CNT = 0x10001; + + deallocFramebufs(); + + IRQ_unregisterHandler(IRQ_PSC0); + IRQ_unregisterHandler(IRQ_PSC1); + IRQ_unregisterHandler(IRQ_PDC0); + //IRQ_unregisterHandler(IRQ_PDC1); + IRQ_unregisterHandler(IRQ_PPF); + IRQ_unregisterHandler(IRQ_P3D); } -static void gfxSetupFramebuffers(void) +void GFX_gpuInit(void) { + REG_GX_GPU_CLK = 0x70100; + *((vu32*)0x10400050) = 0x22221200; + *((vu32*)0x10400054) = 0xFF2; + + *((vu32*)0x10401000) = 0; + *((vu32*)0x10401080) = 0x12345678; + *((vu32*)0x104010C0) = 0xFFFFFFF0; + *((vu32*)0x104010D0) = 1; + + // GPUREG_START_DRAW_FUNC0 + // This reg needs to be set to 1 (configuration) + // before running the first cmd list. + *((vu32*)0x10401914) = 1; +} + +void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot) +{ + REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen + REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen + + if(fmtTop < (g_gfxState.formats[0] & 7u) || fmtBot < (g_gfxState.formats[1] & 7u)) + { + deallocFramebufs(); + setupFramebufs(fmtTop, fmtBot); + } + + // Update PDC regs. + *((vu32*)0x10400468) = (u32)g_gfxState.framebufs[0][0]; + *((vu32*)0x1040046C) = (u32)g_gfxState.framebufs[0][1]; + *((vu32*)0x10400494) = (u32)g_gfxState.framebufs[0][2]; + *((vu32*)0x10400498) = (u32)g_gfxState.framebufs[0][3]; + *((vu32*)0x10400490) = g_gfxState.strides[0]; + *((vu32*)0x10400470) = g_gfxState.formats[0]; + + *((vu32*)0x10400568) = (u32)g_gfxState.framebufs[1][0]; + *((vu32*)0x1040056C) = (u32)g_gfxState.framebufs[1][1]; + *((vu32*)0x10400594) = (u32)g_gfxState.framebufs[1][2]; + *((vu32*)0x10400598) = (u32)g_gfxState.framebufs[1][3]; + *((vu32*)0x10400590) = g_gfxState.strides[1]; + *((vu32*)0x10400570) = g_gfxState.formats[1]; + + REG_LCD_ABL0_FILL = 0; + REG_LCD_ABL1_FILL = 0; +} + +static u32 fmt2PixSize(GfxFbFmt fmt) +{ + u32 size; + + switch(fmt) + { + case GFX_RGBA8: + size = 4; + break; + case GFX_BGR8: + size = 3; + break; + default: // 2 = RGB565, 3 = RGB5A1, 4 = RGBA4 + size = 2; + } + + return size; +} + +static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot) +{ + const u32 topPixSize = fmt2PixSize(fmtTop); + const u32 botPixSize = fmt2PixSize(fmtBot); + g_gfxState.strides[0] = 240u * topPixSize; // No gap. + g_gfxState.strides[1] = 240u * botPixSize; // No gap. + + const u32 topSize = 400 * 240 * topPixSize; + const u32 botSize = 320 * 240 * botPixSize; + g_gfxState.framebufs[0][0] = vramAlloc(topSize); // Top A1 (3D left eye) + void *botPtr = vramAlloc(botSize); + g_gfxState.framebufs[1][0] = botPtr; // Bottom A1 + g_gfxState.framebufs[1][2] = botPtr; // Bottom B1 (unused) + g_gfxState.framebufs[0][2] = vramAlloc(topSize); // Top B1 (3D right eye) + + g_gfxState.framebufs[0][1] = vramAlloc(topSize); // Top A2 (3D left eye) + botPtr = vramAlloc(botSize); + g_gfxState.framebufs[1][1] = botPtr; // Bottom A2 + g_gfxState.framebufs[1][3] = botPtr; // Bottom B2 (unused) + g_gfxState.framebufs[0][3] = vramAlloc(topSize); // Top B2 (3D right eye) + + g_gfxState.formats[0] = 0<<16 | 3<<8 | 1<<6 | 0<<4 | fmtTop; + g_gfxState.formats[1] = 0<<16 | 3<<8 | 0<<6 | 0<<4 | fmtBot; +} + +static void deallocFramebufs(void) +{ + vramFree(g_gfxState.framebufs[0][3]); + vramFree(g_gfxState.framebufs[1][1]); + vramFree(g_gfxState.framebufs[0][1]); + vramFree(g_gfxState.framebufs[0][2]); + vramFree(g_gfxState.framebufs[1][0]); + vramFree(g_gfxState.framebufs[0][0]); +} + +static void setupDislayController(u8 lcd) +{ + if(lcd > 1) return; + + static const u32 displayCfgs[2][24] = + { + { + // PDC0 regs 0-0x4C. + 450, 209, 449, 449, 0, 207, 209, 453<<16 | 449, + 1<<16 | 0, 413, 2, 402, 402, 402, 1, 2, + 406<<16 | 402, 0, 0<<4 | 0, 0<<16 | 0xFF<<8 | 0, + // PDC0 regs 0x5C-0x64. + 400<<16 | 240, // Width and height. + 449<<16 | 209, + 402<<16 | 2, + // PDC0 reg 0x9C. + 0<<16 | 0 + }, + { + // PDC1 regs 0-0x4C. + 450, 209, 449, 449, 205, 207, 209, 453<<16 | 449, + 1<<16 | 0, 413, 82, 402, 402, 79, 80, 82, + 408<<16 | 404, 0, 1<<4 | 1, 0<<16 | 0<<8 | 0xFF, + // PDC1 regs 0x5C-0x64. + 320<<16 | 240, // Width and height. + 449<<16 | 209, + 402<<16 | 82, + // PDC1 reg 0x9C. + 0<<16 | 0 + } + }; + + const u32 *const cfg = displayCfgs[lcd]; + vu32 *const regs = (vu32*)(GX_REGS_BASE + 0x400 + (0x100u * lcd)); + + iomemcpy(regs, cfg, 0x50); // PDC regs 0-0x4C. + iomemcpy(regs + 23, &cfg[20], 0xC); // PDC regs 0x5C-0x64. + regs[36] = g_gfxState.strides[lcd]; // PDC reg 0x90 stride. + regs[39] = cfg[23]; // PDC reg 0x9C. + + + // PDC regs 0x68, 0x6C, 0x94, 0x98 and 0x70. + regs[26] = (u32)g_gfxState.framebufs[lcd][0]; // Framebuffer A first address. + regs[27] = (u32)g_gfxState.framebufs[lcd][1]; // Framebuffer A second address. + regs[37] = (u32)g_gfxState.framebufs[lcd][2]; // Framebuffer B first address. + regs[38] = (u32)g_gfxState.framebufs[lcd][3]; // Framebuffer B second address. + regs[28] = g_gfxState.formats[lcd]; // Format + + + regs[32] = 0; // Gamma table index 0. + for(u32 i = 0; i < 256; i++) regs[33] = 0x10101u * i; +} + +static u16 getLcdIds(void) +{ + u16 ids; + + if(!g_gfxState.lcdIdsRead) + { + g_gfxState.lcdIdsRead = true; + + u16 top, bot; + I2C_writeReg(I2C_DEV_LCD0, 0x40, 0xFF); + I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); + I2C_writeReg(I2C_DEV_LCD1, 0x40, 0xFF); + I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2); + + ids = top>>8; + ids |= bot & 0xFF00u; + g_gfxState.lcdIds = ids; + } + else ids = g_gfxState.lcdIds; + + return ids; +} + +static void resetLcdsMaybe(void) +{ + const u16 ids = getLcdIds(); + // Top screen - *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height - *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address - *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address - *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES - *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 - *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address - *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address + if(ids & 0xFFu) I2C_writeReg(I2C_DEV_LCD0, 0xFE, 0xAA); + else + { + I2C_writeReg(I2C_DEV_LCD0, 0x11, 0x10); + I2C_writeReg(I2C_DEV_LCD0, 0x50, 1); + } // Bottom screen - *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address - *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES - *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 + if(ids>>8) I2C_writeReg(I2C_DEV_LCD1, 0xFE, 0xAA); + else I2C_writeReg(I2C_DEV_LCD1, 0x11, 0x10); + + I2C_writeReg(I2C_DEV_LCD0, 0x60, 0); + I2C_writeReg(I2C_DEV_LCD1, 0x60, 0); + I2C_writeReg(I2C_DEV_LCD0, 1, 0x10); + I2C_writeReg(I2C_DEV_LCD1, 1, 0x10); } -void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1) +static void waitLcdsReady(void) +{ + const u16 ids = getLcdIds(); + + if((ids & 0xFFu) == 0 || (ids>>8) == 0) // Unknown LCD? + { + TIMER_sleepMs(150); + } + else + { + u32 i = 0; + do + { + u16 top, bot; + I2C_writeReg(I2C_DEV_LCD0, 0x40, 0x62); + I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); + I2C_writeReg(I2C_DEV_LCD1, 0x40, 0x62); + I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2); + + if((top>>8) == 1 && (bot>>8) == 1) break; + + TIMER_sleepTicks(TIMER_FREQ(1, 1000) * 33.333f); + i++; + } while(i < 10); + } +} + +void GFX_setBrightness(u8 top, u8 bot) +{ + if(top > 64 || bot > 64) return; + + g_gfxState.lcdLights[0] = top; + g_gfxState.lcdLights[1] = bot; + REG_LCD_ABL0_LIGHT = top; + REG_LCD_ABL1_LIGHT = bot; +} + +void GFX_setForceBlack(bool top, bool bot) +{ + REG_LCD_ABL0_FILL = top<<24; // Force blackscreen + REG_LCD_ABL1_FILL = bot<<24; // Force blackscreen +} + +void* GFX_getFramebuffer(u8 screen) +{ + return g_gfxState.framebufs[screen][g_gfxState.swap ^ 1u]; +} + +void GFX_swapFramebufs(void) +{ + u32 swap = g_gfxState.swap; + swap ^= 1u; + g_gfxState.swap = swap; + + swap |= 0x70000u; // Acknowledge IRQs. + *((vu32*)0x10400478) = swap; + *((vu32*)0x10400578) = swap; +} + +void GFX_waitForEvent(GfxEvent event, bool discard) +{ + bool *const events = g_gfxState.events; + + if(discard) atomic_store_explicit(&events[event], false, memory_order_relaxed); + while(!atomic_load_explicit(&events[event], memory_order_relaxed)) __wfe(); + atomic_store_explicit(&events[event], false, memory_order_relaxed); +} + +static void gfxIrqHandler(u32 intSource) +{ + bool *const events = g_gfxState.events; + + atomic_store_explicit(&events[intSource - IRQ_PSC0], true, memory_order_relaxed); +} + +void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1) { if(buf0a) { @@ -191,173 +520,81 @@ } } -void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags) +// Example: GX_displayTransfer(in, 160u<<16 | 240u, out, 160u<<16 | 240u, 2u<<12 | 2u<<8); +// Copy and unswizzle GBA sized frame in RGB565. +void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags) { if(!in || !out) return; - REGs_GX_PPF[0] = (u32)in>>3; - REGs_GX_PPF[1] = (u32)out>>3; - REGs_GX_PPF[2] = indim; - REGs_GX_PPF[3] = outdim; - REGs_GX_PPF[4] = flags; - REGs_GX_PPF[5] = 0; - REGs_GX_PPF[6] = 1; + REG_GX_PPF_IN_ADR = (u32)in>>3; + REG_GX_PPF_OUT_ADR = (u32)out>>3; + REG_GX_PPF_DT_INDIM = indim; + REG_GX_PPF_DT_OUTDIM = outdim; + REG_GX_PPF_CFG = flags; + REG_GX_PPF_UNK14 = 0; + REG_GX_PPF_CNT = 1; } // Example: GX_textureCopy(in, (240 * 2)<<12 | (240 * 2)>>4, out, (240 * 2)<<12 | (240 * 2)>>4, 240 * 400); // Copies every second line of a 240x400 framebuffer. -void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size) +void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size) { if(!in || !out) return; - REGs_GX_PPF[0] = (u32)in>>3; - REGs_GX_PPF[1] = (u32)out>>3; - REGs_GX_PPF[4] = 1u<<3; - REGs_GX_PPF[8] = size; - REGs_GX_PPF[9] = indim; - REGs_GX_PPF[10] = outdim; - REGs_GX_PPF[6] = 1; + REG_GX_PPF_IN_ADR = (u32)in>>3; + REG_GX_PPF_OUT_ADR = (u32)out>>3; + REG_GX_PPF_CFG = 1u<<3; + REG_GX_PPF_LEN = size; + REG_GX_PPF_TC_INDIM = indim; + REG_GX_PPF_TC_OUTDIM = outdim; + REG_GX_PPF_CNT = 1; } -void GFX_setBrightness(u32 top, u32 sub) +void GX_processCommandList(u32 size, const u32 *const cmdList) { - REG_LCD_BACKLIGHT_MAIN = top; - REG_LCD_BACKLIGHT_SUB = sub; + REG_GX_P3D_UNK = 0; // Acknowledge last P3D? + while(REG_GX_PSC_STAT & 1u<<31) wait(0x30); + + REG_GX_P3D_LIST_SIZE = size>>3; + REG_GX_P3D_LIST_ADR = (u32)cmdList>>3; + REG_GX_P3D_LIST_RUN = 1; } -void* GFX_getFramebuffer(u8 screen) +// TODO: Sleep mode stuff needs some work. +/*void GFX_enterLowPowerState(void) { - static void *const framebufTable[2][2] = - { - {(void*)FRAMEBUF_SUB_A_2, (void*)FRAMEBUF_SUB_A_1}, - {(void*)FRAMEBUF_TOP_A_2, (void*)FRAMEBUF_TOP_A_1} - }; - - return framebufTable[screen][activeFb]; -} - -void GFX_swapFramebufs(void) -{ - activeFb ^= 1; - - *((vu32*)(0x10400400+0x78)) = activeFb; - *((vu32*)(0x10400500+0x78)) = activeFb; -} - -static void gfxIrqHandler(u32 intSource) -{ - eventTable[intSource - IRQ_PSC0] = true; -} - -void GFX_waitForEvent(GfxEvent event, bool discard) -{ - if(discard) eventTable[event] = false; - while(!eventTable[event]) __wfe(); - eventTable[event] = false; -} - -void GFX_init(bool clearScreens) -{ - if(REG_PDN_GPU_CNT != 0x1007F) // Check if screens are already initialized - { - //REG_PDN_GPU_CNT = 0x10000; - //wait(134); - REG_PDN_GPU_CNT = 0x1007F; - // PSC and PPF stuff - //REG_GX_PSC_CLK = 0x70100; - - *((vu32*)0x10202014) = 0x00000001; - *((vu32*)0x1020200C) &= 0xFFFEFFFE; - REG_LCD_COLORFILL_MAIN = 1u<<24; // Force blackscreen - REG_LCD_COLORFILL_SUB = 1u<<24; // Force blackscreen - GFX_setBrightness(DEFAULT_BRIGHTNESS, DEFAULT_BRIGHTNESS); - *((vu32*)0x10202244) = 0x1023E; - *((vu32*)0x10202A44) = 0x1023E; - - gfxSetupLcdTop(); - gfxSetupLcdSub(); - - MCU_powerOnLCDs(); // Power on LCDs and backlight - } - else - { - REG_LCD_COLORFILL_MAIN = 1u<<24; // Force blackscreen - REG_LCD_COLORFILL_SUB = 1u<<24; // Force blackscreen - GFX_setBrightness(DEFAULT_BRIGHTNESS, DEFAULT_BRIGHTNESS); - gfxSetupFramebuffers(); - } - - IRQ_registerHandler(IRQ_PSC0, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PSC1, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PDC0, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PPF, 14, 0, true, gfxIrqHandler); - //IRQ_registerHandler(IRQ_P3D, 14, 0, true, gfxIrqHandler); - - if(clearScreens) - { - // Warning. The GPU mem fill races against the console. - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC1, true); - GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_SUB, 1u<<9, SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC0, true); - - // The transfer engine is (sometimes) borked on screen init. - // Doing a dummy texture copy fixes it. - // TODO: Proper fix. - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)RENDERBUF_SUB, 0, 16); - } - - // We must make sure the I2C bus is not used until this finishes - // otherwise the screens may not turn on on New 3DS. - TIMER_sleepMs(3); - - REG_LCD_COLORFILL_MAIN = 0; - REG_LCD_COLORFILL_SUB = 0; -} - -void GFX_enterLowPowerState(void) -{ - REG_LCD_COLORFILL_MAIN = 1u<<24; // Force blackscreen - REG_LCD_COLORFILL_SUB = 1u<<24; // Force blackscreen + REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen + REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen GFX_waitForEvent(GFX_EVENT_PDC0, true); - GFX_deinit(false); + + // Stop PDCs. + *((vu32*)0x10400474) = 0x700; // Stop + *((vu32*)0x10400574) = 0x700; // Stop + *((vu32*)0x10400478) = 0x70100; + *((vu32*)0x10400578) = 0x70100; + + REG_GX_PSC_UNK = 0xF00; + REG_PDN_GPU_CNT = 0x7F; } void GFX_returnFromLowPowerState(void) { - GFX_init(false); -} + REG_PDN_GPU_CNT = 0x1007F; + REG_GX_PSC_UNK = 0; + //REG_GX_GPU_CLK = 0x70100; + REG_GX_PSC_FILL0_CNT = 0; + REG_GX_PSC_FILL1_CNT = 0; + // *((vu32*)0x10400050) = 0x22221200; + // *((vu32*)0x10400054) = 0xFF2; -void GFX_deinit(bool keepLcdsOn) -{ - IRQ_disable(IRQ_PSC0); - IRQ_disable(IRQ_PSC1); - IRQ_disable(IRQ_PDC0); - IRQ_disable(IRQ_PPF); - //IRQ_disable(IRQ_P3D); + setupDislayController(0); + setupDislayController(1); + const u32 swap = 0x70100 | g_gfxState.swap; + *((vu32*)0x10400478) = swap; + *((vu32*)0x10400578) = swap; + *((vu32*)0x10400474) = 0x10501; // Start + *((vu32*)0x10400574) = 0x10501; // Start - if(keepLcdsOn) - { - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0); - *((vu32*)(0x10400400+0x70)) = 0x00080341; // Format GL_RGB8_OES - *((vu32*)(0x10400400+0x78)) = 0; // Select first framebuffer - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 3; // Stride 0 - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1 + 0x17700; // Sub framebuffer first address - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2 + 0x17700; // Sub framebuffer second address - *((vu32*)(0x10400500+0x70)) = 0x00080301; // Format GL_RGB8_OES - *((vu32*)(0x10400500+0x78)) = 0; // Select first framebuffer - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 3; // Stride 0 - } - else - { - MCU_powerOffLCDs(); - GFX_setBrightness(0, 0); - *((vu32*)0x10202244) = 0; - *((vu32*)0x10202A44) = 0; - *((vu32*)0x1020200C) = 0x10001; - *((vu32*)0x10202014) = 0; - REG_PDN_GPU_CNT = 0x10001; - } -} + REG_LCD_ABL0_FILL = 0; + REG_LCD_ABL1_FILL = 0; +}*/ diff --git a/source/arm11/hardware/hid.c b/source/arm11/hardware/hid.c index a4e41bc..7992896 100644 --- a/source/arm11/hardware/hid.c +++ b/source/arm11/hardware/hid.c @@ -32,50 +32,36 @@ #define CPAD_THRESHOLD (400) -static u32 kHeld, kDown, kUp; -static u32 extraKeys; -//TouchPos tPos; -//CpadPos cPos; -static volatile bool mcuIrq; +static u32 g_kHeld = 0, g_kDown = 0, g_kUp = 0; +static u32 g_extraKeys = 0; +//TouchPos tPos = {0}; +//CpadPos cPos = {0}; -static void hidIrqHandler(UNUSED u32 intSource); - void hidInit(void) { - kUp = kDown = kHeld = 0; - mcuIrq = false; + static bool inited = false; + if(inited) return; + inited = true; - (void)MCU_readReceivedIrqs(); - u8 state = MCU_readExternalHwState(); + MCU_init(); + u8 state = MCU_getExternalHwState(); u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted. tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state - state = MCU_readHidHeld(); + state = MCU_getHidHeld(); tmp |= ~state<<1 & KEY_HOME; // Current HOME button state - extraKeys = tmp; - - IRQ_registerHandler(IRQ_CTR_MCU, 14, 0, true, hidIrqHandler); - MCU_setIrqBitmask(0xFFBF3F80u); - // Configure GPIO for MCU event IRQs - GPIO_config(GPIO_4_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE); + g_extraKeys = tmp; //CODEC_init(); } -static void hidIrqHandler(UNUSED u32 intSource) +static void updateMcuHidState(void) { - mcuIrq = true; -} + const u32 state = MCU_getEvents(0x40C07F); + if(state == 0) return; -static void updateMcuIrqState(void) -{ - if(!mcuIrq) return; - mcuIrq = false; - - const u32 state = MCU_readReceivedIrqs(); - - u32 tmp = extraKeys; + u32 tmp = g_extraKeys; tmp |= state & (KEY_POWER | KEY_POWER_HELD | KEY_HOME); // Power button pressed/held, HOME button pressed if(state & 1u<<3) tmp &= ~KEY_HOME; // HOME released tmp |= state>>1 & (KEY_WIFI | KEY_SHELL); // WiFi switch, shell closed @@ -83,61 +69,65 @@ tmp |= state>>10 & KEY_BAT_CHARGING; // Battery started charging if(state & 1u<<14) tmp &= ~KEY_BAT_CHARGING; // Battery stopped charging tmp |= state>>16 & KEY_VOL_SLIDER; // Volume slider update - extraKeys = tmp; + g_extraKeys = tmp; } /*static u32 rawCodec2Hid(void) { - alignas(4) u8 buf[13 * 4]; - - CODEC_getRawAdcData((u32*)buf); + static u32 fakeKeysCache = 0; + alignas(4) CdcAdcData adc; + if(!CODEC_getRawAdcData(&adc)) return fakeKeysCache; // Touchscreen - u32 emuButtons = !(buf[0] & 1u<<4)<<20; // KEY_TOUCH - tPos.x = (buf[0]<<8 | buf[1]) * 320u / 4096u; // TODO: Calibration - tPos.y = (buf[10]<<8 | buf[11]) * 240u / 4096u; + // TODO: Calibration + const u16 tx = __builtin_bswap16(adc.touchX[0]); + u32 fakeKeys = (~tx & 1u<<12)<<8; // KEY_TOUCH + tPos.x = tx * 320u / 4096u; + tPos.y = __builtin_bswap16(adc.touchY[0]) * 240u / 4096u; // Circle-Pad - cPos.x = -(((buf[36]<<8 | buf[37]) & 0xFFFu) - 2048u); // X axis is inverted - cPos.y = ((buf[20]<<8 | buf[21]) & 0xFFFu) - 2048u; + // TODO: Calibration + cPos.y = (__builtin_bswap16(adc.cpadY[0]) & 0xFFFu) - 2048u; + cPos.x = -((__builtin_bswap16(adc.cpadX[0]) & 0xFFFu) - 2048u); // X axis is inverted. if((cPos.x >= 0 ? cPos.x : -cPos.x) > CPAD_THRESHOLD) { - if(cPos.x >= 0) emuButtons |= KEY_CPAD_RIGHT; - else emuButtons |= KEY_CPAD_LEFT; + if(cPos.x >= 0) fakeKeys |= KEY_CPAD_RIGHT; + else fakeKeys |= KEY_CPAD_LEFT; } if((cPos.y >= 0 ? cPos.y : -cPos.y) > CPAD_THRESHOLD) { - if(cPos.y >= 0) emuButtons |= KEY_CPAD_UP; - else emuButtons |= KEY_CPAD_DOWN; + if(cPos.y >= 0) fakeKeys |= KEY_CPAD_UP; + else fakeKeys |= KEY_CPAD_DOWN; } - return emuButtons; + fakeKeysCache = fakeKeys; + return fakeKeys; }*/ void hidScanInput(void) { - updateMcuIrqState(); + updateMcuHidState(); - const u32 kOld = kHeld; - kHeld = /*rawCodec2Hid() |*/ REG_HID_PAD; - kDown = (~kOld) & kHeld; - kUp = kOld & (~kHeld); + const u32 kOld = g_kHeld; + g_kHeld = /*rawCodec2Hid() |*/ REG_HID_PAD; + g_kDown = (~kOld) & g_kHeld; + g_kUp = kOld & (~g_kHeld); } u32 hidKeysHeld(void) { - return kHeld; + return g_kHeld; } u32 hidKeysDown(void) { - return kDown; + return g_kDown; } u32 hidKeysUp(void) { - return kUp; + return g_kUp; } /*const TouchPos* hidGetTouchPosPtr(void) @@ -152,8 +142,8 @@ u32 hidGetExtraKeys(u32 clearMask) { - const u32 tmp = extraKeys; - extraKeys &= ~clearMask; + const u32 tmp = g_extraKeys; + g_extraKeys &= ~clearMask; return tmp; } diff --git a/source/arm11/hardware/mcu.c b/source/arm11/hardware/mcu.c index e655fa3..6358099 100644 --- a/source/arm11/hardware/mcu.c +++ b/source/arm11/hardware/mcu.c @@ -16,125 +16,94 @@ * along with this program. If not, see . */ -/* - * Based on code from https://github.com/smealum/ctrulib - */ - -#include "mem_map.h" -#include "arm11/hardware/i2c.h" +#include #include "arm11/hardware/mcu.h" +#include "arm11/hardware/i2c.h" +#include "arm11/hardware/interrupt.h" +#include "arm11/hardware/gpio.h" -enum McuRegisters { - RegBattery = 0x0Bu, - RegExHW = 0x0Fu, - RegPower = 0x20u, - RegLCDs = 0x22u, - RegWifiLED = 0x2Au, - RegCamLED = 0x2Bu, - Reg3DLED = 0x2Cu, - RegRTC = 0x30u, - RegSysModel = 0x7Fu -}; +static bool g_mcuIrq = false; +static u32 g_events = 0; +static void mcuIrqHandler(UNUSED u32 intSource); + void MCU_init(void) { + static bool inited = false; + if(inited) return; + inited = true; + I2C_init(); + + atomic_store_explicit(&g_mcuIrq, true, memory_order_relaxed); + (void)MCU_getEvents(0xFFFFFFFFu); + + MCU_setEventMask(0xC0BF3F80); + // Configure GPIO for MCU event IRQs + GPIO_config(GPIO_4_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE); + IRQ_registerHandler(IRQ_CTR_MCU, 14, 0, true, mcuIrqHandler); } -void MCU_disableLEDs(void) +static void mcuIrqHandler(UNUSED u32 intSource) { - // disable wifi LED - I2C_writeReg(I2C_DEV_CTR_MCU, RegWifiLED, 0); - - // disable 3D LED - I2C_writeReg(I2C_DEV_CTR_MCU, Reg3DLED, 0); - - // disable camera LED - I2C_writeReg(I2C_DEV_CTR_MCU, RegCamLED, 0); + g_mcuIrq = true; } -void MCU_powerOnLCDs(void) +bool MCU_setEventMask(u32 mask) { - // bit1 = lcd power enable for both screens - I2C_writeReg(I2C_DEV_CTR_MCU, RegLCDs, 1<<5 | 1<<3 | 1<<1); + return MCU_writeRegBuf(MCU_REG_EVENT_MASK, (const u8*)&mask, 4); } -void MCU_powerOffLCDs(void) +u32 MCU_getEvents(u32 mask) { - // bit0 = lcd power disable for both screens (also disables backlight) - I2C_writeReg(I2C_DEV_CTR_MCU, RegLCDs, 1); + u32 events = g_events; + + if(atomic_load_explicit(&g_mcuIrq, memory_order_relaxed)) + { + atomic_store_explicit(&g_mcuIrq, false, memory_order_relaxed); + + u32 data; + if(!MCU_readRegBuf(MCU_REG_EVENTS, (u8*)&data, 4)) return 0; + + events |= data; + } + + g_mcuIrq = events & ~mask; + + return events & mask; } -void MCU_triggerPowerOff(void) +u32 MCU_waitEvents(u32 mask) { - I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, RegPower, 1); + u32 events; + + while((events = MCU_getEvents(mask)) == 0u) + { + __wfi(); + } + + return events; } -void MCU_triggerReboot(void) +u8 MCU_readReg(McuReg reg) { - I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, RegPower, 1u << 2); + return I2C_readReg(I2C_DEV_CTR_MCU, reg); } -u8 MCU_readBatteryLevel(void) +bool MCU_writeReg(McuReg reg, u8 data) { - u8 state; - - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, RegBattery, &state, 1)) - return 0; - - return state; + return I2C_writeReg(I2C_DEV_CTR_MCU, reg, data); } -u8 MCU_readExternalHwState(void) +bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size) { - return I2C_readReg(I2C_DEV_CTR_MCU, RegExHW); + return I2C_readRegBuf(I2C_DEV_CTR_MCU, reg, out, size); } -u8 MCU_readSystemModel(void) +bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size) { - u8 sysinfo[0x13]; - - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, RegSysModel, sysinfo, sizeof sysinfo)) - return 0xFF; - - return sysinfo[9]; -} - -void MCU_readRTC(void *rtc) -{ - if(!rtc) return; - - I2C_readRegBuf(I2C_DEV_CTR_MCU, RegRTC, rtc, 8); -} - -u32 MCU_readReceivedIrqs(void) -{ - u32 data; - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, 0x10, (u8*)&data, 4)) return 0; - return data; -} - -bool MCU_setIrqBitmask(u32 mask) -{ - return I2C_writeRegBuf(I2C_DEV_CTR_MCU, 0x18, (const u8*)&mask, 4); -} - -u8 MCU_readHidHeld(void) -{ - u8 data[19]; - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, 0x7F, data, sizeof(data))) return 0xFF; - return data[18]; -} - -bool MCU_powerOnLcdBacklights(void) -{ - return I2C_writeReg(I2C_DEV_CTR_MCU, 0x22, 1<<5 | 1<<3); // bit3 = lower screen, bit5 = upper -} - -bool MCU_setPowerLedState(PwLedState state) -{ - return I2C_writeReg(I2C_DEV_CTR_MCU, 0x29, state); + return I2C_writeRegBuf(I2C_DEV_CTR_MCU, reg, in, size); } diff --git a/source/arm11/main.c b/source/arm11/main.c index 3fb73f5..a64d61f 100644 --- a/source/arm11/main.c +++ b/source/arm11/main.c @@ -96,7 +96,7 @@ bool splash_wait = false; if(show_menu || (!nextBootSlot && (bootmode != BootModeQuiet))) { - if (!gfx_initialized) GFX_init(true); + if (!gfx_initialized) GFX_init(GFX_RGB565, GFX_RGB565); gfx_initialized = true; if(configDataExist(KSplashScreen)) { @@ -116,7 +116,7 @@ { splash_wait = drawSplashscreen(banner_spla, tmpBuf, -1, -1, SCREEN_TOP); if (bootmode == BootModeQuick) - drawSplashscreen(menu_spla, tmpBuf, -1, 16, SCREEN_SUB); + drawSplashscreen(menu_spla, tmpBuf, -1, 16, SCREEN_BOT); free(tmpBuf); } else @@ -231,7 +231,7 @@ { if(!gfx_initialized) { - GFX_init(true); + GFX_init(GFX_RGB565, GFX_RGB565); gfx_initialized = true; } // init and select terminal console @@ -271,7 +271,7 @@ { // init menu console PrintConsole menu_con; - consoleInit(SCREEN_SUB, &menu_con, false); + consoleInit(SCREEN_BOT, &menu_con, false); // run menu menu_ret = menuProcess(&menu_con, &term_con, menu_fb3ds); @@ -383,7 +383,11 @@ if (configHasChanged()) writeConfigFile(); // deinit GFX if it was initialized - if(gfx_initialized) GFX_deinit(firm_err == 1); + if(gfx_initialized) + { + if(firm_err == 1) GFX_setFramebufFmt(GFX_BGR8, GFX_BGR8); + else GFX_deinit(); + } // deinit filesystem fsUnmountAll(); @@ -411,8 +415,7 @@ // make sure GFX is in the right state if(!gfx_initialized && (firm_err == 1)) { - GFX_init(true); - GFX_deinit(true); + GFX_init(GFX_BGR8, GFX_BGR8); } // launch firm diff --git a/source/arm11/menu/battery.c b/source/arm11/menu/battery.c index cb6b406..220ab6b 100644 --- a/source/arm11/menu/battery.c +++ b/source/arm11/menu/battery.c @@ -24,6 +24,6 @@ void getBatteryState(BatteryState *battery) { - battery->percent = MCU_readBatteryLevel(); + battery->percent = MCU_getBatteryLevel(); battery->charging = hidGetExtraKeys(0) & KEY_BAT_CHARGING; } diff --git a/source/arm11/menu/bootinfo.c b/source/arm11/menu/bootinfo.c index 494aafc..a75f094 100644 --- a/source/arm11/menu/bootinfo.c +++ b/source/arm11/menu/bootinfo.c @@ -59,7 +59,7 @@ // Get MCU system information. if (int_model >= NUM_MODELS) - int_model = MCU_readSystemModel(); + int_model = MCU_getSystemModel(); if (int_model < NUM_MODELS) ee_snprintf(info->model, 24, "%s", s_modelNames[int_model].name); diff --git a/source/arm11/menu/menu_func.c b/source/arm11/menu/menu_func.c index fa42453..7fa0329 100644 --- a/source/arm11/menu/menu_func.c +++ b/source/arm11/menu/menu_func.c @@ -213,8 +213,8 @@ // check if selection at least looks valid const char* splash_name[] = { CSPLASH_NAME_TOP, CSPLASH_NAME_SUB }; - const u32 splash_bin_width[] = { SCREEN_WIDTH_TOP, SCREEN_WIDTH_SUB }; - const u32 splash_bin_height[] = { SCREEN_HEIGHT_TOP, SCREEN_HEIGHT_SUB }; + const u32 splash_bin_width[] = { SCREEN_WIDTH_TOP, SCREEN_WIDTH_BOT }; + const u32 splash_bin_height[] = { SCREEN_HEIGHT_TOP, SCREEN_HEIGHT_BOT }; char* splash_path = (char*) malloc(FF_MAX_LFN + 1); char* splash_bin_path = (char*) malloc(FF_MAX_LFN + 1); bool valid = false; @@ -606,7 +606,7 @@ // current state of the RTC u8 rtc[8] = { 0 }; - MCU_readRTC(rtc); + MCU_getRTCTime(rtc); // create NAND backup filename char fpath[64]; diff --git a/source/arm11/menu/menu_util.c b/source/arm11/menu/menu_util.c index 14fd8a3..7c081d2 100644 --- a/source/arm11/menu/menu_util.c +++ b/source/arm11/menu/menu_util.c @@ -202,7 +202,7 @@ void clearScreens(void) { - GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_SUB, 1u<<9, SCREEN_SIZE_SUB, 0); + GX_memoryFill(RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, RENDERBUF_BOT, 1u<<9, SCREEN_SIZE_BOT, 0); GFX_waitForEvent(GFX_EVENT_PSC0, true); } @@ -215,7 +215,7 @@ if (!color) { u8 rtc[8]; - MCU_readRTC(rtc); + MCU_getRTCTime(rtc); color = consoleGetRGB565Color((rtc[0] % 6) + 1); } @@ -276,7 +276,7 @@ } fClose(fHandle); - if (drawSplashscreen(splash_data, (u16*)splash_buffer, -1, -1, SCREEN_SUB)) + if (drawSplashscreen(splash_data, (u16*)splash_buffer, -1, -1, SCREEN_BOT)) res = true; } @@ -292,21 +292,21 @@ // only intended to be ran when the shell is closed void sleepmode(void) { - GFX_enterLowPowerState(); + //GFX_enterLowPowerState(); MCU_setPowerLedState(PWLED_SLEEP); do { __wfi(); hidScanInput(); } while(hidGetExtraKeys(0) & KEY_SHELL); - MCU_setPowerLedState(PWLED_NORMAL); - GFX_returnFromLowPowerState(); + MCU_setPowerLedState(PWLED_AUTO); + //GFX_returnFromLowPowerState(); } void updateScreens(void) { - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + GX_textureCopy(RENDERBUF_TOP, 0, GFX_getFramebuffer(SCREEN_TOP), + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_waitForEvent(GFX_EVENT_PPF, true); // Texture copy GFX_swapFramebufs(); GFX_waitForEvent(GFX_EVENT_PDC0, true); // VBlank diff --git a/source/arm11/menu/splash.c b/source/arm11/menu/splash.c index c7feed4..24d8d0a 100644 --- a/source/arm11/menu/splash.c +++ b/source/arm11/menu/splash.c @@ -40,7 +40,7 @@ const u16 width = header->width, height = header->height; if(width == 0 || height == 0) return false; - if(width > (screen ? SCREEN_WIDTH_TOP : SCREEN_WIDTH_SUB) || height > SCREEN_HEIGHT_TOP) + if(width > (screen ? SCREEN_WIDTH_BOT : SCREEN_WIDTH_TOP) || height > SCREEN_HEIGHT_TOP) return false; const u32 flags = header->flags; @@ -70,22 +70,22 @@ else imgData = (u16*)(data + sizeof(SplashHeader)); u32 screenWidth, screenHeight, xx, yy; - if(screen) /* SCREEN_TOP */ + if(!screen) /* SCREEN_TOP */ { screenWidth = SCREEN_WIDTH_TOP; screenHeight = SCREEN_HEIGHT_TOP; } - else /* SCREEN_SUB */ + else /* SCREEN_BOT */ { - screenWidth = SCREEN_WIDTH_SUB; - screenHeight = SCREEN_HEIGHT_SUB; + screenWidth = SCREEN_WIDTH_BOT; + screenHeight = SCREEN_HEIGHT_BOT; } if(startX < 0 || (u32)startX > screenWidth - width) xx = (screenWidth - width) / 2; else xx = (u32)startX; if(startY < 0 || (u32)startY > screenHeight - height) yy = (screenHeight - height) / 2; else yy = (u32)startY; - u16 *fb = (screen ? (u16*)RENDERBUF_TOP : (u16*)RENDERBUF_SUB); + u16 *fb = (screen ? (u16*)RENDERBUF_BOT : (u16*)RENDERBUF_TOP); for(u32 x = 0; x < width; x++) { for(u32 y = 0; y < height; y++) diff --git a/source/arm11/power.c b/source/arm11/power.c index dd37cfc..1dc36ae 100644 --- a/source/arm11/power.c +++ b/source/arm11/power.c @@ -29,7 +29,6 @@ static void power_safe_halt(void) { - MCU_powerOffLCDs(); PXI_sendCmd(IPC_CMD9_PREPARE_POWER, NULL, 0); // give the screens a bit of time to turn off @@ -42,7 +41,7 @@ { power_safe_halt(); - MCU_triggerPowerOff(); + MCU_powerOffSys(); __cpsid(aif); while(1) __wfi(); @@ -52,7 +51,7 @@ { power_safe_halt(); - MCU_triggerReboot(); + MCU_rebootSys(); __cpsid(aif); while(1) __wfi(); diff --git a/source/arm11/util/rbtree/rbtree_clear.c b/source/arm11/util/rbtree/rbtree_clear.c new file mode 100644 index 0000000..ade81ce --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_clear.c @@ -0,0 +1,34 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +void +rbtree_clear(rbtree_t *tree, + rbtree_node_destructor_t destructor) +{ + rbtree_node_t *node = tree->root; + + while(tree->root != NULL) + { + while(node->child[LEFT] != NULL) + node = node->child[LEFT]; + + if(node->child[RIGHT] != NULL) + node = node->child[RIGHT]; + else + { + rbtree_node_t *parent = get_parent(node); + + if(parent == NULL) + tree->root = NULL; + else + parent->child[node != parent->child[LEFT]] = NULL; + + if(destructor != NULL) + (*destructor)(node); + + node = parent; + } + } + + tree->size = 0; +} diff --git a/source/arm11/util/rbtree/rbtree_empty.c b/source/arm11/util/rbtree/rbtree_empty.c new file mode 100644 index 0000000..a1fa56a --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_empty.c @@ -0,0 +1,7 @@ +#include "arm11/util/rbtree.h" + +int +rbtree_empty(const rbtree_t *tree) +{ + return tree->root == NULL; +} diff --git a/source/arm11/util/rbtree/rbtree_find.c b/source/arm11/util/rbtree/rbtree_find.c new file mode 100644 index 0000000..4fa46d5 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_find.c @@ -0,0 +1,30 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +rbtree_node_t* +rbtree_find(const rbtree_t *tree, + const rbtree_node_t *node) +{ + rbtree_node_t *tmp = tree->root; + rbtree_node_t *save = NULL; + + while(tmp != NULL) + { + int rc = (*tree->comparator)(node, tmp); + if(rc < 0) + { + tmp = tmp->child[LEFT]; + } + else if(rc > 0) + { + tmp = tmp->child[RIGHT]; + } + else + { + save = tmp; + tmp = tmp->child[LEFT]; + } + } + + return save; +} diff --git a/source/arm11/util/rbtree/rbtree_init.c b/source/arm11/util/rbtree/rbtree_init.c new file mode 100644 index 0000000..8da65d7 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_init.c @@ -0,0 +1,10 @@ +#include "arm11/util/rbtree.h" + +void +rbtree_init(rbtree_t *tree, + rbtree_node_comparator_t comparator) +{ + tree->root = NULL; + tree->comparator = comparator; + tree->size = 0; +} diff --git a/source/arm11/util/rbtree/rbtree_insert.c b/source/arm11/util/rbtree/rbtree_insert.c new file mode 100644 index 0000000..6267c9c --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_insert.c @@ -0,0 +1,96 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +static rbtree_node_t* +do_insert(rbtree_t *tree, + rbtree_node_t *node, + int multi) +{ + rbtree_node_t *original = node; + rbtree_node_t **tmp = &tree->root; + rbtree_node_t *parent = NULL; + rbtree_node_t *save = NULL; + + while(*tmp != NULL) + { + int cmp = (*(tree->comparator))(node, *tmp); + parent = *tmp; + + if(cmp < 0) + tmp = &((*tmp)->child[LEFT]); + else if(cmp > 0) + tmp = &((*tmp)->child[RIGHT]); + else + { + if(!multi) + save = *tmp; + + tmp = &((*tmp)->child[LEFT]); + } + } + + if(save != NULL) + { + return save; + } + + *tmp = node; + + node->child[LEFT] = node->child[RIGHT] = NULL; + set_parent(node, parent); + + set_red(node); + + while(is_red((parent = get_parent(node)))) + { + rbtree_node_t *grandparent = get_parent(parent); + int left = (parent == grandparent->child[LEFT]); + rbtree_node_t *uncle = grandparent->child[left]; + + if(is_red(uncle)) + { + set_black(uncle); + set_black(parent); + set_red(grandparent); + + node = grandparent; + } + else + { + if(parent->child[left] == node) + { + rbtree_node_t *tmp; + + rbtree_rotate(tree, parent, left); + + tmp = parent; + parent = node; + node = tmp; + } + + set_black(parent); + set_red(grandparent); + rbtree_rotate(tree, grandparent, !left); + } + } + + set_black(tree->root); + + tree->size += 1; + + return original; +} + +rbtree_node_t* +rbtree_insert(rbtree_t *tree, + rbtree_node_t *node) +{ + return do_insert(tree, node, 0); +} + +void +rbtree_insert_multi(rbtree_t *tree, + rbtree_node_t *node) +{ + do_insert(tree, node, 1); +} diff --git a/source/arm11/util/rbtree/rbtree_internal.h b/source/arm11/util/rbtree/rbtree_internal.h new file mode 100644 index 0000000..6d0d0a9 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_internal.h @@ -0,0 +1,64 @@ +#pragma once + +#define LEFT 0 +#define RIGHT 1 + +typedef enum rbtree_color +{ + RED = 0, + BLACK = 1, +} rbtree_color_t; + +#define COLOR_MASK (RED|BLACK) + +static inline void +set_black(rbtree_node_t *node) +{ + node->parent_color &= ~COLOR_MASK; + node->parent_color |= BLACK; +} + +static inline void +set_red(rbtree_node_t *node) +{ + node->parent_color &= ~COLOR_MASK; + node->parent_color |= RED; +} + +static inline rbtree_color_t +get_color(const rbtree_node_t *node) +{ + if(node == NULL) + return BLACK; + return (rbtree_color_t)(node->parent_color & COLOR_MASK); +} + +static inline int +is_black(const rbtree_node_t *node) +{ + return get_color(node) == BLACK; +} + +static inline int +is_red(const rbtree_node_t *node) +{ + return get_color(node) == RED; +} + +static inline rbtree_node_t* +get_parent(const rbtree_node_t *node) +{ + return (rbtree_node_t*)(node->parent_color & ~COLOR_MASK); +} + +static inline void +set_parent(rbtree_node_t *node, + const rbtree_node_t *parent) +{ + node->parent_color = (get_color(node)) | ((uintptr_t)parent); +} + +void +rbtree_rotate(rbtree_t *tree, + rbtree_node_t *node, + int left); diff --git a/source/arm11/util/rbtree/rbtree_iterator.c b/source/arm11/util/rbtree/rbtree_iterator.c new file mode 100644 index 0000000..f715a57 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_iterator.c @@ -0,0 +1,41 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +static inline rbtree_node_t* +do_iterate(const rbtree_node_t *node, + int next) +{ + rbtree_node_t *it = (rbtree_node_t*)node; + + if(it->child[next] != NULL) + { + it = it->child[next]; + while(it->child[!next] != NULL) + it = it->child[!next]; + } + else + { + rbtree_node_t *parent = get_parent(node); + while(parent != NULL && it == parent->child[next]) + { + it = parent; + parent = get_parent(it); + } + + it = parent; + } + + return it; +} + +rbtree_node_t* +rbtree_node_next(const rbtree_node_t *node) +{ + return do_iterate(node, RIGHT); +} + +rbtree_node_t* +rbtree_node_prev(const rbtree_node_t *node) +{ + return do_iterate(node, LEFT); +} diff --git a/source/arm11/util/rbtree/rbtree_minmax.c b/source/arm11/util/rbtree/rbtree_minmax.c new file mode 100644 index 0000000..7843666 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_minmax.c @@ -0,0 +1,37 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +static inline rbtree_node_t* +do_minmax(const rbtree_t *tree, + int max) +{ + rbtree_node_t *node = tree->root; + + if(node == NULL) + return NULL; + + while(node->child[max] != NULL) + node = node->child[max]; + + return node; +} + +rbtree_node_t* +rbtree_min(const rbtree_t *tree) +{ + rbtree_node_t *node; + + node = do_minmax(tree, LEFT); + + return node; +} + +rbtree_node_t* +rbtree_max(const rbtree_t *tree) +{ + rbtree_node_t *node; + + node = do_minmax(tree, RIGHT); + + return node; +} diff --git a/source/arm11/util/rbtree/rbtree_remove.c b/source/arm11/util/rbtree/rbtree_remove.c new file mode 100644 index 0000000..2a4a6fc --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_remove.c @@ -0,0 +1,140 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +static void +recolor(rbtree_t *tree, + rbtree_node_t *parent, + rbtree_node_t *node) +{ + rbtree_node_t *sibling; + + while(is_black(node) && node != tree->root) + { + int left = (node == parent->child[LEFT]); + + sibling = parent->child[left]; + + if(is_red(sibling)) + { + set_black(sibling); + set_red(parent); + rbtree_rotate(tree, parent, left); + sibling = parent->child[left]; + } + + if(is_black(sibling->child[LEFT]) && is_black(sibling->child[RIGHT])) + { + set_red(sibling); + node = parent; + parent = get_parent(node); + } + else + { + if(is_black(sibling->child[left])) + { + set_black(sibling->child[!left]); + set_red(sibling); + rbtree_rotate(tree, sibling, !left); + sibling = parent->child[left]; + } + + if(is_black(parent)) + set_black(sibling); + else + set_red(sibling); + set_black(parent); + set_black(sibling->child[left]); + + rbtree_rotate(tree, parent, left); + + node = tree->root; + } + } + + if(node != NULL) + set_black(node); +} + +rbtree_node_t* +rbtree_remove(rbtree_t *tree, + rbtree_node_t *node, + rbtree_node_destructor_t destructor) +{ + rbtree_color_t color; + rbtree_node_t *child, *parent, *original = node; + rbtree_node_t *next; + + next = rbtree_node_next(node); + + if(node->child[LEFT] != NULL && node->child[RIGHT] != NULL) + { + rbtree_node_t *old = node; + + node = node->child[RIGHT]; + while(node->child[LEFT] != NULL) + node = node->child[LEFT]; + + parent = get_parent(old); + if(parent != NULL) + { + if(parent->child[LEFT] == old) + parent->child[LEFT] = node; + else + parent->child[RIGHT] = node; + } + else + tree->root = node; + + child = node->child[RIGHT]; + parent = get_parent(node); + color = get_color(node); + + if(parent == old) + parent = node; + else + { + if(child != NULL) + set_parent(child, parent); + parent->child[LEFT] = child; + + node->child[RIGHT] = old->child[RIGHT]; + set_parent(old->child[RIGHT], node); + } + + node->parent_color = old->parent_color; + node->child[LEFT] = old->child[LEFT]; + set_parent(old->child[LEFT], node); + } + else + { + if(node->child[LEFT] == NULL) + child = node->child[RIGHT]; + else + child = node->child[LEFT]; + + parent = get_parent(node); + color = get_color(node); + + if(child != NULL) + set_parent(child, parent); + if(parent != NULL) + { + if(parent->child[LEFT] == node) + parent->child[LEFT] = child; + else + parent->child[RIGHT] = child; + } + else + tree->root = child; + } + + if(color == BLACK) + recolor(tree, parent, child); + + if(destructor != NULL) + (*destructor)(original); + + tree->size -= 1; + + return next; +} diff --git a/source/arm11/util/rbtree/rbtree_rotate.c b/source/arm11/util/rbtree/rbtree_rotate.c new file mode 100644 index 0000000..154f2d7 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_rotate.c @@ -0,0 +1,28 @@ +#include "arm11/util/rbtree.h" +#include "rbtree_internal.h" + +void +rbtree_rotate(rbtree_t *tree, + rbtree_node_t *node, + int left) +{ + rbtree_node_t *tmp = node->child[left]; + rbtree_node_t *parent = get_parent(node); + + node->child[left] = tmp->child[!left]; + if(tmp->child[!left] != NULL) + set_parent(tmp->child[!left], node); + + tmp->child[!left] = node; + set_parent(tmp, parent); + if(parent != NULL) + { + if(node == parent->child[!left]) + parent->child[!left] = tmp; + else + parent->child[left] = tmp; + } + else + tree->root = tmp; + set_parent(node, tmp); +} diff --git a/source/arm11/util/rbtree/rbtree_size.c b/source/arm11/util/rbtree/rbtree_size.c new file mode 100644 index 0000000..0416761 --- /dev/null +++ b/source/arm11/util/rbtree/rbtree_size.c @@ -0,0 +1,7 @@ +#include "arm11/util/rbtree.h" + +size_t +rbtree_size(const rbtree_t *tree) +{ + return tree->size; +} diff --git a/source/arm9/debug.c b/source/arm9/debug.c index 3c527ff..eb47907 100644 --- a/source/arm9/debug.c +++ b/source/arm9/debug.c @@ -60,8 +60,8 @@ while(1) { const u32 color = RGB8_to_565(0, 255, 0)<<16 | RGB8_to_565(0, 255, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } @@ -74,8 +74,8 @@ while(1) { const u32 color = RGB8_to_565(0, 255, 0)<<16 | RGB8_to_565(0, 255, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } @@ -90,8 +90,8 @@ while(1) { const u32 color = RGB8_to_565(255, 0, 0)<<16 | RGB8_to_565(255, 0, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } diff --git a/source/arm9/firm.c b/source/arm9/firm.c index 8e59d4f..6af6ccf 100644 --- a/source/arm9/firm.c +++ b/source/arm9/firm.c @@ -314,10 +314,10 @@ { (u8*)FRAMEBUF_TOP_A_1, (u8*)FRAMEBUF_TOP_A_1, - (u8*)FRAMEBUF_SUB_A_1 + 0x17700, + (u8*)FRAMEBUF_BOT_A_1 + 0x17700, (u8*)FRAMEBUF_TOP_A_2, (u8*)FRAMEBUF_TOP_A_2, - (u8*)FRAMEBUF_SUB_A_2 + 0x17700 + (u8*)FRAMEBUF_BOT_A_2 + 0x17700 }; memcpy((void*)(ITCM_KERNEL_MIRROR + 0x7478), &fbs, sizeof(fbs)); diff --git a/source/arm9/hardware/hid.c b/source/arm9/hardware/hid.c index 24484ad..7b9b829 100644 --- a/source/arm9/hardware/hid.c +++ b/source/arm9/hardware/hid.c @@ -2,11 +2,13 @@ * This code is part of ctrulib (https://github.com/smealum/ctrulib) */ -#include "mem_map.h" #include "types.h" +#include "mem_map.h" -#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) +#define HID_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x46000) +#define REG_HID_PAD (*((vu16*)(HID_REGS_BASE + 0x0)) ^ 0xFFFFu) +#define REG_HID_PADCNT *((vu16*)(HID_REGS_BASE + 0x2)) static u32 kHeld, kDown, kUp; diff --git a/source/fb_assert.c b/source/fb_assert.c index e6c57f8..7752032 100644 --- a/source/fb_assert.c +++ b/source/fb_assert.c @@ -42,8 +42,8 @@ PXI_sendCmd(IPC_CMD11_PANIC, NULL, 0); #elif ARM11 ee_printf("Assertion failed: %s:%" PRIu32, str, line); - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + GX_textureCopy(RENDERBUF_TOP, 0, GFX_getFramebuffer(SCREEN_TOP), + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); PXI_sendCmd(IPC_CMD9_PANIC, NULL, 0); #endif @@ -52,8 +52,8 @@ { #ifdef ARM9 const u32 color = RGB8_to_565(0, 0, 255)<<16 | RGB8_to_565(0, 0, 255); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill(FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill(FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); #elif ARM11 __wfi(); #endif diff --git a/source/hardware/pxi.c b/source/hardware/pxi.c index 81609ac..4087317 100644 --- a/source/hardware/pxi.c +++ b/source/hardware/pxi.c @@ -64,13 +64,13 @@ REG_PXI_CNT = PXI_CNT_ENABLE_SRFIFO | PXI_CNT_FIFO_ERROR | PXI_CNT_FLUSH_SFIFO; #ifdef ARM9 - REG_PXI_SYNC_SENT = 9; - while(REG_PXI_SYNC_RECVD != 11); + pxiSendWord(0x99); + while(pxiRecvWord() != 0x11); IRQ_registerHandler(IRQ_PXI_SYNC, pxiIrqHandler); #elif ARM11 - while(REG_PXI_SYNC_RECVD != 9); - REG_PXI_SYNC_SENT = 11; + while(pxiRecvWord() != 0x99); + pxiSendWord(0x11); IRQ_registerHandler(IRQ_PXI_SYNC, 13, 0, true, pxiIrqHandler); #endif