From 30f0b004c23a7de10c1723c67dd684d71f7b7dfd Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Sat, 18 Jul 2020 20:25:34 -0300 Subject: [PATCH] fixed screen init, hopefully the last commmit - properly performs gpu/backlight reset - nukes vram so the initrd had to be moved to arm9 memory, and have its size (at least temporarily) limited to 256k --- Makefile | 6 +- Makefile.build | 70 +- arm11/source/arm/exception.c | 434 +++++----- arm11/source/arm/scu.c | 64 +- arm11/source/arm/scu.h | 46 +- arm11/source/arm/timer.h | 4 + arm11/source/hw/codec.c | 292 +++---- arm11/source/hw/codec.h | 64 +- arm11/source/hw/gpio.h | 68 +- arm11/source/hw/gpulcd.c | 430 +++++----- arm11/source/hw/gpulcd.h | 175 +++- arm11/source/hw/hid.c | 146 ++-- arm11/source/hw/hid.h | 48 +- arm11/source/hw/i2c.h | 13 + arm11/source/hw/mcu.c | 10 +- arm11/source/hw/mcu.h | 136 ++-- arm11/source/hw/nvram.c | 186 ++--- arm11/source/hw/nvram.h | 68 +- arm11/source/main.c | 17 +- arm11/source/system/sections.h | 70 +- arm11/source/system/sys.c | 11 +- arm11/source/system/sys.h | 76 +- arm11/source/system/xalloc.c | 74 +- arm11/source/system/xalloc.h | 50 +- arm9/source/game/bps.c | 1372 ++++++++++++++++---------------- arm9/source/main.c | 3 - arm9/source/system/bootfirm.s | 6 +- arm9/source/system/spiflash.c | 88 +- arm9/source/system/vram0.h | 4 +- arm9/source/utils/gameutil.c | 5 +- common/common.h | 158 ++-- common/fixp.h | 120 +-- common/hid_map.h | 70 +- common/pxi.c | 118 +-- common/shmem.h | 78 +- common/vram.h | 10 +- 36 files changed, 2409 insertions(+), 2181 deletions(-) diff --git a/Makefile b/Makefile index 68f8065..525a528 100644 --- a/Makefile +++ b/Makefile @@ -83,14 +83,14 @@ vram0: @$(MAKE) --no-print-directory -C $(@D) firm: $(ELF) vram0 - @test `wc -c <$(VRAM_OUT)` -le 3145728 + @test `wc -c <$(VRAM_OUT)` -le 262144 @mkdir -p $(call dirname,"$(FIRM)") $(call dirname,"$(FIRMD)") @echo "[FLAVOR] $(FLAVOR)" @echo "[VERSION] $(VERSION)" @echo "[BUILD] $(DBUILTL)" @echo "[FIRM] $(FIRM)" - @$(PY3) -m firmtool build $(FIRM) $(FTFLAGS) -g -A 0x18000000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy + @$(PY3) -m firmtool build $(FIRM) $(FTFLAGS) -g -A 0x80C0000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy @echo "[FIRM] $(FIRMD)" - @$(PY3) -m firmtool build $(FIRMD) $(FTDFLAGS) -g -A 0x18000000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy + @$(PY3) -m firmtool build $(FIRMD) $(FTDFLAGS) -g -A 0x80C0000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy .FORCE: diff --git a/Makefile.build b/Makefile.build index 27be973..0a36f6f 100755 --- a/Makefile.build +++ b/Makefile.build @@ -1,35 +1,35 @@ - -OBJECTS := $(patsubst $(SOURCE)/%.s, $(BUILD)/%.o, \ - $(patsubst $(SOURCE)/%.c, $(BUILD)/%.o, \ - $(call rwildcard, $(SOURCE), *.s *.c))) - -OBJECTS_COMMON := $(patsubst $(COMMON_DIR)/%.c, $(BUILD)/%.cmn.o, \ - $(call rwildcard, $(COMMON_DIR), *.c)) - -.PHONY: all -all: $(TARGET).elf - -.PHONY: clean -clean: - @rm -rf $(BUILD) $(TARGET).elf $(TARGET).map - -$(TARGET).elf: $(OBJECTS) $(OBJECTS_COMMON) - @mkdir -p "$(@D)" - @$(CC) $(LDFLAGS) $^ -o $@ - -$(BUILD)/%.cmn.o: $(COMMON_DIR)/%.c - @mkdir -p "$(@D)" - @echo "[$(PROCESSOR)] $<" - @$(CC) -c $(CFLAGS) -o $@ $< - -$(BUILD)/%.o: $(SOURCE)/%.c - @mkdir -p "$(@D)" - @echo "[$(PROCESSOR)] $<" - @$(CC) -c $(CFLAGS) -o $@ $< - -$(BUILD)/%.o: $(SOURCE)/%.s - @mkdir -p "$(@D)" - @echo "[$(PROCESSOR)] $<" - @$(CC) -c $(ASFLAGS) -o $@ $< - -include $(call rwildcard, $(BUILD), *.d) + +OBJECTS := $(patsubst $(SOURCE)/%.s, $(BUILD)/%.o, \ + $(patsubst $(SOURCE)/%.c, $(BUILD)/%.o, \ + $(call rwildcard, $(SOURCE), *.s *.c))) + +OBJECTS_COMMON := $(patsubst $(COMMON_DIR)/%.c, $(BUILD)/%.cmn.o, \ + $(call rwildcard, $(COMMON_DIR), *.c)) + +.PHONY: all +all: $(TARGET).elf + +.PHONY: clean +clean: + @rm -rf $(BUILD) $(TARGET).elf $(TARGET).map + +$(TARGET).elf: $(OBJECTS) $(OBJECTS_COMMON) + @mkdir -p "$(@D)" + @$(CC) $(LDFLAGS) $^ -o $@ + +$(BUILD)/%.cmn.o: $(COMMON_DIR)/%.c + @mkdir -p "$(@D)" + @echo "[$(PROCESSOR)] $<" + @$(CC) -c $(CFLAGS) -o $@ $< + +$(BUILD)/%.o: $(SOURCE)/%.c + @mkdir -p "$(@D)" + @echo "[$(PROCESSOR)] $<" + @$(CC) -c $(CFLAGS) -o $@ $< + +$(BUILD)/%.o: $(SOURCE)/%.s + @mkdir -p "$(@D)" + @echo "[$(PROCESSOR)] $<" + @$(CC) -c $(ASFLAGS) -o $@ $< + +include $(call rwildcard, $(BUILD), *.d) diff --git a/arm11/source/arm/exception.c b/arm11/source/arm/exception.c index 86df02e..a2c99b4 100644 --- a/arm11/source/arm/exception.c +++ b/arm11/source/arm/exception.c @@ -1,217 +1,217 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include - -static const u8 num_font[16*8]; - -#define SCREEN ((u16*)(VRAM_TOP_LA)) - -void draw_char(u16 *fb, int c, int x, int y) -{ - for (int _y = 0; _y < 8; _y++) { - for (int _x = 0; _x < 8; _x++) { - u16 *fbpos = fb + (240 - (y + _y)) + (240 * (x + _x)); - - u8 mask = (num_font[(c * 8) + _y] >> (8 - _x)) & 1; - - if (mask) - *fbpos = ~0; - else - *fbpos = 0; - } - } -} - -void draw_hex(u16 *fb, u32 num, int x, int y) -{ - x += 7*8; - for (int i = 0; i < 8; i++) { - draw_char(fb, num & 0xf, x, y); - num >>= 4; - x -= 8; - } -} - -void do_exception(u32 type, u32 *regs) -{ - for (int i = 0; i < 400*240; i++) - SCREEN[i] = 0; - - draw_hex(SCREEN, type, 8, 16); - - for (int i = 0; i < 20; i += 2) { - draw_hex(SCREEN, i, 8, 32 + (i * 4)); - draw_hex(SCREEN, regs[i], 80, 32 + (i * 4)); - - draw_hex(SCREEN, i + 1, 208, 32 + (i * 4)); - draw_hex(SCREEN, regs[i + 1], 280, 32 + (i * 4)); - } - - while(1) - ARM_WFI(); -} - -static const u8 num_font[] = { - 0b00000000, - 0b00011000, - 0b00100100, - 0b00101100, - 0b00110100, - 0b00100100, - 0b00011000, - 0b00000000, // 0 - - 0b00000000, - 0b00011000, - 0b00101000, - 0b00001000, - 0b00001000, - 0b00001000, - 0b00111100, - 0b00000000, // 1 - - 0b00000000, - 0b00011000, - 0b00100100, - 0b00000100, - 0b00001000, - 0b00010000, - 0b00111100, - 0b00000000, // 2 - - 0b00000000, - 0b00111000, - 0b00000100, - 0b00011000, - 0b00000100, - 0b00000100, - 0b00111000, - 0b00000000, // 3 - - 0b00000000, - 0b00100100, - 0b00100100, - 0b00111100, - 0b00000100, - 0b00000100, - 0b00000100, - 0b00000000, // 4 - - 0b00000000, - 0b00111100, - 0b00100000, - 0b00111000, - 0b00000100, - 0b00000100, - 0b00111000, - 0b00000000, // 5 - - 0b00000000, - 0b00011100, - 0b00100000, - 0b00111000, - 0b00100100, - 0b00100100, - 0b00011000, - 0b00000000, // 6 - - 0b00000000, - 0b00111100, - 0b00000100, - 0b00000100, - 0b00001000, - 0b00010000, - 0b00010000, - 0b00000000, // 7 - - 0b00000000, - 0b00011000, - 0b00100100, - 0b00011000, - 0b00100100, - 0b00100100, - 0b00011000, - 0b00000000, // 8 - - 0b00000000, - 0b00011000, - 0b00100100, - 0b00011100, - 0b00000100, - 0b00000100, - 0b00111000, - 0b00000000, // 9 - - 0b00000000, - 0b00011000, - 0b00100100, - 0b00111100, - 0b00100100, - 0b00100100, - 0b00100100, - 0b00000000, // A - - 0b00000000, - 0b00111000, - 0b00100100, - 0b00111000, - 0b00100100, - 0b00100100, - 0b00111000, - 0b00000000, // B - - 0b00000000, - 0b00011100, - 0b00100000, - 0b00100000, - 0b00100000, - 0b00100000, - 0b00011100, - 0b00000000, // C - - 0b00000000, - 0b00110000, - 0b00101000, - 0b00100100, - 0b00100100, - 0b00101000, - 0b00110000, - 0b00000000, // C - - 0b00000000, - 0b00111100, - 0b00100000, - 0b00111100, - 0b00100000, - 0b00100000, - 0b00111100, - 0b00000000, // E - - 0b00000000, - 0b00111100, - 0b00100000, - 0b00111100, - 0b00100000, - 0b00100000, - 0b00100000, - 0b00000000, // F -}; +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include + +static const u8 num_font[16*8]; + +#define SCREEN ((u16*)(VRAM_TOP_LA)) + +void draw_char(u16 *fb, int c, int x, int y) +{ + for (int _y = 0; _y < 8; _y++) { + for (int _x = 0; _x < 8; _x++) { + u16 *fbpos = fb + (240 - (y + _y)) + (240 * (x + _x)); + + u8 mask = (num_font[(c * 8) + _y] >> (8 - _x)) & 1; + + if (mask) + *fbpos = ~0; + else + *fbpos = 0; + } + } +} + +void draw_hex(u16 *fb, u32 num, int x, int y) +{ + x += 7*8; + for (int i = 0; i < 8; i++) { + draw_char(fb, num & 0xf, x, y); + num >>= 4; + x -= 8; + } +} + +void do_exception(u32 type, u32 *regs) +{ + for (int i = 0; i < 400*240; i++) + SCREEN[i] = 0; + + draw_hex(SCREEN, type, 8, 16); + + for (int i = 0; i < 20; i += 2) { + draw_hex(SCREEN, i, 8, 32 + (i * 4)); + draw_hex(SCREEN, regs[i], 80, 32 + (i * 4)); + + draw_hex(SCREEN, i + 1, 208, 32 + (i * 4)); + draw_hex(SCREEN, regs[i + 1], 280, 32 + (i * 4)); + } + + while(1) + ARM_WFI(); +} + +static const u8 num_font[] = { + 0b00000000, + 0b00011000, + 0b00100100, + 0b00101100, + 0b00110100, + 0b00100100, + 0b00011000, + 0b00000000, // 0 + + 0b00000000, + 0b00011000, + 0b00101000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00111100, + 0b00000000, // 1 + + 0b00000000, + 0b00011000, + 0b00100100, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00111100, + 0b00000000, // 2 + + 0b00000000, + 0b00111000, + 0b00000100, + 0b00011000, + 0b00000100, + 0b00000100, + 0b00111000, + 0b00000000, // 3 + + 0b00000000, + 0b00100100, + 0b00100100, + 0b00111100, + 0b00000100, + 0b00000100, + 0b00000100, + 0b00000000, // 4 + + 0b00000000, + 0b00111100, + 0b00100000, + 0b00111000, + 0b00000100, + 0b00000100, + 0b00111000, + 0b00000000, // 5 + + 0b00000000, + 0b00011100, + 0b00100000, + 0b00111000, + 0b00100100, + 0b00100100, + 0b00011000, + 0b00000000, // 6 + + 0b00000000, + 0b00111100, + 0b00000100, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00010000, + 0b00000000, // 7 + + 0b00000000, + 0b00011000, + 0b00100100, + 0b00011000, + 0b00100100, + 0b00100100, + 0b00011000, + 0b00000000, // 8 + + 0b00000000, + 0b00011000, + 0b00100100, + 0b00011100, + 0b00000100, + 0b00000100, + 0b00111000, + 0b00000000, // 9 + + 0b00000000, + 0b00011000, + 0b00100100, + 0b00111100, + 0b00100100, + 0b00100100, + 0b00100100, + 0b00000000, // A + + 0b00000000, + 0b00111000, + 0b00100100, + 0b00111000, + 0b00100100, + 0b00100100, + 0b00111000, + 0b00000000, // B + + 0b00000000, + 0b00011100, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00011100, + 0b00000000, // C + + 0b00000000, + 0b00110000, + 0b00101000, + 0b00100100, + 0b00100100, + 0b00101000, + 0b00110000, + 0b00000000, // C + + 0b00000000, + 0b00111100, + 0b00100000, + 0b00111100, + 0b00100000, + 0b00100000, + 0b00111100, + 0b00000000, // E + + 0b00000000, + 0b00111100, + 0b00100000, + 0b00111100, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000, // F +}; diff --git a/arm11/source/arm/scu.c b/arm11/source/arm/scu.c index f089d06..75a57ee 100755 --- a/arm11/source/arm/scu.c +++ b/arm11/source/arm/scu.c @@ -1,32 +1,32 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2018-2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#define REG_SCU_CNT (*REG_ARM_PMR(0x00, u32)) -#define REG_SCU_CFG (*REG_ARM_PMR(0x04, u32)) -#define REG_SCU_CPU (*REG_ARM_PMR(0x08, u32)) -#define REG_SCU_INV (*REG_ARM_PMR(0x0C, u32)) - -void SCU_Init(void) -{ - REG_SCU_CNT = 0x1FFE; - REG_SCU_INV = 0xFFFF; - REG_SCU_CNT = 0x3FFF; -} +/* + * This file is part of GodMode9 + * Copyright (C) 2018-2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#define REG_SCU_CNT (*REG_ARM_PMR(0x00, u32)) +#define REG_SCU_CFG (*REG_ARM_PMR(0x04, u32)) +#define REG_SCU_CPU (*REG_ARM_PMR(0x08, u32)) +#define REG_SCU_INV (*REG_ARM_PMR(0x0C, u32)) + +void SCU_Init(void) +{ + REG_SCU_CNT = 0x1FFE; + REG_SCU_INV = 0xFFFF; + REG_SCU_CNT = 0x3FFF; +} diff --git a/arm11/source/arm/scu.h b/arm11/source/arm/scu.h index 250d997..af407a0 100755 --- a/arm11/source/arm/scu.h +++ b/arm11/source/arm/scu.h @@ -1,23 +1,23 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2018-2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -void SCU_Init(void); +/* + * This file is part of GodMode9 + * Copyright (C) 2018-2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +void SCU_Init(void); diff --git a/arm11/source/arm/timer.h b/arm11/source/arm/timer.h index ed6f09c..7491145 100755 --- a/arm11/source/arm/timer.h +++ b/arm11/source/arm/timer.h @@ -30,3 +30,7 @@ #define CLK_MS_TO_TICKS(m) (((BASE_CLKRATE / 1000) * (m)) - 1) void TIMER_WaitTicks(u32 ticks); + +static inline void TIMER_WaitMS(u32 ms) { + TIMER_WaitTicks(CLK_MS_TO_TICKS(ms)); +} diff --git a/arm11/source/hw/codec.c b/arm11/source/hw/codec.c index 656b5a8..5b38a18 100755 --- a/arm11/source/hw/codec.c +++ b/arm11/source/hw/codec.c @@ -1,146 +1,146 @@ -// Somewhat based on xerpi's CODEC driver for Linux -/* - * This file is part of GodMode9 - * Copyright (C) 2017 Sergi Granell, Paul LaMendola - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include - -#include "hw/codec.h" -#include - -#define CPAD_THRESH_X (750) -#define CPAD_THRESH_Y (150) - -/* SPI stuff */ -static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl) -{ - SPI_XferInfo xfers[2]; - - xfers[0].buf = txb; - xfers[0].len = txl; - xfers[0].read = false; - - xfers[1].buf = rxb; - xfers[1].len = rxl; - xfers[1].read = true; - - SPI_DoXfer(SPI_DEV_CODEC, xfers, 2, true); -} - -static void CODEC_RegSelect(u8 reg) -{ - SPI_XferInfo xfer; - u32 cmd; - - cmd = reg << 8; - - xfer.buf = &cmd; - xfer.len = 2; - xfer.read = false; - - SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true); -} - -static u8 CODEC_RegRead(u8 reg) -{ - u32 cmd, ret; - cmd = (reg << 1) | 1; - CODEC_WriteRead(&cmd, 1, &ret, 1); - return ret; -} - -static void CODEC_RegReadBuf(u8 reg, u32 *out, u8 size) -{ - u32 cmd = (reg << 1) | 1; - CODEC_WriteRead(&cmd, 1, out, size); -} - -static void CODEC_RegWrite(u8 reg, u8 val) -{ - SPI_XferInfo xfer; - u32 cmd; - - cmd = (val << 8) | (reg << 1); - - xfer.buf = &cmd; - xfer.len = 2; - xfer.read = false; - - SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true); -} - -static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1) -{ - CODEC_RegWrite(reg, (CODEC_RegRead(reg) & ~mask1) | (mask0 & mask1)); -} - -// elder god magic -void CODEC_Init(void) -{ - CODEC_RegSelect(0x67); - CODEC_RegWrite(0x24, 0x98); - CODEC_RegWrite(0x26, 0x00); - CODEC_RegWrite(0x25, 0x43); - CODEC_RegWrite(0x24, 0x18); - CODEC_RegWrite(0x17, 0x43); - CODEC_RegWrite(0x19, 0x69); - CODEC_RegWrite(0x1B, 0x80); - CODEC_RegWrite(0x27, 0x11); - CODEC_RegWrite(0x26, 0xEC); - CODEC_RegWrite(0x24, 0x18); - CODEC_RegWrite(0x25, 0x53); - - CODEC_RegMask(0x26, 0x80, 0x80); - CODEC_RegMask(0x24, 0x00, 0x80); - CODEC_RegMask(0x25, 0x10, 0x3C); -} - -void CODEC_GetRawData(u32 *buffer) -{ - CODEC_RegSelect(0xFB); - CODEC_RegReadBuf(1, buffer, 0x34); -} - -void CODEC_Get(CODEC_Input *input) -{ - u32 raw_data_buf[0x34 / 4]; - u8 *raw_data = (u8*)raw_data_buf; - s16 cpad_x, cpad_y; - bool ts_pressed; - - CODEC_GetRawData(raw_data_buf); - - cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048; - cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048; - - // X axis is inverted - input->cpad_x = (abs(cpad_x) > CPAD_THRESH_X) ? -cpad_x : 0; - input->cpad_y = (abs(cpad_y) > CPAD_THRESH_Y) ? cpad_y : 0; - - ts_pressed = !(raw_data[0] & BIT(4)); - if (ts_pressed) { - input->ts_x = (raw_data[0] << 8) | raw_data[1]; - input->ts_y = (raw_data[10] << 8) | raw_data[11]; - } else { - input->ts_x = 0xFFFF; - input->ts_y = 0xFFFF; - } -} +// Somewhat based on xerpi's CODEC driver for Linux +/* + * This file is part of GodMode9 + * Copyright (C) 2017 Sergi Granell, Paul LaMendola + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include + +#include "hw/codec.h" +#include + +#define CPAD_THRESH_X (750) +#define CPAD_THRESH_Y (150) + +/* SPI stuff */ +static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl) +{ + SPI_XferInfo xfers[2]; + + xfers[0].buf = txb; + xfers[0].len = txl; + xfers[0].read = false; + + xfers[1].buf = rxb; + xfers[1].len = rxl; + xfers[1].read = true; + + SPI_DoXfer(SPI_DEV_CODEC, xfers, 2, true); +} + +static void CODEC_RegSelect(u8 reg) +{ + SPI_XferInfo xfer; + u32 cmd; + + cmd = reg << 8; + + xfer.buf = &cmd; + xfer.len = 2; + xfer.read = false; + + SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true); +} + +static u8 CODEC_RegRead(u8 reg) +{ + u32 cmd, ret; + cmd = (reg << 1) | 1; + CODEC_WriteRead(&cmd, 1, &ret, 1); + return ret; +} + +static void CODEC_RegReadBuf(u8 reg, u32 *out, u8 size) +{ + u32 cmd = (reg << 1) | 1; + CODEC_WriteRead(&cmd, 1, out, size); +} + +static void CODEC_RegWrite(u8 reg, u8 val) +{ + SPI_XferInfo xfer; + u32 cmd; + + cmd = (val << 8) | (reg << 1); + + xfer.buf = &cmd; + xfer.len = 2; + xfer.read = false; + + SPI_DoXfer(SPI_DEV_CODEC, &xfer, 1, true); +} + +static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1) +{ + CODEC_RegWrite(reg, (CODEC_RegRead(reg) & ~mask1) | (mask0 & mask1)); +} + +// elder god magic +void CODEC_Init(void) +{ + CODEC_RegSelect(0x67); + CODEC_RegWrite(0x24, 0x98); + CODEC_RegWrite(0x26, 0x00); + CODEC_RegWrite(0x25, 0x43); + CODEC_RegWrite(0x24, 0x18); + CODEC_RegWrite(0x17, 0x43); + CODEC_RegWrite(0x19, 0x69); + CODEC_RegWrite(0x1B, 0x80); + CODEC_RegWrite(0x27, 0x11); + CODEC_RegWrite(0x26, 0xEC); + CODEC_RegWrite(0x24, 0x18); + CODEC_RegWrite(0x25, 0x53); + + CODEC_RegMask(0x26, 0x80, 0x80); + CODEC_RegMask(0x24, 0x00, 0x80); + CODEC_RegMask(0x25, 0x10, 0x3C); +} + +void CODEC_GetRawData(u32 *buffer) +{ + CODEC_RegSelect(0xFB); + CODEC_RegReadBuf(1, buffer, 0x34); +} + +void CODEC_Get(CODEC_Input *input) +{ + u32 raw_data_buf[0x34 / 4]; + u8 *raw_data = (u8*)raw_data_buf; + s16 cpad_x, cpad_y; + bool ts_pressed; + + CODEC_GetRawData(raw_data_buf); + + cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048; + cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048; + + // X axis is inverted + input->cpad_x = (abs(cpad_x) > CPAD_THRESH_X) ? -cpad_x : 0; + input->cpad_y = (abs(cpad_y) > CPAD_THRESH_Y) ? cpad_y : 0; + + ts_pressed = !(raw_data[0] & BIT(4)); + if (ts_pressed) { + input->ts_x = (raw_data[0] << 8) | raw_data[1]; + input->ts_y = (raw_data[10] << 8) | raw_data[11]; + } else { + input->ts_x = 0xFFFF; + input->ts_y = 0xFFFF; + } +} diff --git a/arm11/source/hw/codec.h b/arm11/source/hw/codec.h index da5a1fa..f1d75f6 100755 --- a/arm11/source/hw/codec.h +++ b/arm11/source/hw/codec.h @@ -1,32 +1,32 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2017 Sergi Granell, Paul LaMendola - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -typedef struct { - s16 cpad_x, cpad_y; - s16 ts_x, ts_y; -} CODEC_Input; - -void CODEC_Init(void); - -void CODEC_GetRawData(u32 *buffer); -void CODEC_Get(CODEC_Input *input); +/* + * This file is part of GodMode9 + * Copyright (C) 2017 Sergi Granell, Paul LaMendola + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +typedef struct { + s16 cpad_x, cpad_y; + s16 ts_x, ts_y; +} CODEC_Input; + +void CODEC_Init(void); + +void CODEC_GetRawData(u32 *buffer); +void CODEC_Get(CODEC_Input *input); diff --git a/arm11/source/hw/gpio.h b/arm11/source/hw/gpio.h index 706dee1..3b3aa41 100755 --- a/arm11/source/hw/gpio.h +++ b/arm11/source/hw/gpio.h @@ -1,34 +1,34 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2017 derrek, profi200 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#define REG_GPIO ((vu16*)(0x10100000 + 0x47000)) - -static inline void GPIO_setBit(u16 reg, u8 bitNum) -{ - REG_GPIO[reg] |= 1u<. + */ + +#pragma once + +#include + +#define REG_GPIO ((vu16*)(0x10100000 + 0x47000)) + +static inline void GPIO_setBit(u16 reg, u8 bitNum) +{ + REG_GPIO[reg] |= 1u<. */ +#include #include #include #include "arm/timer.h" +#include "hw/i2c.h" #include "hw/mcu.h" #include "hw/gpulcd.h" -/* LCD Configuration Registers */ -#define REG_LCD(x) ((vu32*)(0x10202000 + (x))) -void LCD_SetBrightness(u8 brightness) +static struct { - *REG_LCD(0x240) = brightness; - *REG_LCD(0xA40) = brightness; + 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. + u32 framebufs[2]; // For each screen + u8 doubleBuf[2]; // Top, bottom, 1 = enable. + u16 strides[2]; // Top, bottom + u32 formats[2]; // Top, bottom +} g_gfxState = {0}; + +static void setupDisplayController(u8 lcd); +static void resetLcdsMaybe(void); +static void waitLcdsReady(void); + +static u32 gxModeWidth(unsigned c) { + switch(c) { + case 0: return 4; + case 1: return 3; + default: return 2; + } } -u8 LCD_GetBrightness(void) +unsigned GFX_init(GfxFbFmt mode) { - return *REG_LCD(0x240); + unsigned err = 0; + + REG_CFG11_GPUPROT = 0; + + // Reset + REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E; + waitClks(12); + REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL; + REG_GX_GPU_CLK = 0x100; + REG_GX_PSC_VRAM = 0; + REG_GX_PSC_FILL0_CNT = 0; + REG_GX_PSC_FILL1_CNT = 0; + REG_GX_PPF_CNT = 0; + + // LCD framebuffer setup. + + g_gfxState.strides[0] = 240 * gxModeWidth(mode); + g_gfxState.strides[1] = 240 * gxModeWidth(mode); + + g_gfxState.framebufs[0] = VRAM_TOP_LA; + g_gfxState.framebufs[1] = VRAM_BOT_A; + + g_gfxState.formats[0] = mode | BIT(6) | BIT(9); + g_gfxState.formats[1] = mode | BIT(9); + + setupDisplayController(0); + setupDisplayController(1); + REG_LCD_PDC0_SWAP = 0; // Select framebuf 0. + REG_LCD_PDC1_SWAP = 0; + REG_LCD_PDC0_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E; // Start + REG_LCD_PDC1_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E; + + // LCD reg setup. + REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen + REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen + REG_LCD_PARALLAX_CNT = 0; + REG_LCD_PARALLAX_PWM = 0xA390A39; + REG_LCD_RST = 0; + REG_LCD_UNK00C = 0x10001; + + // Clear used VRAM + REG_GX_PSC_FILL0_S_ADDR = VRAM_TOP_LA >> 3; + REG_GX_PSC_FILL0_E_ADDR = VRAM_END >> 3; + REG_GX_PSC_FILL0_VAL = 0; + REG_GX_PSC_FILL0_CNT = BIT(9) | BIT(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; + + REG_LCD_RST = 1; + REG_LCD_UNK00C = 0; + TIMER_WaitMS(10); + resetLcdsMaybe(); + MCU_controlLCDPower(2u); // Power on LCDs. + if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) __builtin_trap(); + + 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) __builtin_trap(); + g_gfxState.lcdPower = 0x15; // All on. + + // Make sure the fills finished. + REG_LCD_ABL0_FILL = 0; + REG_LCD_ABL1_FILL = 0; + + // GPU stuff. + REG_GX_GPU_CLK = 0x70100; + *((vu32*)0x10400050) = 0x22221200; + *((vu32*)0x10400054) = 0xFF2; + + GFX_setBrightness(0x80, 0x80); + + return err; } -void LCD_Initialize(u8 brightness) +static u16 getLcdIds(void) { - *REG_LCD(0x014) = 1; - *REG_LCD(0x00C) = 0; - TIMER_WaitTicks(CLK_MS_TO_TICKS(10)); + u16 ids; - *REG_LCD(0x240) = brightness; - *REG_LCD(0xA40) = brightness; - *REG_LCD(0x244) = 0x1023E; - *REG_LCD(0xA44) = 0x1023E; + 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; } -void LCD_Deinitialize(void) +static void resetLcdsMaybe(void) { - *REG_LCD(0x244) = 0; - *REG_LCD(0xA44) = 0; - *REG_LCD(0x00C) = 0x10001; - *REG_LCD(0x014) = 0; -} + const u16 ids = getLcdIds(); -/* GPU Control Registers */ -#define REG_GPU_CNT ((vu32*)(0x10141200)) - - -/* GPU DMA */ -#define REG_GPU_PSC(n, x) ((vu32*)(0x10400010 + ((n) * 0x10) + (x))) -#define GPU_PSC_START (0x00) -#define GPU_PSC_END (0x04) -#define GPU_PSC_FILLVAL (0x08) -#define GPU_PSC_CNT (0x0C) - -#define GPUDMA_ADDR(x) ((x) >> 3) -#define PSC_START (BIT(0)) -#define PSC_DONE (BIT(1)) -#define PSC_32BIT (2 << 8) -#define PSC_24BIT (1 << 8) -#define PSC_16BIT (0 << 8) - -void GPU_PSCFill(u32 start, u32 end, u32 fv) -{ - u32 mp; - if (start > end) - return; - - start = GPUDMA_ADDR(start); - end = GPUDMA_ADDR(end); - mp = (start + end) / 2; - - *REG_GPU_PSC(0, GPU_PSC_START) = start; - *REG_GPU_PSC(0, GPU_PSC_END) = mp; - *REG_GPU_PSC(0, GPU_PSC_FILLVAL) = fv; - *REG_GPU_PSC(0, GPU_PSC_CNT) = PSC_START | PSC_32BIT; - - *REG_GPU_PSC(1, GPU_PSC_START) = mp; - *REG_GPU_PSC(1, GPU_PSC_END) = end; - *REG_GPU_PSC(1, GPU_PSC_FILLVAL) = fv; - *REG_GPU_PSC(1, GPU_PSC_CNT) = PSC_START | PSC_32BIT; - - while(!((*REG_GPU_PSC(0, GPU_PSC_CNT) | *REG_GPU_PSC(1, GPU_PSC_CNT)) & PSC_DONE)); -} - -/* GPU Display Registers */ -#define GPU_PDC(n, x) ((vu32*)(0x10400400 + ((n) * 0x100) + x)) -#define PDC_PARALLAX (BIT(5)) -#define PDC_MAINSCREEN (BIT(6)) -#define PDC_FIXSTRIP (BIT(7)) - -void GPU_SetFramebuffers(const u32 *framebuffers) -{ - *GPU_PDC(0, 0x68) = framebuffers[0]; - *GPU_PDC(0, 0x6C) = framebuffers[1]; - *GPU_PDC(0, 0x94) = framebuffers[2]; - *GPU_PDC(0, 0x98) = framebuffers[3]; - *GPU_PDC(1, 0x68) = framebuffers[4]; - *GPU_PDC(1, 0x6C) = framebuffers[5]; - *GPU_PDC(0, 0x78) = 0; - *GPU_PDC(1, 0x78) = 0; -} - -void GPU_SetFramebufferMode(u32 screen, u8 mode) -{ - u32 stride, cfg; - vu32 *fbcfg_reg, *fbstr_reg; - - mode &= 7; - screen &= 1; - cfg = PDC_FIXSTRIP | mode; - if (screen) { - fbcfg_reg = GPU_PDC(1, 0x70); - fbstr_reg = GPU_PDC(1, 0x90); - } else { - fbcfg_reg = GPU_PDC(0, 0x70); - fbstr_reg = GPU_PDC(0, 0x90); - cfg |= PDC_MAINSCREEN; + // Top screen + 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); } - stride = 240; - switch(mode) { - case PDC_RGBA8: - stride *= 4; - break; - case PDC_RGB24: - stride *= 3; - break; - default: - stride *= 2; - break; - } + // Bottom screen + if(ids>>8) I2C_writeReg(I2C_DEV_LCD1, 0xFE, 0xAA); + else I2C_writeReg(I2C_DEV_LCD1, 0x11, 0x10); - *fbcfg_reg = cfg; - *fbstr_reg = stride; + 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 GPU_Init(void) +static void waitLcdsReady(void) { - MCU_PushToLCD(true); + const u16 ids = getLcdIds(); - LCD_Initialize(0x20); + if((ids & 0xFFu) == 0 || (ids>>8) == 0) // Unknown LCD? + { + TIMER_WaitMS(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); - *REG_GPU_CNT = 0x1007F; - *GPU_PDC(0, 0x00) = 0x000001C2; - *GPU_PDC(0, 0x04) = 0x000000D1; - *GPU_PDC(0, 0x08) = 0x000001C1; - *GPU_PDC(0, 0x0C) = 0x000001C1; - *GPU_PDC(0, 0x10) = 0x00000000; - *GPU_PDC(0, 0x14) = 0x000000CF; - *GPU_PDC(0, 0x18) = 0x000000D1; - *GPU_PDC(0, 0x1C) = 0x01C501C1; - *GPU_PDC(0, 0x20) = 0x00010000; - *GPU_PDC(0, 0x24) = 0x0000019D; - *GPU_PDC(0, 0x28) = 0x00000002; - *GPU_PDC(0, 0x2C) = 0x00000192; - *GPU_PDC(0, 0x30) = 0x00000192; - *GPU_PDC(0, 0x34) = 0x00000192; - *GPU_PDC(0, 0x38) = 0x00000001; - *GPU_PDC(0, 0x3C) = 0x00000002; - *GPU_PDC(0, 0x40) = 0x01960192; - *GPU_PDC(0, 0x44) = 0x00000000; - *GPU_PDC(0, 0x48) = 0x00000000; - *GPU_PDC(0, 0x5C) = 0x00F00190; - *GPU_PDC(0, 0x60) = 0x01C100D1; - *GPU_PDC(0, 0x64) = 0x01920002; - *GPU_PDC(0, 0x68) = VRAM_START; - *GPU_PDC(0, 0x6C) = VRAM_START; - *GPU_PDC(0, 0x70) = 0x00080340; - *GPU_PDC(0, 0x74) = 0x00010501; - *GPU_PDC(0, 0x78) = 0x00000000; - *GPU_PDC(0, 0x90) = 0x000003C0; - *GPU_PDC(0, 0x94) = VRAM_START; - *GPU_PDC(0, 0x98) = VRAM_START; - *GPU_PDC(0, 0x9C) = 0x00000000; + if((top>>8) == 1 && (bot>>8) == 1) break; - for (u32 i = 0; i < 256; i++) - *GPU_PDC(0, 0x84) = 0x10101 * i; - - *GPU_PDC(1, 0x00) = 0x000001C2; - *GPU_PDC(1, 0x04) = 0x000000D1; - *GPU_PDC(1, 0x08) = 0x000001C1; - *GPU_PDC(1, 0x0C) = 0x000001C1; - *GPU_PDC(1, 0x10) = 0x000000CD; - *GPU_PDC(1, 0x14) = 0x000000CF; - *GPU_PDC(1, 0x18) = 0x000000D1; - *GPU_PDC(1, 0x1C) = 0x01C501C1; - *GPU_PDC(1, 0x20) = 0x00010000; - *GPU_PDC(1, 0x24) = 0x0000019D; - *GPU_PDC(1, 0x28) = 0x00000052; - *GPU_PDC(1, 0x2C) = 0x00000192; - *GPU_PDC(1, 0x30) = 0x00000192; - *GPU_PDC(1, 0x34) = 0x0000004F; - *GPU_PDC(1, 0x38) = 0x00000050; - *GPU_PDC(1, 0x3C) = 0x00000052; - *GPU_PDC(1, 0x40) = 0x01980194; - *GPU_PDC(1, 0x44) = 0x00000000; - *GPU_PDC(1, 0x48) = 0x00000011; - *GPU_PDC(1, 0x5C) = 0x00F00140; - *GPU_PDC(1, 0x60) = 0x01C100d1; - *GPU_PDC(1, 0x64) = 0x01920052; - *GPU_PDC(1, 0x68) = VRAM_START; - *GPU_PDC(1, 0x6C) = VRAM_START; - *GPU_PDC(1, 0x70) = 0x00080300; - *GPU_PDC(1, 0x74) = 0x00010501; - *GPU_PDC(1, 0x78) = 0x00000000; - *GPU_PDC(1, 0x90) = 0x000003C0; - *GPU_PDC(1, 0x9C) = 0x00000000; - - for (u32 i = 0; i < 256; i++) - *GPU_PDC(1, 0x84) = 0x10101 * i; + TIMER_WaitMS(33); + } while(i++ < 10); + } +} + +void GFX_powerOnBacklights(GfxBlight mask) +{ + g_gfxState.lcdPower |= mask; + + mask <<= 1; + MCU_controlLCDPower(mask); // Power on backlights. + if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) + __builtin_trap(); +} + +void GFX_powerOffBacklights(GfxBlight mask) +{ + g_gfxState.lcdPower &= ~mask; + + MCU_controlLCDPower(mask); // Power off backlights. + if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) + __builtin_trap(); +} + +u8 GFX_getBrightness(void) +{ + return REG_LCD_ABL0_LIGHT; +} + +void GFX_setBrightness(u8 top, u8 bot) +{ + 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 = (u32)top<<24; // Force blackscreen + REG_LCD_ABL1_FILL = (u32)bot<<24; // Force blackscreen +} + +static void setupDisplayController(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)); + + for (unsigned i = 0; i < 0x50/4; i++) + regs[i] = cfg[i]; + + for (unsigned i = 0; i < 0xC/4; i++) + regs[23 + i] = cfg[20 + i]; + + 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] = g_gfxState.framebufs[lcd]; // Framebuffer A first address. + regs[27] = g_gfxState.framebufs[lcd]; // Framebuffer A second address. + regs[37] = g_gfxState.framebufs[lcd]; // Framebuffer B first address. + regs[38] = g_gfxState.framebufs[lcd]; // 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; } diff --git a/arm11/source/hw/gpulcd.h b/arm11/source/hw/gpulcd.h index 5cae87d..d5f3d73 100644 --- a/arm11/source/hw/gpulcd.h +++ b/arm11/source/hw/gpulcd.h @@ -21,21 +21,166 @@ #define VBLANK_INTERRUPT (0x2A) -void LCD_SetBrightness(u8 brightness); -u8 LCD_GetBrightness(void); +enum +{ + PDN_GPU_CNT_RST_REGS = 1u, // And more? + PDN_GPU_CNT_RST_PSC = 1u<<1, // ? + PDN_GPU_CNT_RST_GEOSHADER = 1u<<2, // ? + PDN_GPU_CNT_RST_RASTERIZER = 1u<<3, // ? + PDN_GPU_CNT_RST_PPF = 1u<<4, + PDN_GPU_CNT_RST_PDC = 1u<<5, // ? + PDN_GPU_CNT_RST_PDC2 = 1u<<6, // Maybe pixel pipeline or so? -void LCD_Deinitialize(void); - -void GPU_PSCFill(u32 start, u32 end, u32 fv); - -enum { - PDC_RGBA8 = 0, - PDC_RGB24 = 1, - PDC_RGB565 = 2, - PDC_RGB5A1 = 3, - PDC_RGBA4 = 4, + PDN_GPU_CNT_RST_ALL = (PDN_GPU_CNT_RST_PDC2<<1) - 1 }; -void GPU_SetFramebufferMode(u32 screen, u8 mode); -void GPU_SetFramebuffers(const u32 *framebuffers); -void GPU_Init(void); +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; + +typedef enum +{ + GFX_EVENT_PSC0 = 0u, + GFX_EVENT_PSC1 = 1u, + GFX_EVENT_PDC0 = 2u, + GFX_EVENT_PDC1 = 3u, + GFX_EVENT_PPF = 4u, + GFX_EVENT_P3D = 5u +} GfxEvent; + +typedef enum +{ + GFX_BLIGHT_BOT = 1u<<2, + GFX_BLIGHT_TOP = 1u<<4, + GFX_BLIGHT_BOTH = GFX_BLIGHT_TOP | GFX_BLIGHT_BOT +} GfxBlight; + +#define REG_CFG11_GPUPROT *((vu16*)(0x10140140)) +#define REG_PDN_GPU_CNT *((vu32*)(0x10141200)) +#define PDN_GPU_CNT_CLK_E (1u<<16) +#define PDN_VRAM_CNT_CLK_E (1u) + + + +#define GX_REGS_BASE (0x10400000) +#define REG_GX_GPU_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ? + +// PSC (memory fill) regs. +#define REG_GX_PSC_FILL0_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address +#define REG_GX_PSC_FILL0_E_ADDR *((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_FILL1_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0020)) +#define REG_GX_PSC_FILL1_E_ADDR *((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 REG_GX_PSC_VRAM *((vu32*)(GX_REGS_BASE + 0x0030)) // gsp mudule only changes bit 8-11. +#define REG_GX_PSC_STAT *((vu32*)(GX_REGS_BASE + 0x0034)) + +// PDC0/1 regs see lcd.h. + +// PPF (transfer engine) regs. +#define REG_GX_PPF_IN_ADDR *((vu32*)(GX_REGS_BASE + 0x0C00)) +#define REG_GX_PPF_OUT_ADDR *((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_FlAGS *((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_IRQ_POS *((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 internal) regs. See gpu_regs.h. +#define REG_GX_P3D(reg) *((vu32*)(GX_REGS_BASE + 0x1000 + ((reg) * 4))) + +// LCD/ABL regs. +#define LCD_REGS_BASE (0x10202000) +#define REG_LCD_PARALLAX_CNT *((vu32*)(LCD_REGS_BASE + 0x000)) // Controls PWM for the parallax barrier? +#define REG_LCD_PARALLAX_PWM *((vu32*)(LCD_REGS_BASE + 0x004)) // Frequency/other PWM stuff maybe? +#define REG_LCD_UNK00C *((vu32*)(LCD_REGS_BASE + 0x00C)) // Wtf is "FIX"? +#define REG_LCD_RST *((vu32*)(LCD_REGS_BASE + 0x014)) // Reset active low. + +#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 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)) + + +// Technically these regs belong in gx.h but they are used for LCD configuration so... +// Pitfall warning: The 3DS LCDs are physically rotated 90° CCW. + +// PDC0 (top screen display controller) regs. +#define REG_LCD_PDC0_HTOTAL *((vu32*)(GX_REGS_BASE + 0x400)) +#define REG_LCD_PDC0_VTOTAL *((vu32*)(GX_REGS_BASE + 0x424)) +#define REG_LCD_PDC0_HPOS *((const vu32*)(GX_REGS_BASE + 0x450)) +#define REG_LCD_PDC0_VPOS *((const vu32*)(GX_REGS_BASE + 0x454)) +#define REG_LCD_PDC0_FB_A1 *((vu32*)(GX_REGS_BASE + 0x468)) +#define REG_LCD_PDC0_FB_A2 *((vu32*)(GX_REGS_BASE + 0x46C)) +#define REG_LCD_PDC0_FMT *((vu32*)(GX_REGS_BASE + 0x470)) +#define REG_LCD_PDC0_CNT *((vu32*)(GX_REGS_BASE + 0x474)) +#define REG_LCD_PDC0_SWAP *((vu32*)(GX_REGS_BASE + 0x478)) +#define REG_LCD_PDC0_STAT *((const vu32*)(GX_REGS_BASE + 0x47C)) +#define REG_LCD_PDC0_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x480)) // Gamma table index. +#define REG_LCD_PDC0_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x484)) // Gamma table FIFO. +#define REG_LCD_PDC0_STRIDE *((vu32*)(GX_REGS_BASE + 0x490)) +#define REG_LCD_PDC0_FB_B1 *((vu32*)(GX_REGS_BASE + 0x494)) +#define REG_LCD_PDC0_FB_B2 *((vu32*)(GX_REGS_BASE + 0x498)) + +// PDC1 (bottom screen display controller) regs. +#define REG_LCD_PDC1_HTOTAL *((vu32*)(GX_REGS_BASE + 0x500)) +#define REG_LCD_PDC1_VTOTAL *((vu32*)(GX_REGS_BASE + 0x524)) +#define REG_LCD_PDC1_HPOS *((const vu32*)(GX_REGS_BASE + 0x550)) +#define REG_LCD_PDC1_VPOS *((const vu32*)(GX_REGS_BASE + 0x554)) +#define REG_LCD_PDC1_FB_A1 *((vu32*)(GX_REGS_BASE + 0x568)) +#define REG_LCD_PDC1_FB_A2 *((vu32*)(GX_REGS_BASE + 0x56C)) +#define REG_LCD_PDC1_FMT *((vu32*)(GX_REGS_BASE + 0x570)) +#define REG_LCD_PDC1_CNT *((vu32*)(GX_REGS_BASE + 0x574)) +#define REG_LCD_PDC1_SWAP *((vu32*)(GX_REGS_BASE + 0x578)) +#define REG_LCD_PDC1_STAT *((const vu32*)(GX_REGS_BASE + 0x57C)) +#define REG_LCD_PDC1_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x580)) // Gamma table index. +#define REG_LCD_PDC1_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x584)) // Gamma table FIFO. +#define REG_LCD_PDC1_STRIDE *((vu32*)(GX_REGS_BASE + 0x590)) +#define REG_LCD_PDC1_FB_B1 *((vu32*)(GX_REGS_BASE + 0x594)) +#define REG_LCD_PDC1_FB_B2 *((vu32*)(GX_REGS_BASE + 0x598)) + + +// REG_LCD_PDC_CNT +#define PDC_CNT_E (1u) +#define PDC_CNT_I_MASK_H (1u<<8) // Disables H(Blank?) IRQs. +#define PDC_CNT_I_MASK_V (1u<<9) // Disables VBlank IRQs. +#define PDC_CNT_I_MASK_ERR (1u<<10) // Disables error IRQs. What kind of errors? +#define PDC_CNT_OUT_E (1u<<16) // Output enable? + +// REG_LCD_PDC_SWAP +// Masks +#define PDC_SWAP_NEXT (1u) // Next framebuffer. +#define PDC_SWAP_CUR (1u<<4) // Currently displaying framebuffer? +// Bits +#define PDC_SWAP_RST_FIFO (1u<<8) // Which FIFO? +#define PDC_SWAP_I_H (1u<<16) // H(Blank?) IRQ bit. +#define PDC_SWAP_I_V (1u<<17) // VBlank IRQ bit. +#define PDC_SWAP_I_ERR (1u<<18) // Error IRQ bit? +#define PDC_SWAP_I_ALL (PDC_SWAP_I_ERR | PDC_SWAP_I_V | PDC_SWAP_I_H) + + +unsigned GFX_init(GfxFbFmt mode); +void GFX_setForceBlack(bool top, bool bot); +void GFX_powerOnBacklights(GfxBlight mask); +void GFX_powerOffBacklights(GfxBlight mask); + +u8 GFX_getBrightness(void); +void GFX_setBrightness(u8 top, u8 bot); diff --git a/arm11/source/hw/hid.c b/arm11/source/hw/hid.c index 6cc8505..dd2140d 100755 --- a/arm11/source/hw/hid.c +++ b/arm11/source/hw/hid.c @@ -1,73 +1,73 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include "hw/codec.h" -#include "hw/hid.h" -#include "hw/mcu.h" - -#define REG_HID (~(*(vu16*)(0x10146000)) & BUTTON_ANY) - -static u32 HID_ConvertCPAD(s16 cpad_x, s16 cpad_y) -{ - u32 ret = 0; - - switch(int_sign(cpad_x)) { - default: - break; - case 1: - ret |= BUTTON_RIGHT; - break; - case -1: - ret |= BUTTON_LEFT; - } - - switch(int_sign(cpad_y)) { - default: - break; - case 1: - ret |= BUTTON_UP; - break; - case -1: - ret |= BUTTON_DOWN; - } - - return ret; -} - -u64 HID_GetState(void) -{ - CODEC_Input codec; - u64 ret = 0; - - CODEC_Get(&codec); - - ret = REG_HID | MCU_GetSpecialHID(); - if (!(ret & BUTTON_ARROW)) - ret |= HID_ConvertCPAD(codec.cpad_x, codec.cpad_y); - - if (codec.ts_x <= 0xFFF) - ret |= BUTTON_TOUCH; - - ret |= (((u64)codec.ts_x << 16) | (u64)codec.ts_y) << 32; - - return ret; -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "hw/codec.h" +#include "hw/hid.h" +#include "hw/mcu.h" + +#define REG_HID (~(*(vu16*)(0x10146000)) & BUTTON_ANY) + +static u32 HID_ConvertCPAD(s16 cpad_x, s16 cpad_y) +{ + u32 ret = 0; + + switch(int_sign(cpad_x)) { + default: + break; + case 1: + ret |= BUTTON_RIGHT; + break; + case -1: + ret |= BUTTON_LEFT; + } + + switch(int_sign(cpad_y)) { + default: + break; + case 1: + ret |= BUTTON_UP; + break; + case -1: + ret |= BUTTON_DOWN; + } + + return ret; +} + +u64 HID_GetState(void) +{ + CODEC_Input codec; + u64 ret = 0; + + CODEC_Get(&codec); + + ret = REG_HID | MCU_GetSpecialHID(); + if (!(ret & BUTTON_ARROW)) + ret |= HID_ConvertCPAD(codec.cpad_x, codec.cpad_y); + + if (codec.ts_x <= 0xFFF) + ret |= BUTTON_TOUCH; + + ret |= (((u64)codec.ts_x << 16) | (u64)codec.ts_y) << 32; + + return ret; +} diff --git a/arm11/source/hw/hid.h b/arm11/source/hw/hid.h index d5bcc34..512dae7 100755 --- a/arm11/source/hw/hid.h +++ b/arm11/source/hw/hid.h @@ -1,24 +1,24 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -u64 HID_GetState(void); +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +u64 HID_GetState(void); diff --git a/arm11/source/hw/i2c.h b/arm11/source/hw/i2c.h index 35a5dfc..3315973 100644 --- a/arm11/source/hw/i2c.h +++ b/arm11/source/hw/i2c.h @@ -31,6 +31,9 @@ #define I2C_IRQ_ENABLE (1u<<6) #define I2C_ENABLE (1u<<7) +#define I2C_DEV_LCD0 5 +#define I2C_DEV_LCD1 6 + #define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) @@ -62,3 +65,13 @@ bool I2C_readRegBuf(int devId, u8 regAddr, u8 *out, u32 size); * @return Returns true on success and false on failure. */ bool I2C_writeRegBuf(int devId, u8 regAddr, const u8 *in, u32 size); + +static inline u8 I2C_readReg(int devId, u8 regAddr) { + u8 v; + I2C_readRegBuf(devId, regAddr, &v, 1); + return v; +} + +static inline void I2C_writeReg(int devId, u8 regAddr, u8 v) { + I2C_writeRegBuf(devId, regAddr, &v, 1); +} diff --git a/arm11/source/hw/mcu.c b/arm11/source/hw/mcu.c index d43dbac..e20c500 100755 --- a/arm11/source/hw/mcu.c +++ b/arm11/source/hw/mcu.c @@ -135,12 +135,6 @@ void MCU_ResetLED(void) MCU_SetNotificationLED(0, 0); } -void MCU_PushToLCD(bool enable) -{ - MCU_WriteReg(REG_LCD_STATE, enable ? 0x2A : 0x01); - TIMER_WaitTicks(CLK_MS_TO_TICKS(160)); -} - void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) { u32 ints; @@ -171,13 +165,11 @@ void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) break; case MCU_SHELL_OPEN: - MCU_PushToLCD(true); MCU_UpdateShellState(true); MCU_ResetLED(); break; case MCU_SHELL_CLOSE: - MCU_PushToLCD(false); MCU_UpdateShellState(false); break; @@ -195,7 +187,7 @@ void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) void MCU_Init(void) { - u32 clrpend, mask = 0xFFBF0800; + u32 clrpend, mask = 0; /* set register mask and clear any pending registers */ MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask)); diff --git a/arm11/source/hw/mcu.h b/arm11/source/hw/mcu.h index 797d5f6..c9f67e8 100755 --- a/arm11/source/hw/mcu.h +++ b/arm11/source/hw/mcu.h @@ -1,60 +1,76 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "hw/i2c.h" - -#define MCU_INTERRUPT (0x71) -#define I2C_MCU_DEVICE (3) - -u8 MCU_GetVolumeSlider(void); -u32 MCU_GetSpecialHID(void); - -void MCU_SetNotificationLED(u32 period_ms, u32 color); -void MCU_ResetLED(void); - -void MCU_PushToLCD(bool enable); - -void MCU_HandleInterrupts(u32 irqn); - -void MCU_Init(void); - -static inline u8 MCU_ReadReg(u8 addr) -{ - u8 val; - I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1); - return val; -} - -static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u32 size) -{ - return I2C_readRegBuf(I2C_MCU_DEVICE, addr, buf, size); -} - -static inline bool MCU_WriteReg(u8 addr, u8 val) -{ - return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, &val, 1); -} - -static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u32 size) -{ - return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size); -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include "arm/timer.h" +#include "hw/i2c.h" + +#define MCU_INTERRUPT (0x71) +#define I2C_MCU_DEVICE (3) + +u8 MCU_GetVolumeSlider(void); +u32 MCU_GetSpecialHID(void); + +void MCU_SetNotificationLED(u32 period_ms, u32 color); +void MCU_ResetLED(void); + +void MCU_HandleInterrupts(u32 irqn); + +void MCU_Init(void); + +static inline u8 MCU_ReadReg(u8 addr) +{ + u8 val; + I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1); + return val; +} + +static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u32 size) +{ + return I2C_readRegBuf(I2C_MCU_DEVICE, addr, buf, size); +} + +static inline bool MCU_WriteReg(u8 addr, u8 val) +{ + return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, &val, 1); +} + +static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u32 size) +{ + return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size); +} + +static inline u32 MCU_waitEvents(u32 mask) { + u32 v; + while(1) { + TIMER_WaitMS(10); + MCU_ReadRegBuf(0x10, (u8*)&v, 4); + v &= mask; + if (v) + break; + } + return v; +} + +static inline void MCU_controlLCDPower(u8 bits) +{ + MCU_WriteReg(0x22u, bits); +} diff --git a/arm11/source/hw/nvram.c b/arm11/source/hw/nvram.c index ca8ec06..6792dce 100755 --- a/arm11/source/hw/nvram.c +++ b/arm11/source/hw/nvram.c @@ -1,93 +1,93 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include -#include "hw/nvram.h" - -// returns manuf id, memory type and size -// size = (1 << id[2]) ? -// apparently unreliable on some Sanyo chips? -#define CMD_RDID 0x9F - -#define CMD_READ 0x03 -#define CMD_WREN 0x06 -#define CMD_WRDI 0x04 - -#define CMD_RDSR 0x05 - -#define CMD_DPD 0xB9 // deep power down -#define CMD_RDP 0xAB // release from deep power down - -static u32 NVRAM_SendStatusCommand(u32 cmd, u32 width) -{ - u32 ret; - SPI_XferInfo xfer[2]; - - xfer[0].buf = &cmd; - xfer[0].len = 1; - xfer[0].read = false; - - xfer[1].buf = &ret; - xfer[1].len = width; - xfer[1].read = true; - - ret = 0; - SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true); - return ret; -} - -u32 NVRAM_Status(void) -{ - return NVRAM_SendStatusCommand(CMD_RDSR, 1); -} - -u32 NVRAM_ReadID(void) -{ - return NVRAM_SendStatusCommand(CMD_RDID, 3); -} - -void NVRAM_DeepStandby(void) -{ - NVRAM_SendStatusCommand(CMD_DPD, 0); -} - -void NVRAM_Wakeup(void) -{ - NVRAM_SendStatusCommand(CMD_RDP, 0); -} - -void NVRAM_Read(u32 address, u32 *buffer, u32 len) -{ - SPI_XferInfo xfer[2]; - u32 cmd; - - address &= BIT(24) - 1; - cmd = __builtin_bswap32(address) | CMD_READ; - - xfer[0].buf = &cmd; - xfer[0].len = 4; - xfer[0].read = false; - - xfer[1].buf = buffer; - xfer[1].len = len; - xfer[1].read = true; - - SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true); -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include "hw/nvram.h" + +// returns manuf id, memory type and size +// size = (1 << id[2]) ? +// apparently unreliable on some Sanyo chips? +#define CMD_RDID 0x9F + +#define CMD_READ 0x03 +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 + +#define CMD_RDSR 0x05 + +#define CMD_DPD 0xB9 // deep power down +#define CMD_RDP 0xAB // release from deep power down + +static u32 NVRAM_SendStatusCommand(u32 cmd, u32 width) +{ + u32 ret; + SPI_XferInfo xfer[2]; + + xfer[0].buf = &cmd; + xfer[0].len = 1; + xfer[0].read = false; + + xfer[1].buf = &ret; + xfer[1].len = width; + xfer[1].read = true; + + ret = 0; + SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true); + return ret; +} + +u32 NVRAM_Status(void) +{ + return NVRAM_SendStatusCommand(CMD_RDSR, 1); +} + +u32 NVRAM_ReadID(void) +{ + return NVRAM_SendStatusCommand(CMD_RDID, 3); +} + +void NVRAM_DeepStandby(void) +{ + NVRAM_SendStatusCommand(CMD_DPD, 0); +} + +void NVRAM_Wakeup(void) +{ + NVRAM_SendStatusCommand(CMD_RDP, 0); +} + +void NVRAM_Read(u32 address, u32 *buffer, u32 len) +{ + SPI_XferInfo xfer[2]; + u32 cmd; + + address &= BIT(24) - 1; + cmd = __builtin_bswap32(address) | CMD_READ; + + xfer[0].buf = &cmd; + xfer[0].len = 4; + xfer[0].read = false; + + xfer[1].buf = buffer; + xfer[1].len = len; + xfer[1].read = true; + + SPI_DoXfer(SPI_DEV_NVRAM, xfer, 2, true); +} diff --git a/arm11/source/hw/nvram.h b/arm11/source/hw/nvram.h index 0cdd4ed..3f01c3e 100755 --- a/arm11/source/hw/nvram.h +++ b/arm11/source/hw/nvram.h @@ -1,34 +1,34 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include - -#define NVRAM_SR_WIP BIT(0) // work in progress / busy -#define NVRAM_SR_WEL BIT(1) // write enable latch - -u32 NVRAM_Status(void); -u32 NVRAM_ReadID(void); - -void NVRAM_Read(u32 offset, u32 *buffer, u32 len); - -void NVRAM_DeepStandby(void); -void NVRAM_Wakeup(void); +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include + +#define NVRAM_SR_WIP BIT(0) // work in progress / busy +#define NVRAM_SR_WEL BIT(1) // write enable latch + +u32 NVRAM_Status(void); +u32 NVRAM_ReadID(void); + +void NVRAM_Read(u32 offset, u32 *buffer, u32 len); + +void NVRAM_DeepStandby(void); +void NVRAM_Wakeup(void); diff --git a/arm11/source/main.c b/arm11/source/main.c index 32b1429..3de988b 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -52,7 +52,8 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn) int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2) % countof(brightness_lvls); if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) { prev_bright_lvl = cur_bright_lvl; - LCD_SetBrightness(brightness_lvls[cur_bright_lvl]); + u8 br = brightness_lvls[cur_bright_lvl]; + GFX_setBrightness(br, br); } #endif @@ -98,9 +99,8 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) case PXI_SET_VMODE: { - int mode = args[0] ? PDC_RGB24 : PDC_RGB565; - GPU_SetFramebufferMode(0, mode); - GPU_SetFramebufferMode(1, mode); + int mode = args[0] ? GFX_BGR8 : GFX_RGB565; + GFX_init(mode); ret = 0; break; } @@ -147,10 +147,11 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) case PXI_BRIGHTNESS: { - ret = LCD_GetBrightness(); + s32 newbrightness = (s32)args[0]; + ret = GFX_getBrightness(); #ifndef FIXED_BRIGHTNESS - if ((args[0] > 0) && (args[0] < 0x100)) { - LCD_SetBrightness(args[0]); + if ((newbrightness > 0) && (newbrightness < 0x100)) { + GFX_setBrightness(newbrightness, newbrightness); auto_brightness = false; } else { prev_bright_lvl = -1; @@ -184,6 +185,8 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) PXI_Send(ret); } +extern u32 pdcerr; + void __attribute__((noreturn)) MainLoop(void) { #ifdef FIXED_BRIGHTNESS diff --git a/arm11/source/system/sections.h b/arm11/source/system/sections.h index 1c0bb34..1a93316 100755 --- a/arm11/source/system/sections.h +++ b/arm11/source/system/sections.h @@ -1,35 +1,35 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#define DEF_SECT_(n) extern u32 __##n##_pa, __##n##_va, __##n##_len; -DEF_SECT_(vector) -DEF_SECT_(text) -DEF_SECT_(data) -DEF_SECT_(rodata) -DEF_SECT_(bss) -#undef DEF_SECT_ - -#define SECTION_VA(n) ((u32)&__##n##_va) -#define SECTION_PA(n) ((u32)&__##n##_pa) -#define SECTION_LEN(n) ((u32)&__##n##_len) - -#define SECTION_TRI(n) SECTION_VA(n), SECTION_PA(n), SECTION_LEN(n) +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#define DEF_SECT_(n) extern u32 __##n##_pa, __##n##_va, __##n##_len; +DEF_SECT_(vector) +DEF_SECT_(text) +DEF_SECT_(data) +DEF_SECT_(rodata) +DEF_SECT_(bss) +#undef DEF_SECT_ + +#define SECTION_VA(n) ((u32)&__##n##_va) +#define SECTION_PA(n) ((u32)&__##n##_pa) +#define SECTION_LEN(n) ((u32)&__##n##_len) + +#define SECTION_TRI(n) SECTION_VA(n), SECTION_PA(n), SECTION_LEN(n) diff --git a/arm11/source/system/sys.c b/arm11/source/system/sys.c index a0a6112..ce51239 100755 --- a/arm11/source/system/sys.c +++ b/arm11/source/system/sys.c @@ -108,16 +108,7 @@ void SYS_CoreZeroInit(void) SPI_Init(); CODEC_Init(); - GPU_Init(); - GPU_PSCFill(VRAM_START, VRAM_END, 0); - GPU_SetFramebuffers((u32[]){VRAM_TOP_LA, VRAM_TOP_LB, - VRAM_TOP_RA, VRAM_TOP_RB, - VRAM_BOT_A, VRAM_BOT_B}); - - GPU_SetFramebufferMode(0, PDC_RGB24); - GPU_SetFramebufferMode(1, PDC_RGB24); - - MCU_PushToLCD(true); + GFX_init(GFX_RGB565); } void SYS_CoreInit(void) diff --git a/arm11/source/system/sys.h b/arm11/source/system/sys.h index 2d26110..ada331e 100755 --- a/arm11/source/system/sys.h +++ b/arm11/source/system/sys.h @@ -1,38 +1,38 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -/* - how to run the SYS_Core(Zero){Init,Shutdown} functions: - for init: - - FIRST run CoreZeroInit ONCE - - all cores must run CoreInit ONCE - - for shutdown: - - all non-zero cores must call CoreShutdown - - core zero must call CoreZeroShutdown, then CoreShutdown -*/ - -void SYS_CoreZeroInit(void); -void SYS_CoreInit(void); - -void SYS_CoreZeroShutdown(void); -void __attribute__((noreturn)) SYS_CoreShutdown(void); +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +/* + how to run the SYS_Core(Zero){Init,Shutdown} functions: + for init: + - FIRST run CoreZeroInit ONCE + - all cores must run CoreInit ONCE + + for shutdown: + - all non-zero cores must call CoreShutdown + - core zero must call CoreZeroShutdown, then CoreShutdown +*/ + +void SYS_CoreZeroInit(void); +void SYS_CoreInit(void); + +void SYS_CoreZeroShutdown(void); +void __attribute__((noreturn)) SYS_CoreShutdown(void); diff --git a/arm11/source/system/xalloc.c b/arm11/source/system/xalloc.c index 02a7921..d075352 100755 --- a/arm11/source/system/xalloc.c +++ b/arm11/source/system/xalloc.c @@ -1,37 +1,37 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// super simple watermark allocator for ARM9 <-> ARM11 xfers -// designed to be request once, free never - -#include "system/xalloc.h" - -static char ALIGN(4096) xalloc_buf[XALLOC_BUF_SIZE]; -static size_t mark = 0; - -void *XAlloc(size_t size) -{ // not thread-safe at all - void *ret; - size_t end = size + mark; - if (end >= XALLOC_BUF_SIZE) - return NULL; - - ret = &xalloc_buf[mark]; - mark = end; - return ret; -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// super simple watermark allocator for ARM9 <-> ARM11 xfers +// designed to be request once, free never + +#include "system/xalloc.h" + +static char ALIGN(4096) xalloc_buf[XALLOC_BUF_SIZE]; +static size_t mark = 0; + +void *XAlloc(size_t size) +{ // not thread-safe at all + void *ret; + size_t end = size + mark; + if (end >= XALLOC_BUF_SIZE) + return NULL; + + ret = &xalloc_buf[mark]; + mark = end; + return ret; +} diff --git a/arm11/source/system/xalloc.h b/arm11/source/system/xalloc.h index 02bcd60..de80418 100755 --- a/arm11/source/system/xalloc.h +++ b/arm11/source/system/xalloc.h @@ -1,25 +1,25 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "types.h" - -#define XALLOC_BUF_SIZE (16384) - -void *XAlloc(size_t size); +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "types.h" + +#define XALLOC_BUF_SIZE (16384) + +void *XAlloc(size_t size); diff --git a/arm9/source/game/bps.c b/arm9/source/game/bps.c index fe0be9d..4adf8ed 100644 --- a/arm9/source/game/bps.c +++ b/arm9/source/game/bps.c @@ -1,686 +1,686 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "common.h" -#include "timer.h" -#include "crc32.h" -#include "fs.h" -#include "ui.h" - -#include "hid.h" -#include "bps.h" - -#define BEAT_VLIBUFSZ (8) -#define BEAT_MAXPATH (256) -#define BEAT_FILEBUFSZ (256 * 1024) - -#define BEAT_RANGE(c, i) ((c)->ranges[1][i] - (c)->ranges[0][i]) -#define BEAT_UPDATEDELAYMS (1000 / 4) - -#define BEAT_ABSPOS(c, i) ((c)->foff[i] + (c)->ranges[0][i]) - -#define BEAT_READONLY (FA_READ | FA_OPEN_EXISTING) -#define BEAT_RWCREATE (FA_READ | FA_WRITE | FA_CREATE_ALWAYS) - -static u32 progress_refcnt = 0; -static u64 progress_timer = 0; - -static size_t fs_size(const char *path) -{ - FILINFO fno; - FRESULT res = fvx_stat(path, &fno); - if (res != FR_OK) return 0; - return fno.fsize; -} - -static const char *basepath(const char *path) -{ - const char *ret = path + strlen(path); - while((--ret) > path) { - if (*ret == '/') break; - } - return ret; -} - -/* Possible error codes */ -enum { - BEAT_OK = 0, - BEAT_EOAL, - BEAT_ABORTED, - BEAT_IO_ERROR, - BEAT_OVERFLOW, - BEAT_BADPATCH, - BEAT_BADINPUT, - BEAT_BADOUTPUT, - BEAT_BADCHKSUM, - BEAT_PATCH_EXPECT, - BEAT_OUT_OF_MEMORY, -}; - -/* State machine actions */ -enum { - BPS_SOURCEREAD = 0, - BPS_TARGETREAD = 1, - BPS_SOURCECOPY = 2, - BPS_TARGETCOPY = 3 -}; - -enum { - BPM_CREATEPATH = 0, - BPM_CREATEFILE = 1, - BPM_MODIFYFILE = 2, - BPM_MIRRORFILE = 3 -}; - -/* File handles used within the Beat state */ -enum { - BEAT_PF = 0, // patch file - BEAT_IF, // input file - BEAT_OF, // output file - BEAT_FILENUM, -}; - -static const u8 bps_signature[] = { 'B', 'P', 'S', '1' }; -static const u8 bps_chksumoffs[BEAT_FILENUM] = { - [BEAT_PF] = 4, [BEAT_OF] = 8, [BEAT_IF] = 12, -}; -static const u8 bpm_signature[] = { 'B', 'P', 'M', '1' }; - -/** BEAT STATE STORAGE */ -typedef struct { - u8 *copybuf; - size_t foff[BEAT_FILENUM], eoal_offset; - size_t ranges[2][BEAT_FILENUM]; - u32 ocrc; // Output crc - - union { - struct { // BPS exclusive fields - u32 xocrc; // Expected output crc - size_t source_relative, target_relative; - }; - struct { // BPM exclusive fields - const char *bpm_path, *source_dir, *target_dir; - }; - }; - char processing[BEAT_MAXPATH]; - FIL file[BEAT_FILENUM]; -} BEAT_Context; - -typedef int (*BEAT_Action)(BEAT_Context*, u32); - -static bool BEAT_UpdateProgress(const BEAT_Context *ctx) -{ // only updates progress for the parent patch, so the embedded BPS wont be displayed - u64 tmr; - if (progress_refcnt > 2) bkpt; // nope, bug out - - tmr = timer_msec(progress_timer); - if (CheckButton(BUTTON_B)) return false; // check for an abort situation - if (progress_refcnt != 1) return true; // only show the first level progress - if (tmr < BEAT_UPDATEDELAYMS) return true; // give it some time - - progress_timer = timer_start(); - ShowProgress(ctx->foff[BEAT_PF], BEAT_RANGE(ctx, BEAT_PF), ctx->processing); - return true; -} - -static const char *BEAT_ErrString(int error) -{ // Get an error description string - switch(error) { - case BEAT_OK: return "No error"; - case BEAT_EOAL: return "End of action list"; - case BEAT_ABORTED: return "Aborted by user"; - case BEAT_IO_ERROR: return "Failed to read/write file"; - case BEAT_OVERFLOW: return "Attempted to write beyond end of file"; - case BEAT_BADPATCH: return "Invalid patch file"; - case BEAT_BADINPUT: return "Invalid input file"; - case BEAT_BADOUTPUT: return "Output file checksum mismatch"; - case BEAT_BADCHKSUM: return "File checksum failed"; - case BEAT_PATCH_EXPECT: return "Expected more patch data"; - case BEAT_OUT_OF_MEMORY: return "Out of memory"; - default: return "Unknown error"; - } -} - -static int BEAT_Read(BEAT_Context *ctx, int id, void *out, size_t len, int fwd) -{ // Read up to `len` bytes from the context file `id` to the `out` buffer - UINT br; - FRESULT res; - if ((len + ctx->foff[id]) > BEAT_RANGE(ctx, id)) - return BEAT_OVERFLOW; - - fvx_lseek(&ctx->file[id], BEAT_ABSPOS(ctx, id)); // ALWAYS use the state offset + start range - ctx->foff[id] += len * fwd; - res = fvx_read(&ctx->file[id], out, len, &br); - return (res == FR_OK && br == len) ? BEAT_OK : BEAT_IO_ERROR; -} - -static int BEAT_WriteOut(BEAT_Context *ctx, const u8 *in, size_t len, int fwd) -{ // Write `len` bytes from `in` to BEAT_OF, updates the output CRC - UINT bw; - FRESULT res; - if ((len + ctx->foff[BEAT_OF]) > BEAT_RANGE(ctx, BEAT_OF)) - return BEAT_OVERFLOW; - - // Blindly assume all writes will be done linearly - ctx->ocrc = ~crc32_calculate(~ctx->ocrc, in, len); - fvx_lseek(&ctx->file[BEAT_OF], BEAT_ABSPOS(ctx, BEAT_OF)); - ctx->foff[BEAT_OF] += len * fwd; - res = fvx_write(&ctx->file[BEAT_OF], in, len, &bw); - return (res == FR_OK && bw == len) ? BEAT_OK : BEAT_IO_ERROR; -} - -static void BEAT_SeekOff(BEAT_Context *ctx, int id, ssize_t offset) -{ ctx->foff[id] += offset; } // Seek `offset` bytes forward -static void BEAT_SeekAbs(BEAT_Context *ctx, int id, size_t pos) -{ ctx->foff[id] = pos; } // Seek to absolute position `pos` - -static int BEAT_NextVLI(BEAT_Context *ctx, u32 *vli) -{ // Read the next VLI in the file, update the seek position - int res; - u32 ret = 0; - u32 iter = 0; - u8 vli_rdbuf[BEAT_VLIBUFSZ], *scan = vli_rdbuf; - - res = BEAT_Read(ctx, BEAT_PF, vli_rdbuf, sizeof(vli_rdbuf), 0); - if (res != BEAT_OK) return res; - - while(scan < &vli_rdbuf[sizeof(vli_rdbuf)]) { - u32 val = *(scan++); - ret += (val & 0x7F) << iter; - if (val & 0x80) break; - iter += 7; - ret += (u32)(1ULL << iter); - } - - // Seek forward only by the amount of used bytes - BEAT_SeekOff(ctx, BEAT_PF, scan - vli_rdbuf); - *vli = ret; - return res; -} - -static s32 BEAT_DecodeSigned(u32 val) // Extract the signed number -{ if (val&1) return -(val>>1); else return (val>>1); } - -static int BEAT_RunActions(BEAT_Context *ctx, const BEAT_Action *acts) -{ // Parses an action list and runs commands specified in `acts` - u32 vli, len; - int cmd, res; - - while((res == BEAT_OK) && - (ctx->foff[BEAT_PF] < (BEAT_RANGE(ctx, BEAT_PF) - ctx->eoal_offset))) { - res = BEAT_NextVLI(ctx, &vli); // get next action - cmd = vli & 3; - len = (vli >> 2) + 1; - if (res != BEAT_OK) return res; - - if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; - - res = (acts[cmd])(ctx, len); // Execute next action - if (res != BEAT_OK) return res; // Break on error or user abort - } - - return res; -} - -static void BEAT_ReleaseCTX(BEAT_Context *ctx) -{ // Release any resources associated to the context - free(ctx->copybuf); - for (int i = 0; i < BEAT_FILENUM; i++) { - if (fvx_opened(&ctx->file[i])) fvx_close(&ctx->file[i]); - } - progress_refcnt--; // lol what even are atomics -} - -// BPS Specific functions -/** - Initialize the Beat File Structure - - verifies checksums - - performs further sanity checks - - extracts initial info - - leaves the file ready to begin state machine execution - */ -static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const char *in_path, const char *out_path, size_t start, size_t end, bool do_chksum) -{ - int res; - u8 read_magic[4]; - u32 vli, in_sz, metaend_off; - u32 chksum[BEAT_FILENUM], expected_chksum[BEAT_FILENUM]; - - // Clear stackbuf - memset(ctx, 0, sizeof(*ctx)); - ctx->eoal_offset = 12; - - if (end == 0) { - start = 0; - end = fs_size(bps_path); - } - - if (do_chksum) // get BPS checksum - chksum[BEAT_PF] = crc32_calculate_from_file(bps_path, start, end - start - 4); - - strcpy(ctx->processing, basepath(bps_path)); - - // open all files - fvx_open(&ctx->file[BEAT_PF], bps_path, BEAT_READONLY); - ctx->ranges[0][BEAT_PF] = start; - ctx->ranges[1][BEAT_PF] = end; - - fvx_open(&ctx->file[BEAT_IF], in_path, BEAT_READONLY); - ctx->ranges[0][BEAT_IF] = 0; - ctx->ranges[1][BEAT_IF] = fs_size(in_path); - - res = fvx_open(&ctx->file[BEAT_OF], out_path, BEAT_RWCREATE); - if (res != FR_OK) return BEAT_IO_ERROR; - - // Verify BPS1 header magic - res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1); - if (res != BEAT_OK) return BEAT_IO_ERROR; - res = memcmp(read_magic, bps_signature, sizeof(bps_signature)); - if (res != 0) return BEAT_BADPATCH; - - // Check input size - res = BEAT_NextVLI(ctx, &in_sz); - if (res != BEAT_OK) return res; - if (ctx->ranges[1][BEAT_IF] != in_sz) return BEAT_BADINPUT; - - // Get expected output size - res = BEAT_NextVLI(ctx, &vli); - if (res != BEAT_OK) return res; - ctx->ranges[0][BEAT_OF] = 0; - ctx->ranges[1][BEAT_OF] = vli; - - // Get end of metadata offset - res = BEAT_NextVLI(ctx, &metaend_off); - if (res != BEAT_OK) return res; - metaend_off += ctx->foff[BEAT_PF]; - - // Read checksums from BPS file - for (int i = 0; i < BEAT_FILENUM; i++) { - BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - bps_chksumoffs[i]); - BEAT_Read(ctx, BEAT_PF, &expected_chksum[i], sizeof(u32), 0); - } - - if (do_chksum) { // Verify patch checksum - if (chksum[BEAT_PF] != expected_chksum[BEAT_PF]) return BEAT_BADCHKSUM; - } - - // Initialize output checksums - ctx->ocrc = 0; - ctx->xocrc = expected_chksum[BEAT_OF]; - - // Allocate temporary block copy buffer - ctx->copybuf = malloc(BEAT_FILEBUFSZ); - if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY; - - // Seek back to the start of action stream / end of metadata - BEAT_SeekAbs(ctx, BEAT_PF, metaend_off); - progress_refcnt++; - return BEAT_OK; -} - -static int BPS_InitCTX(BEAT_Context *ctx, const char *bps, const char *in, const char *out) -{ return BPS_InitCTX_Advanced(ctx, bps, in, out, 0, 0, true); } - -/* - Generic helper function to copy from `src_id` to BEAT_OF - Used by SourceRead, TargetRead and CreateFile -*/ -static int BEAT_BlkCopy(BEAT_Context *ctx, int src_id, u32 len) -{ - while(len > 0) { - ssize_t blksz = min(len, BEAT_FILEBUFSZ); - int res = BEAT_Read(ctx, src_id, ctx->copybuf, blksz, 1); - if (res != BEAT_OK) return res; - - res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 1); - if (res != BEAT_OK) return res; - - if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; - - len -= blksz; - } - return BEAT_OK; -} - -static int BPS_SourceRead(BEAT_Context *ctx, u32 len) -{ // This command copies bytes from the source file to the target file - BEAT_SeekAbs(ctx, BEAT_IF, ctx->foff[BEAT_OF]); - return BEAT_BlkCopy(ctx, BEAT_IF, len); -} - -/* - [...] the actual data is not available to the patch applier, - so it is stored directly inside the patch. -*/ -static int BPS_TargetRead(BEAT_Context *ctx, u32 len) -{ - return BEAT_BlkCopy(ctx, BEAT_PF, len); -} - -/* - An offset is supplied to seek the sourceRelativeOffset to the desired - location, and then data is copied from said offset to the target file -*/ -static int BPS_SourceCopy(BEAT_Context *ctx, u32 len) -{ - int res; - u32 vli; - s32 offset; - - res = BEAT_NextVLI(ctx, &vli); - if (res != BEAT_OK) return res; - - offset = BEAT_DecodeSigned(vli); - BEAT_SeekAbs(ctx, BEAT_IF, ctx->source_relative + offset); - ctx->source_relative += offset + len; - - return BEAT_BlkCopy(ctx, BEAT_IF, len); -} - -/* This command treats all of the data that has already been written to the target file as a dictionary */ -static int BPS_TargetCopy(BEAT_Context *ctx, u32 len) -{ // the black sheep of the family, needs special care - int res; - s32 offset; - u32 out_off, rel_off, vli; - - res = BEAT_NextVLI(ctx, &vli); - if (res != BEAT_OK) return res; - - offset = BEAT_DecodeSigned(vli); - out_off = ctx->foff[BEAT_OF]; - rel_off = ctx->target_relative + offset; - if (rel_off > out_off) return BEAT_BADPATCH; // Illegal - - while(len != 0) { - u8 *remfill; - ssize_t blksz, distance, remainder; - - blksz = min(len, BEAT_FILEBUFSZ); - distance = min((ssize_t)(out_off - rel_off), blksz); - - BEAT_SeekAbs(ctx, BEAT_OF, rel_off); - res = BEAT_Read(ctx, BEAT_OF, ctx->copybuf, distance, 0); - if (res != BEAT_OK) return res; - - remfill = ctx->copybuf + distance; - remainder = blksz - distance; - while(remainder > 0) { // fill the buffer with repeats - ssize_t remblk = min(distance, remainder); - memcpy(remfill, ctx->copybuf, remblk); - remfill += remblk; - remainder -= remblk; - } - - BEAT_SeekAbs(ctx, BEAT_OF, out_off); - res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 0); - if (res != BEAT_OK) return res; - - if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; - rel_off += blksz; - out_off += blksz; - len -= blksz; - } - - BEAT_SeekAbs(ctx, BEAT_OF, out_off); - ctx->target_relative = rel_off; - return BEAT_OK; -} - -static int BPS_RunActions(BEAT_Context *ctx) -{ - static const BEAT_Action BPS_Actions[] = { // BPS action handlers - [BPS_SOURCEREAD] = BPS_SourceRead, - [BPS_TARGETREAD] = BPS_TargetRead, - [BPS_SOURCECOPY] = BPS_SourceCopy, - [BPS_TARGETCOPY] = BPS_TargetCopy - }; - int res = BEAT_RunActions(ctx, BPS_Actions); - if (res == BEAT_ABORTED) return BEAT_ABORTED; - if (res == BEAT_EOAL) // Verify hashes - return (ctx->ocrc == ctx->xocrc) ? BEAT_OK : BEAT_BADOUTPUT; - return res; // some kind of error -} - -/*********************** - BPM Specific functions -***********************/ -static int BPM_OpenFile(BEAT_Context *ctx, int id, const char *path, size_t max_sz) -{ - FRESULT res; - - if (fvx_opened(&ctx->file[id])) fvx_close(&ctx->file[id]); - res = fvx_open(&ctx->file[id], path, max_sz ? BEAT_RWCREATE : BEAT_READONLY); - if (res != FR_OK) return BEAT_IO_ERROR; - - ctx->ranges[0][id] = 0; - if (max_sz > 0) { - ctx->ranges[1][id] = max_sz; - } else { - ctx->ranges[1][id] = f_size(&ctx->file[id]); - } - - // if a new file is opened it makes no sense to keep the old CRC - // a single outfile wont be created from more than one infile (& patch) - ctx->ocrc = 0; - ctx->foff[id] = 0; - return BEAT_OK; -} - -static int BPM_InitCTX(BEAT_Context *ctx, const char *bpm_path, const char *src_dir, const char *dst_dir) -{ - int res; - u32 metaend_off; - u8 read_magic[4]; - u32 chksum, expected_chksum; - - memset(ctx, 0, sizeof(*ctx)); - - ctx->bpm_path = bpm_path; - ctx->source_dir = src_dir; - ctx->target_dir = dst_dir; - ctx->eoal_offset = 4; - - chksum = crc32_calculate_from_file(bpm_path, 0, fs_size(bpm_path) - 4); - res = BPM_OpenFile(ctx, BEAT_PF, bpm_path, 0); - if (res != BEAT_OK) return res; - res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1); - if (res != BEAT_OK) return res; - res = memcmp(read_magic, bpm_signature, sizeof(bpm_signature)); - if (res != 0) return BEAT_BADPATCH; - - // Get end of metadata offset - res = BEAT_NextVLI(ctx, &metaend_off); - if (res != BEAT_OK) return res; - metaend_off += ctx->foff[BEAT_PF]; - - // Read checksums from BPS file - BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - 4); - res = BEAT_Read(ctx, BEAT_PF, &expected_chksum, sizeof(u32), 0); - if (res != BEAT_OK) return res; - if (expected_chksum != chksum) return BEAT_BADCHKSUM; - - // Allocate temporary block copy buffer - ctx->copybuf = malloc(BEAT_FILEBUFSZ); - if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY; - - // Seek back to the start of action stream / end of metadata - BEAT_SeekAbs(ctx, BEAT_PF, metaend_off); - progress_refcnt++; - return BEAT_OK; -} - -static int BPM_NextPath(BEAT_Context *ctx, char *out, int name_len) -{ - if (name_len >= BEAT_MAXPATH) return BEAT_BADPATCH; - int res = BEAT_Read(ctx, BEAT_PF, out, name_len, 1); - out[name_len] = '\0'; - if (res == BEAT_OK) { - out[name_len] = '\0'; // make sure the buffer ends with a zero char - strcpy(ctx->processing, out); - } - return res; -} - -static int BPM_MakeRelativePaths(BEAT_Context *ctx, char *src, char *dst, int name_len) -{ - char name[BEAT_MAXPATH]; - int res = BPM_NextPath(ctx, name, name_len); - if (res != BEAT_OK) return res; - if (src != NULL) - if (snprintf(src, BEAT_MAXPATH, "%s/%s", ctx->source_dir, name) >= BEAT_MAXPATH) return BEAT_BADPATCH; - if (dst != NULL) - if (snprintf(dst, BEAT_MAXPATH, "%s/%s", ctx->target_dir, name) >= BEAT_MAXPATH) return BEAT_BADPATCH; - return res; -} - -static int BPM_CreatePath(BEAT_Context *ctx, u32 name_len) -{ // Create a directory - char path[BEAT_MAXPATH]; - int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len); - if (res != BEAT_OK) return res; - - res = fvx_mkdir(path); - if (res != FR_OK && res != FR_EXIST) return BEAT_IO_ERROR; - return BEAT_OK; -} - -static int BPM_CreateFile(BEAT_Context *ctx, u32 name_len) -{ // Create a file and fill it with data provided in the BPM - u32 file_sz; - u32 checksum; - char path[BEAT_MAXPATH]; - - int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len); - if (res != BEAT_OK) return res; - - res = BEAT_NextVLI(ctx, &file_sz); // get new file size - if (res != BEAT_OK) return res; - res = BPM_OpenFile(ctx, BEAT_OF, path, file_sz); // open file as RW - if (res != BEAT_OK) return res; - res = BEAT_BlkCopy(ctx, BEAT_PF, file_sz); // copy data to new file - if (res != BEAT_OK) return res; - - res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1); - if (res != BEAT_OK) return res; - if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // get and check CRC32 - return BEAT_OK; -} - -static int BPM_ModifyFile(BEAT_Context *ctx, u32 name_len) -{ // Apply a BPS patch - u32 origin, bps_sz; - BEAT_Context bps_context; - char src[BEAT_MAXPATH], dst[BEAT_MAXPATH]; - - int res = BPM_MakeRelativePaths(ctx, src, dst, name_len); - if (res != BEAT_OK) return res; - - res = BEAT_NextVLI(ctx, &origin); // get dummy(?) origin value - if (res != BEAT_OK) return res; - res = BEAT_NextVLI(ctx, &bps_sz); // get embedded BPS size - if (res != BEAT_OK) return res; - - res = BPS_InitCTX_Advanced( - &bps_context, ctx->bpm_path, src, dst, - ctx->foff[BEAT_PF], ctx->foff[BEAT_PF] + bps_sz, - false - ); // create a BPS context using the current ranges - if (res == BEAT_OK) res = BPS_RunActions(&bps_context); // run if OK - BEAT_ReleaseCTX(&bps_context); - if (res != BEAT_OK) return res; // break off if there was an error - - BEAT_SeekOff(ctx, BEAT_PF, bps_sz); // advance beyond the BPS - return BEAT_OK; -} - -static int BPM_MirrorFile(BEAT_Context *ctx, u32 name_len) -{ // Copy a file from source to target without any modifications - u32 origin; - u32 checksum; - char src[BEAT_MAXPATH], dst[BEAT_MAXPATH]; - - int res = BPM_MakeRelativePaths(ctx, src, dst, name_len); - if (res != BEAT_OK) return res; - - // open source and destination files, read the origin dummy - res = BPM_OpenFile(ctx, BEAT_IF, src, 0); - if (res != BEAT_OK) return res; - res = BPM_OpenFile(ctx, BEAT_OF, dst, ctx->ranges[1][BEAT_IF]); - if (res != BEAT_OK) return res; - res = BEAT_NextVLI(ctx, &origin); - if (res != BEAT_OK) return res; - - // copy straight from source to destination - res = BEAT_BlkCopy(ctx, BEAT_IF, ctx->ranges[1][BEAT_IF]); - if (res != BEAT_OK) return res; - - res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1); - if (res != BEAT_OK) return res; - if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // verify checksum - return BEAT_OK; -} - -static int BPM_RunActions(BEAT_Context *ctx) -{ - static const BEAT_Action BPM_Actions[] = { // BPM Action handlers - [BPM_CREATEPATH] = BPM_CreatePath, - [BPM_CREATEFILE] = BPM_CreateFile, - [BPM_MODIFYFILE] = BPM_ModifyFile, - [BPM_MIRRORFILE] = BPM_MirrorFile - }; - int res = BEAT_RunActions(ctx, BPM_Actions); - if (res == BEAT_ABORTED) return BEAT_ABORTED; - if (res == BEAT_EOAL) return BEAT_OK; - return res; -} - -static int BEAT_Run(const char *p, const char *s, const char *d, bool bpm) -{ - int res; - BEAT_Context ctx; - - progress_timer = timer_start(); - res = (bpm ? BPM_InitCTX : BPS_InitCTX)(&ctx, p, s, d); - if (res != BEAT_OK) { - ShowPrompt(false, "Failed to initialize %s file:\n%s", - bpm ? "BPM" : "BPS", BEAT_ErrString(res)); - } else { - res = (bpm ? BPM_RunActions : BPS_RunActions)(&ctx); - switch(res) { - case BEAT_OK: - ShowPrompt(false, "Patch successfully applied"); - break; - case BEAT_ABORTED: - ShowPrompt(false, "Patching aborted by user"); - break; - default: - ShowPrompt(false, "Failed to run patch:\n%s", BEAT_ErrString(res)); - break; - } - } - BEAT_ReleaseCTX(&ctx); - return (res == BEAT_OK) ? 0 : 1; -} - -int ApplyBPSPatch(const char* modifyName, const char* sourceName, const char* targetName) -{ return BEAT_Run(modifyName, sourceName, targetName, false); } -int ApplyBPMPatch(const char* patchName, const char* sourcePath, const char* targetPath) -{ return BEAT_Run(patchName, sourcePath, targetPath, true); } +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "common.h" +#include "timer.h" +#include "crc32.h" +#include "fs.h" +#include "ui.h" + +#include "hid.h" +#include "bps.h" + +#define BEAT_VLIBUFSZ (8) +#define BEAT_MAXPATH (256) +#define BEAT_FILEBUFSZ (256 * 1024) + +#define BEAT_RANGE(c, i) ((c)->ranges[1][i] - (c)->ranges[0][i]) +#define BEAT_UPDATEDELAYMS (1000 / 4) + +#define BEAT_ABSPOS(c, i) ((c)->foff[i] + (c)->ranges[0][i]) + +#define BEAT_READONLY (FA_READ | FA_OPEN_EXISTING) +#define BEAT_RWCREATE (FA_READ | FA_WRITE | FA_CREATE_ALWAYS) + +static u32 progress_refcnt = 0; +static u64 progress_timer = 0; + +static size_t fs_size(const char *path) +{ + FILINFO fno; + FRESULT res = fvx_stat(path, &fno); + if (res != FR_OK) return 0; + return fno.fsize; +} + +static const char *basepath(const char *path) +{ + const char *ret = path + strlen(path); + while((--ret) > path) { + if (*ret == '/') break; + } + return ret; +} + +/* Possible error codes */ +enum { + BEAT_OK = 0, + BEAT_EOAL, + BEAT_ABORTED, + BEAT_IO_ERROR, + BEAT_OVERFLOW, + BEAT_BADPATCH, + BEAT_BADINPUT, + BEAT_BADOUTPUT, + BEAT_BADCHKSUM, + BEAT_PATCH_EXPECT, + BEAT_OUT_OF_MEMORY, +}; + +/* State machine actions */ +enum { + BPS_SOURCEREAD = 0, + BPS_TARGETREAD = 1, + BPS_SOURCECOPY = 2, + BPS_TARGETCOPY = 3 +}; + +enum { + BPM_CREATEPATH = 0, + BPM_CREATEFILE = 1, + BPM_MODIFYFILE = 2, + BPM_MIRRORFILE = 3 +}; + +/* File handles used within the Beat state */ +enum { + BEAT_PF = 0, // patch file + BEAT_IF, // input file + BEAT_OF, // output file + BEAT_FILENUM, +}; + +static const u8 bps_signature[] = { 'B', 'P', 'S', '1' }; +static const u8 bps_chksumoffs[BEAT_FILENUM] = { + [BEAT_PF] = 4, [BEAT_OF] = 8, [BEAT_IF] = 12, +}; +static const u8 bpm_signature[] = { 'B', 'P', 'M', '1' }; + +/** BEAT STATE STORAGE */ +typedef struct { + u8 *copybuf; + size_t foff[BEAT_FILENUM], eoal_offset; + size_t ranges[2][BEAT_FILENUM]; + u32 ocrc; // Output crc + + union { + struct { // BPS exclusive fields + u32 xocrc; // Expected output crc + size_t source_relative, target_relative; + }; + struct { // BPM exclusive fields + const char *bpm_path, *source_dir, *target_dir; + }; + }; + char processing[BEAT_MAXPATH]; + FIL file[BEAT_FILENUM]; +} BEAT_Context; + +typedef int (*BEAT_Action)(BEAT_Context*, u32); + +static bool BEAT_UpdateProgress(const BEAT_Context *ctx) +{ // only updates progress for the parent patch, so the embedded BPS wont be displayed + u64 tmr; + if (progress_refcnt > 2) bkpt; // nope, bug out + + tmr = timer_msec(progress_timer); + if (CheckButton(BUTTON_B)) return false; // check for an abort situation + if (progress_refcnt != 1) return true; // only show the first level progress + if (tmr < BEAT_UPDATEDELAYMS) return true; // give it some time + + progress_timer = timer_start(); + ShowProgress(ctx->foff[BEAT_PF], BEAT_RANGE(ctx, BEAT_PF), ctx->processing); + return true; +} + +static const char *BEAT_ErrString(int error) +{ // Get an error description string + switch(error) { + case BEAT_OK: return "No error"; + case BEAT_EOAL: return "End of action list"; + case BEAT_ABORTED: return "Aborted by user"; + case BEAT_IO_ERROR: return "Failed to read/write file"; + case BEAT_OVERFLOW: return "Attempted to write beyond end of file"; + case BEAT_BADPATCH: return "Invalid patch file"; + case BEAT_BADINPUT: return "Invalid input file"; + case BEAT_BADOUTPUT: return "Output file checksum mismatch"; + case BEAT_BADCHKSUM: return "File checksum failed"; + case BEAT_PATCH_EXPECT: return "Expected more patch data"; + case BEAT_OUT_OF_MEMORY: return "Out of memory"; + default: return "Unknown error"; + } +} + +static int BEAT_Read(BEAT_Context *ctx, int id, void *out, size_t len, int fwd) +{ // Read up to `len` bytes from the context file `id` to the `out` buffer + UINT br; + FRESULT res; + if ((len + ctx->foff[id]) > BEAT_RANGE(ctx, id)) + return BEAT_OVERFLOW; + + fvx_lseek(&ctx->file[id], BEAT_ABSPOS(ctx, id)); // ALWAYS use the state offset + start range + ctx->foff[id] += len * fwd; + res = fvx_read(&ctx->file[id], out, len, &br); + return (res == FR_OK && br == len) ? BEAT_OK : BEAT_IO_ERROR; +} + +static int BEAT_WriteOut(BEAT_Context *ctx, const u8 *in, size_t len, int fwd) +{ // Write `len` bytes from `in` to BEAT_OF, updates the output CRC + UINT bw; + FRESULT res; + if ((len + ctx->foff[BEAT_OF]) > BEAT_RANGE(ctx, BEAT_OF)) + return BEAT_OVERFLOW; + + // Blindly assume all writes will be done linearly + ctx->ocrc = ~crc32_calculate(~ctx->ocrc, in, len); + fvx_lseek(&ctx->file[BEAT_OF], BEAT_ABSPOS(ctx, BEAT_OF)); + ctx->foff[BEAT_OF] += len * fwd; + res = fvx_write(&ctx->file[BEAT_OF], in, len, &bw); + return (res == FR_OK && bw == len) ? BEAT_OK : BEAT_IO_ERROR; +} + +static void BEAT_SeekOff(BEAT_Context *ctx, int id, ssize_t offset) +{ ctx->foff[id] += offset; } // Seek `offset` bytes forward +static void BEAT_SeekAbs(BEAT_Context *ctx, int id, size_t pos) +{ ctx->foff[id] = pos; } // Seek to absolute position `pos` + +static int BEAT_NextVLI(BEAT_Context *ctx, u32 *vli) +{ // Read the next VLI in the file, update the seek position + int res; + u32 ret = 0; + u32 iter = 0; + u8 vli_rdbuf[BEAT_VLIBUFSZ], *scan = vli_rdbuf; + + res = BEAT_Read(ctx, BEAT_PF, vli_rdbuf, sizeof(vli_rdbuf), 0); + if (res != BEAT_OK) return res; + + while(scan < &vli_rdbuf[sizeof(vli_rdbuf)]) { + u32 val = *(scan++); + ret += (val & 0x7F) << iter; + if (val & 0x80) break; + iter += 7; + ret += (u32)(1ULL << iter); + } + + // Seek forward only by the amount of used bytes + BEAT_SeekOff(ctx, BEAT_PF, scan - vli_rdbuf); + *vli = ret; + return res; +} + +static s32 BEAT_DecodeSigned(u32 val) // Extract the signed number +{ if (val&1) return -(val>>1); else return (val>>1); } + +static int BEAT_RunActions(BEAT_Context *ctx, const BEAT_Action *acts) +{ // Parses an action list and runs commands specified in `acts` + u32 vli, len; + int cmd, res; + + while((res == BEAT_OK) && + (ctx->foff[BEAT_PF] < (BEAT_RANGE(ctx, BEAT_PF) - ctx->eoal_offset))) { + res = BEAT_NextVLI(ctx, &vli); // get next action + cmd = vli & 3; + len = (vli >> 2) + 1; + if (res != BEAT_OK) return res; + + if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; + + res = (acts[cmd])(ctx, len); // Execute next action + if (res != BEAT_OK) return res; // Break on error or user abort + } + + return res; +} + +static void BEAT_ReleaseCTX(BEAT_Context *ctx) +{ // Release any resources associated to the context + free(ctx->copybuf); + for (int i = 0; i < BEAT_FILENUM; i++) { + if (fvx_opened(&ctx->file[i])) fvx_close(&ctx->file[i]); + } + progress_refcnt--; // lol what even are atomics +} + +// BPS Specific functions +/** + Initialize the Beat File Structure + - verifies checksums + - performs further sanity checks + - extracts initial info + - leaves the file ready to begin state machine execution + */ +static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const char *in_path, const char *out_path, size_t start, size_t end, bool do_chksum) +{ + int res; + u8 read_magic[4]; + u32 vli, in_sz, metaend_off; + u32 chksum[BEAT_FILENUM], expected_chksum[BEAT_FILENUM]; + + // Clear stackbuf + memset(ctx, 0, sizeof(*ctx)); + ctx->eoal_offset = 12; + + if (end == 0) { + start = 0; + end = fs_size(bps_path); + } + + if (do_chksum) // get BPS checksum + chksum[BEAT_PF] = crc32_calculate_from_file(bps_path, start, end - start - 4); + + strcpy(ctx->processing, basepath(bps_path)); + + // open all files + fvx_open(&ctx->file[BEAT_PF], bps_path, BEAT_READONLY); + ctx->ranges[0][BEAT_PF] = start; + ctx->ranges[1][BEAT_PF] = end; + + fvx_open(&ctx->file[BEAT_IF], in_path, BEAT_READONLY); + ctx->ranges[0][BEAT_IF] = 0; + ctx->ranges[1][BEAT_IF] = fs_size(in_path); + + res = fvx_open(&ctx->file[BEAT_OF], out_path, BEAT_RWCREATE); + if (res != FR_OK) return BEAT_IO_ERROR; + + // Verify BPS1 header magic + res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1); + if (res != BEAT_OK) return BEAT_IO_ERROR; + res = memcmp(read_magic, bps_signature, sizeof(bps_signature)); + if (res != 0) return BEAT_BADPATCH; + + // Check input size + res = BEAT_NextVLI(ctx, &in_sz); + if (res != BEAT_OK) return res; + if (ctx->ranges[1][BEAT_IF] != in_sz) return BEAT_BADINPUT; + + // Get expected output size + res = BEAT_NextVLI(ctx, &vli); + if (res != BEAT_OK) return res; + ctx->ranges[0][BEAT_OF] = 0; + ctx->ranges[1][BEAT_OF] = vli; + + // Get end of metadata offset + res = BEAT_NextVLI(ctx, &metaend_off); + if (res != BEAT_OK) return res; + metaend_off += ctx->foff[BEAT_PF]; + + // Read checksums from BPS file + for (int i = 0; i < BEAT_FILENUM; i++) { + BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - bps_chksumoffs[i]); + BEAT_Read(ctx, BEAT_PF, &expected_chksum[i], sizeof(u32), 0); + } + + if (do_chksum) { // Verify patch checksum + if (chksum[BEAT_PF] != expected_chksum[BEAT_PF]) return BEAT_BADCHKSUM; + } + + // Initialize output checksums + ctx->ocrc = 0; + ctx->xocrc = expected_chksum[BEAT_OF]; + + // Allocate temporary block copy buffer + ctx->copybuf = malloc(BEAT_FILEBUFSZ); + if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY; + + // Seek back to the start of action stream / end of metadata + BEAT_SeekAbs(ctx, BEAT_PF, metaend_off); + progress_refcnt++; + return BEAT_OK; +} + +static int BPS_InitCTX(BEAT_Context *ctx, const char *bps, const char *in, const char *out) +{ return BPS_InitCTX_Advanced(ctx, bps, in, out, 0, 0, true); } + +/* + Generic helper function to copy from `src_id` to BEAT_OF + Used by SourceRead, TargetRead and CreateFile +*/ +static int BEAT_BlkCopy(BEAT_Context *ctx, int src_id, u32 len) +{ + while(len > 0) { + ssize_t blksz = min(len, BEAT_FILEBUFSZ); + int res = BEAT_Read(ctx, src_id, ctx->copybuf, blksz, 1); + if (res != BEAT_OK) return res; + + res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 1); + if (res != BEAT_OK) return res; + + if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; + + len -= blksz; + } + return BEAT_OK; +} + +static int BPS_SourceRead(BEAT_Context *ctx, u32 len) +{ // This command copies bytes from the source file to the target file + BEAT_SeekAbs(ctx, BEAT_IF, ctx->foff[BEAT_OF]); + return BEAT_BlkCopy(ctx, BEAT_IF, len); +} + +/* + [...] the actual data is not available to the patch applier, + so it is stored directly inside the patch. +*/ +static int BPS_TargetRead(BEAT_Context *ctx, u32 len) +{ + return BEAT_BlkCopy(ctx, BEAT_PF, len); +} + +/* + An offset is supplied to seek the sourceRelativeOffset to the desired + location, and then data is copied from said offset to the target file +*/ +static int BPS_SourceCopy(BEAT_Context *ctx, u32 len) +{ + int res; + u32 vli; + s32 offset; + + res = BEAT_NextVLI(ctx, &vli); + if (res != BEAT_OK) return res; + + offset = BEAT_DecodeSigned(vli); + BEAT_SeekAbs(ctx, BEAT_IF, ctx->source_relative + offset); + ctx->source_relative += offset + len; + + return BEAT_BlkCopy(ctx, BEAT_IF, len); +} + +/* This command treats all of the data that has already been written to the target file as a dictionary */ +static int BPS_TargetCopy(BEAT_Context *ctx, u32 len) +{ // the black sheep of the family, needs special care + int res; + s32 offset; + u32 out_off, rel_off, vli; + + res = BEAT_NextVLI(ctx, &vli); + if (res != BEAT_OK) return res; + + offset = BEAT_DecodeSigned(vli); + out_off = ctx->foff[BEAT_OF]; + rel_off = ctx->target_relative + offset; + if (rel_off > out_off) return BEAT_BADPATCH; // Illegal + + while(len != 0) { + u8 *remfill; + ssize_t blksz, distance, remainder; + + blksz = min(len, BEAT_FILEBUFSZ); + distance = min((ssize_t)(out_off - rel_off), blksz); + + BEAT_SeekAbs(ctx, BEAT_OF, rel_off); + res = BEAT_Read(ctx, BEAT_OF, ctx->copybuf, distance, 0); + if (res != BEAT_OK) return res; + + remfill = ctx->copybuf + distance; + remainder = blksz - distance; + while(remainder > 0) { // fill the buffer with repeats + ssize_t remblk = min(distance, remainder); + memcpy(remfill, ctx->copybuf, remblk); + remfill += remblk; + remainder -= remblk; + } + + BEAT_SeekAbs(ctx, BEAT_OF, out_off); + res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 0); + if (res != BEAT_OK) return res; + + if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED; + rel_off += blksz; + out_off += blksz; + len -= blksz; + } + + BEAT_SeekAbs(ctx, BEAT_OF, out_off); + ctx->target_relative = rel_off; + return BEAT_OK; +} + +static int BPS_RunActions(BEAT_Context *ctx) +{ + static const BEAT_Action BPS_Actions[] = { // BPS action handlers + [BPS_SOURCEREAD] = BPS_SourceRead, + [BPS_TARGETREAD] = BPS_TargetRead, + [BPS_SOURCECOPY] = BPS_SourceCopy, + [BPS_TARGETCOPY] = BPS_TargetCopy + }; + int res = BEAT_RunActions(ctx, BPS_Actions); + if (res == BEAT_ABORTED) return BEAT_ABORTED; + if (res == BEAT_EOAL) // Verify hashes + return (ctx->ocrc == ctx->xocrc) ? BEAT_OK : BEAT_BADOUTPUT; + return res; // some kind of error +} + +/*********************** + BPM Specific functions +***********************/ +static int BPM_OpenFile(BEAT_Context *ctx, int id, const char *path, size_t max_sz) +{ + FRESULT res; + + if (fvx_opened(&ctx->file[id])) fvx_close(&ctx->file[id]); + res = fvx_open(&ctx->file[id], path, max_sz ? BEAT_RWCREATE : BEAT_READONLY); + if (res != FR_OK) return BEAT_IO_ERROR; + + ctx->ranges[0][id] = 0; + if (max_sz > 0) { + ctx->ranges[1][id] = max_sz; + } else { + ctx->ranges[1][id] = f_size(&ctx->file[id]); + } + + // if a new file is opened it makes no sense to keep the old CRC + // a single outfile wont be created from more than one infile (& patch) + ctx->ocrc = 0; + ctx->foff[id] = 0; + return BEAT_OK; +} + +static int BPM_InitCTX(BEAT_Context *ctx, const char *bpm_path, const char *src_dir, const char *dst_dir) +{ + int res; + u32 metaend_off; + u8 read_magic[4]; + u32 chksum, expected_chksum; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->bpm_path = bpm_path; + ctx->source_dir = src_dir; + ctx->target_dir = dst_dir; + ctx->eoal_offset = 4; + + chksum = crc32_calculate_from_file(bpm_path, 0, fs_size(bpm_path) - 4); + res = BPM_OpenFile(ctx, BEAT_PF, bpm_path, 0); + if (res != BEAT_OK) return res; + res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1); + if (res != BEAT_OK) return res; + res = memcmp(read_magic, bpm_signature, sizeof(bpm_signature)); + if (res != 0) return BEAT_BADPATCH; + + // Get end of metadata offset + res = BEAT_NextVLI(ctx, &metaend_off); + if (res != BEAT_OK) return res; + metaend_off += ctx->foff[BEAT_PF]; + + // Read checksums from BPS file + BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - 4); + res = BEAT_Read(ctx, BEAT_PF, &expected_chksum, sizeof(u32), 0); + if (res != BEAT_OK) return res; + if (expected_chksum != chksum) return BEAT_BADCHKSUM; + + // Allocate temporary block copy buffer + ctx->copybuf = malloc(BEAT_FILEBUFSZ); + if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY; + + // Seek back to the start of action stream / end of metadata + BEAT_SeekAbs(ctx, BEAT_PF, metaend_off); + progress_refcnt++; + return BEAT_OK; +} + +static int BPM_NextPath(BEAT_Context *ctx, char *out, int name_len) +{ + if (name_len >= BEAT_MAXPATH) return BEAT_BADPATCH; + int res = BEAT_Read(ctx, BEAT_PF, out, name_len, 1); + out[name_len] = '\0'; + if (res == BEAT_OK) { + out[name_len] = '\0'; // make sure the buffer ends with a zero char + strcpy(ctx->processing, out); + } + return res; +} + +static int BPM_MakeRelativePaths(BEAT_Context *ctx, char *src, char *dst, int name_len) +{ + char name[BEAT_MAXPATH]; + int res = BPM_NextPath(ctx, name, name_len); + if (res != BEAT_OK) return res; + if (src != NULL) + if (snprintf(src, BEAT_MAXPATH, "%s/%s", ctx->source_dir, name) >= BEAT_MAXPATH) return BEAT_BADPATCH; + if (dst != NULL) + if (snprintf(dst, BEAT_MAXPATH, "%s/%s", ctx->target_dir, name) >= BEAT_MAXPATH) return BEAT_BADPATCH; + return res; +} + +static int BPM_CreatePath(BEAT_Context *ctx, u32 name_len) +{ // Create a directory + char path[BEAT_MAXPATH]; + int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len); + if (res != BEAT_OK) return res; + + res = fvx_mkdir(path); + if (res != FR_OK && res != FR_EXIST) return BEAT_IO_ERROR; + return BEAT_OK; +} + +static int BPM_CreateFile(BEAT_Context *ctx, u32 name_len) +{ // Create a file and fill it with data provided in the BPM + u32 file_sz; + u32 checksum; + char path[BEAT_MAXPATH]; + + int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len); + if (res != BEAT_OK) return res; + + res = BEAT_NextVLI(ctx, &file_sz); // get new file size + if (res != BEAT_OK) return res; + res = BPM_OpenFile(ctx, BEAT_OF, path, file_sz); // open file as RW + if (res != BEAT_OK) return res; + res = BEAT_BlkCopy(ctx, BEAT_PF, file_sz); // copy data to new file + if (res != BEAT_OK) return res; + + res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1); + if (res != BEAT_OK) return res; + if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // get and check CRC32 + return BEAT_OK; +} + +static int BPM_ModifyFile(BEAT_Context *ctx, u32 name_len) +{ // Apply a BPS patch + u32 origin, bps_sz; + BEAT_Context bps_context; + char src[BEAT_MAXPATH], dst[BEAT_MAXPATH]; + + int res = BPM_MakeRelativePaths(ctx, src, dst, name_len); + if (res != BEAT_OK) return res; + + res = BEAT_NextVLI(ctx, &origin); // get dummy(?) origin value + if (res != BEAT_OK) return res; + res = BEAT_NextVLI(ctx, &bps_sz); // get embedded BPS size + if (res != BEAT_OK) return res; + + res = BPS_InitCTX_Advanced( + &bps_context, ctx->bpm_path, src, dst, + ctx->foff[BEAT_PF], ctx->foff[BEAT_PF] + bps_sz, + false + ); // create a BPS context using the current ranges + if (res == BEAT_OK) res = BPS_RunActions(&bps_context); // run if OK + BEAT_ReleaseCTX(&bps_context); + if (res != BEAT_OK) return res; // break off if there was an error + + BEAT_SeekOff(ctx, BEAT_PF, bps_sz); // advance beyond the BPS + return BEAT_OK; +} + +static int BPM_MirrorFile(BEAT_Context *ctx, u32 name_len) +{ // Copy a file from source to target without any modifications + u32 origin; + u32 checksum; + char src[BEAT_MAXPATH], dst[BEAT_MAXPATH]; + + int res = BPM_MakeRelativePaths(ctx, src, dst, name_len); + if (res != BEAT_OK) return res; + + // open source and destination files, read the origin dummy + res = BPM_OpenFile(ctx, BEAT_IF, src, 0); + if (res != BEAT_OK) return res; + res = BPM_OpenFile(ctx, BEAT_OF, dst, ctx->ranges[1][BEAT_IF]); + if (res != BEAT_OK) return res; + res = BEAT_NextVLI(ctx, &origin); + if (res != BEAT_OK) return res; + + // copy straight from source to destination + res = BEAT_BlkCopy(ctx, BEAT_IF, ctx->ranges[1][BEAT_IF]); + if (res != BEAT_OK) return res; + + res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1); + if (res != BEAT_OK) return res; + if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // verify checksum + return BEAT_OK; +} + +static int BPM_RunActions(BEAT_Context *ctx) +{ + static const BEAT_Action BPM_Actions[] = { // BPM Action handlers + [BPM_CREATEPATH] = BPM_CreatePath, + [BPM_CREATEFILE] = BPM_CreateFile, + [BPM_MODIFYFILE] = BPM_ModifyFile, + [BPM_MIRRORFILE] = BPM_MirrorFile + }; + int res = BEAT_RunActions(ctx, BPM_Actions); + if (res == BEAT_ABORTED) return BEAT_ABORTED; + if (res == BEAT_EOAL) return BEAT_OK; + return res; +} + +static int BEAT_Run(const char *p, const char *s, const char *d, bool bpm) +{ + int res; + BEAT_Context ctx; + + progress_timer = timer_start(); + res = (bpm ? BPM_InitCTX : BPS_InitCTX)(&ctx, p, s, d); + if (res != BEAT_OK) { + ShowPrompt(false, "Failed to initialize %s file:\n%s", + bpm ? "BPM" : "BPS", BEAT_ErrString(res)); + } else { + res = (bpm ? BPM_RunActions : BPS_RunActions)(&ctx); + switch(res) { + case BEAT_OK: + ShowPrompt(false, "Patch successfully applied"); + break; + case BEAT_ABORTED: + ShowPrompt(false, "Patching aborted by user"); + break; + default: + ShowPrompt(false, "Failed to run patch:\n%s", BEAT_ErrString(res)); + break; + } + } + BEAT_ReleaseCTX(&ctx); + return (res == BEAT_OK) ? 0 : 1; +} + +int ApplyBPSPatch(const char* modifyName, const char* sourceName, const char* targetName) +{ return BEAT_Run(modifyName, sourceName, targetName, false); } +int ApplyBPMPatch(const char* patchName, const char* sourcePath, const char* targetPath) +{ return BEAT_Run(patchName, sourcePath, targetPath, true); } diff --git a/arm9/source/main.c b/arm9/source/main.c index 7e9dec2..4d6e8d7 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -19,9 +19,6 @@ void main(int argc, char** argv, int entrypoint) // ARM11 says it's ready PXI_Barrier(ARM11_READY_BARRIER); - // Set screens to RGB16 mode - PXI_DoCMD(PXI_SET_VMODE, (u32[]){0}, 1); - // A pointer to the shared memory region is // stored in the thread ID register in the ARM9 ARM_InitSHMEM(); diff --git a/arm9/source/system/bootfirm.s b/arm9/source/system/bootfirm.s index dfcdb6a..2a604ae 100644 --- a/arm9/source/system/bootfirm.s +++ b/arm9/source/system/bootfirm.s @@ -123,13 +123,9 @@ BootFirm: @ Setup the framebuffer struct ldr r0, =FBPTR_LOC ldr r1, =VRAM_TOP_LA - ldr r2, =VRAM_TOP_RA + ldr r2, =VRAM_TOP_LA ldr r3, =VRAM_BOT_A stmia r0!, {r1,r2,r3} - - ldr r1, =VRAM_TOP_LB - ldr r2, =VRAM_TOP_RB - ldr r3, =VRAM_BOT_B stmia r0!, {r1,r2,r3} @ Copy the FIRM path somewhere safe diff --git a/arm9/source/system/spiflash.c b/arm9/source/system/spiflash.c index 00bc1a8..2f7cb08 100755 --- a/arm9/source/system/spiflash.c +++ b/arm9/source/system/spiflash.c @@ -1,44 +1,44 @@ -#include "common.h" -#include "arm.h" -#include "pxi.h" - -#define SPIFLASH_CHUNK_SIZE (0x1000) - -static char *spiflash_xfer_buf = NULL; - -bool spiflash_get_status(void) -{ - return PXI_DoCMD(PXI_NVRAM_ONLINE, NULL, 0); -} - -bool spiflash_read(u32 offset, u32 size, u8 *buf) -{ - u32 args[3]; - - if (!spiflash_xfer_buf) { - u32 xbuf = PXI_DoCMD(PXI_XALLOC, (u32[]){SPIFLASH_CHUNK_SIZE}, 1); - if (xbuf == 0 || xbuf == 0xFFFFFFFF) - return false; - spiflash_xfer_buf = (char*)xbuf; - } - - args[1] = (u32)spiflash_xfer_buf; - - while(size > 0) { - u32 blksz = min(size, SPIFLASH_CHUNK_SIZE); - - args[0] = offset; - args[2] = blksz; - - ARM_DSB(); - PXI_DoCMD(PXI_NVRAM_READ, args, 3); - ARM_InvDC_Range(spiflash_xfer_buf, blksz); - memcpy(buf, spiflash_xfer_buf, blksz); - - buf += blksz; - size -= blksz; - offset += blksz; - } - - return true; -} +#include "common.h" +#include "arm.h" +#include "pxi.h" + +#define SPIFLASH_CHUNK_SIZE (0x1000) + +static char *spiflash_xfer_buf = NULL; + +bool spiflash_get_status(void) +{ + return PXI_DoCMD(PXI_NVRAM_ONLINE, NULL, 0); +} + +bool spiflash_read(u32 offset, u32 size, u8 *buf) +{ + u32 args[3]; + + if (!spiflash_xfer_buf) { + u32 xbuf = PXI_DoCMD(PXI_XALLOC, (u32[]){SPIFLASH_CHUNK_SIZE}, 1); + if (xbuf == 0 || xbuf == 0xFFFFFFFF) + return false; + spiflash_xfer_buf = (char*)xbuf; + } + + args[1] = (u32)spiflash_xfer_buf; + + while(size > 0) { + u32 blksz = min(size, SPIFLASH_CHUNK_SIZE); + + args[0] = offset; + args[2] = blksz; + + ARM_DSB(); + PXI_DoCMD(PXI_NVRAM_READ, args, 3); + ARM_InvDC_Range(spiflash_xfer_buf, blksz); + memcpy(buf, spiflash_xfer_buf, blksz); + + buf += blksz; + size -= blksz; + offset += blksz; + } + + return true; +} diff --git a/arm9/source/system/vram0.h b/arm9/source/system/vram0.h index b3f5fec..c397bc0 100644 --- a/arm9/source/system/vram0.h +++ b/arm9/source/system/vram0.h @@ -18,8 +18,8 @@ #define VRAM0_EASTER_BIN "easter.bin" -#define VRAM0_OFFSET 0x18000000 -#define VRAM0_LIMIT 0x00300000 +#define VRAM0_OFFSET 0x080C0000 +#define VRAM0_LIMIT 0x00040000 #define TARDATA ((void*) VRAM0_OFFSET) #define TARDATA_(off) ((void*) (u32) (VRAM0_OFFSET + (off))) diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index 1ea3f58..7aaf04a 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -1609,14 +1609,13 @@ u32 BuildCiaFromNcsdFile(const char* path_ncsd, const char* path_cia) { // insert NCSD content TmdContentChunk* chunk = cia->content_list; - for (u32 i = 0, idx = 0; i < 3; i++) { + for (u32 i = 0; i < 3; i++) { NcchPartition* partition = ncsd.partitions + i; u32 offset = partition->offset * NCSD_MEDIA_UNIT; u32 size = partition->size * NCSD_MEDIA_UNIT; if (!size) continue; memset(chunk, 0, sizeof(TmdContentChunk)); - chunk->id[3] = i; - chunk->index[1] = idx++; + chunk->id[3] = chunk->index[1] = i; if (InsertCiaContent(path_cia, path_ncsd, offset, size, chunk++, NULL, false, (i == 0), false) != 0) { free(cia); return 1; diff --git a/common/common.h b/common/common.h index 2fadb31..b0e456b 100755 --- a/common/common.h +++ b/common/common.h @@ -1,78 +1,80 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef ARM9 -# ifdef MONITOR_HEAP -#include "mymalloc.h" -#define malloc my_malloc -#define realloc my_realloc -#define free my_free -# endif -#endif - -#define max(a,b) \ - (((a) > (b)) ? (a) : (b)) - -#define min(a,b) \ - (((a) < (b)) ? (a) : (b)) - -#define abs(x) \ - (((x) >= 0) ? (x) : -(x)) - -#define int_sign(x) \ - (((x) > 0) - ((x) < 0)) - -#define clamp(x, min, max) \ - ((x) < (max) ? ((x) > (min) ? (x) : (min)) : (max)) - -#define getbe16(d) \ - (((d)[0]<<8) | (d)[1]) -#define getbe32(d) \ - ((((u32) getbe16(d))<<16) | ((u32) getbe16((d)+2))) -#define getbe64(d) \ - ((((u64) getbe32(d))<<32) | ((u64) getbe32((d)+4))) - -#define getle16(d) \ - (((d)[1]<<8) | (d)[0]) -#define getle32(d) \ - ((((u32) getle16((d)+2))<<16) | ((u32) getle16(d))) -#define getle64(d) \ - ((((u64) getle32((d)+4))<<32) | ((u64) getle32(d))) - -#define align(v,a) \ - (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) - -#define countof(x) \ - (sizeof(x) / sizeof(*(x))) - -#define bkpt \ - __builtin_trap() - -#define assert(x) \ - (!!(x) ? (void)0 : __builtin_trap()) - - -#define STATIC_ASSERT(...) \ - _Static_assert((__VA_ARGS__), #__VA_ARGS__) - - -// standard output path (support file paths are in support.h) -#define OUTPUT_PATH "0:/gm9/out" - -// used in several places -#define STD_BUFFER_SIZE 0x100000 // must be a multiple of 0x200 - -// buffer area defines (in use by image.c, for RAMdrive) -#define RAMDRV_BUFFER ((u8*)0x22800000) // top of STACK -#define RAMDRV_SIZE_O3DS (0x5800000) // 88MB -#define RAMDRV_SIZE_N3DS (0xD800000) // 216MB +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef ARM9 +# ifdef MONITOR_HEAP +#include "mymalloc.h" +#define malloc my_malloc +#define realloc my_realloc +#define free my_free +# endif +#endif + +#define max(a,b) \ + (((a) > (b)) ? (a) : (b)) + +#define min(a,b) \ + (((a) < (b)) ? (a) : (b)) + +#define abs(x) \ + (((x) >= 0) ? (x) : -(x)) + +#define int_sign(x) \ + (((x) > 0) - ((x) < 0)) + +#define clamp(x, min, max) \ + ((x) < (max) ? ((x) > (min) ? (x) : (min)) : (max)) + +#define getbe16(d) \ + (((d)[0]<<8) | (d)[1]) +#define getbe32(d) \ + ((((u32) getbe16(d))<<16) | ((u32) getbe16((d)+2))) +#define getbe64(d) \ + ((((u64) getbe32(d))<<32) | ((u64) getbe32((d)+4))) + +#define getle16(d) \ + (((d)[1]<<8) | (d)[0]) +#define getle32(d) \ + ((((u32) getle16((d)+2))<<16) | ((u32) getle16(d))) +#define getle64(d) \ + ((((u64) getle32((d)+4))<<32) | ((u64) getle32(d))) + +#define align(v,a) \ + (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) + +#define countof(x) \ + (sizeof(x) / sizeof(*(x))) + +#define bkpt \ + __builtin_trap() + +#define assert(x) \ + (!!(x) ? (void)0 : __builtin_trap()) + +static inline void waitClks(unsigned clk) { + asm_v("1: subs %0, %0, #2\n\tbne 1b\n\t":"=r"(clk)::"memory","cc"); +} + +#define STATIC_ASSERT(...) \ + _Static_assert((__VA_ARGS__), #__VA_ARGS__) + +// standard output path (support file paths are in support.h) +#define OUTPUT_PATH "0:/gm9/out" + +// used in several places +#define STD_BUFFER_SIZE 0x100000 // must be a multiple of 0x200 + +// buffer area defines (in use by image.c, for RAMdrive) +#define RAMDRV_BUFFER ((u8*)0x22800000) // top of STACK +#define RAMDRV_SIZE_O3DS (0x5800000) // 88MB +#define RAMDRV_SIZE_N3DS (0xD800000) // 216MB diff --git a/common/fixp.h b/common/fixp.h index c9cebe3..89d842b 100755 --- a/common/fixp.h +++ b/common/fixp.h @@ -1,60 +1,60 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -// Fixed point math operations - -#include -#include - -typedef int32_t fixp_t; - -// 12 bit precision was chosen because -// that's the touchscreen's ADC resolution -#define FIXP_PRECISION (12) - -#define INT_TO_FIXP(i) ((fixp_t)((i) * (1 << FIXP_PRECISION))) -#define FIXP_TO_INT(f) ((fixp_t)((f) / (1 << FIXP_PRECISION))) - -#define FIXP_WHOLE_UNIT INT_TO_FIXP(1) -#define FIXP_HALF_UNIT (FIXP_WHOLE_UNIT / 2) -#define FIXP_ZERO_UNIT (0) - -#define FIXP_FRAC_MASK (FIXP_WHOLE_UNIT - 1) -#define FIXP_UNIT_MASK (~FIXP_FRAC_MASK) - -static inline fixp_t fixp_product(fixp_t a, fixp_t b) -{ - return (((s64)a * (s64)b) >> FIXP_PRECISION); -} - -static inline fixp_t fixp_quotient(fixp_t a, fixp_t b) -{ - return ((s64)a << FIXP_PRECISION) / b; -} - -static inline fixp_t fixp_round(fixp_t n) -{ - return (n + FIXP_HALF_UNIT) & FIXP_UNIT_MASK; -} - -static inline fixp_t fixp_changespace(fixp_t n, fixp_t lower_s, fixp_t upper_s, fixp_t lower_d, fixp_t upper_d) -{ - return fixp_product(n - lower_s, fixp_quotient(upper_d, upper_s)) + lower_d; -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +// Fixed point math operations + +#include +#include + +typedef int32_t fixp_t; + +// 12 bit precision was chosen because +// that's the touchscreen's ADC resolution +#define FIXP_PRECISION (12) + +#define INT_TO_FIXP(i) ((fixp_t)((i) * (1 << FIXP_PRECISION))) +#define FIXP_TO_INT(f) ((fixp_t)((f) / (1 << FIXP_PRECISION))) + +#define FIXP_WHOLE_UNIT INT_TO_FIXP(1) +#define FIXP_HALF_UNIT (FIXP_WHOLE_UNIT / 2) +#define FIXP_ZERO_UNIT (0) + +#define FIXP_FRAC_MASK (FIXP_WHOLE_UNIT - 1) +#define FIXP_UNIT_MASK (~FIXP_FRAC_MASK) + +static inline fixp_t fixp_product(fixp_t a, fixp_t b) +{ + return (((s64)a * (s64)b) >> FIXP_PRECISION); +} + +static inline fixp_t fixp_quotient(fixp_t a, fixp_t b) +{ + return ((s64)a << FIXP_PRECISION) / b; +} + +static inline fixp_t fixp_round(fixp_t n) +{ + return (n + FIXP_HALF_UNIT) & FIXP_UNIT_MASK; +} + +static inline fixp_t fixp_changespace(fixp_t n, fixp_t lower_s, fixp_t upper_s, fixp_t lower_d, fixp_t upper_d) +{ + return fixp_product(n - lower_s, fixp_quotient(upper_d, upper_s)) + lower_d; +} diff --git a/common/hid_map.h b/common/hid_map.h index 1ed722a..7f2ac2a 100755 --- a/common/hid_map.h +++ b/common/hid_map.h @@ -1,35 +1,35 @@ -#pragma once - -#define BUTTON_A ((u32)1 << 0) -#define BUTTON_B ((u32)1 << 1) -#define BUTTON_SELECT ((u32)1 << 2) -#define BUTTON_START ((u32)1 << 3) -#define BUTTON_RIGHT ((u32)1 << 4) -#define BUTTON_LEFT ((u32)1 << 5) -#define BUTTON_UP ((u32)1 << 6) -#define BUTTON_DOWN ((u32)1 << 7) -#define BUTTON_R1 ((u32)1 << 8) -#define BUTTON_L1 ((u32)1 << 9) -#define BUTTON_X ((u32)1 << 10) -#define BUTTON_Y ((u32)1 << 11) -#define BUTTON_ANY 0x00000FFF -#define BUTTON_ARROW (BUTTON_RIGHT|BUTTON_LEFT|BUTTON_UP|BUTTON_DOWN) - -// strings for button conversion -#define BUTTON_STRINGS "A", "B", "SELECT", "START", "RIGHT", "LEFT", "UP", "DOWN", "R", "L", "X", "Y" - -// special buttons / touchscreen / cart / sd -#define BUTTON_POWER ((u32)1 << 12) -#define BUTTON_HOME ((u32)1 << 13) -#define BUTTON_WIFI ((u32)1 << 14) -#define BUTTON_TOUCH ((u32)1 << 15) - -#define SHELL_OPEN ((u32)1 << 16) -#define SHELL_CLOSED ((u32)1 << 17) - -#define CART_INSERT ((u32)1 << 18) -#define CART_EJECT ((u32)1 << 19) -#define SD_INSERT ((u32)1 << 20) -#define SD_EJECT ((u32)1 << 21) - -#define TIMEOUT_HID ((u32)1 << 31) +#pragma once + +#define BUTTON_A ((u32)1 << 0) +#define BUTTON_B ((u32)1 << 1) +#define BUTTON_SELECT ((u32)1 << 2) +#define BUTTON_START ((u32)1 << 3) +#define BUTTON_RIGHT ((u32)1 << 4) +#define BUTTON_LEFT ((u32)1 << 5) +#define BUTTON_UP ((u32)1 << 6) +#define BUTTON_DOWN ((u32)1 << 7) +#define BUTTON_R1 ((u32)1 << 8) +#define BUTTON_L1 ((u32)1 << 9) +#define BUTTON_X ((u32)1 << 10) +#define BUTTON_Y ((u32)1 << 11) +#define BUTTON_ANY 0x00000FFF +#define BUTTON_ARROW (BUTTON_RIGHT|BUTTON_LEFT|BUTTON_UP|BUTTON_DOWN) + +// strings for button conversion +#define BUTTON_STRINGS "A", "B", "SELECT", "START", "RIGHT", "LEFT", "UP", "DOWN", "R", "L", "X", "Y" + +// special buttons / touchscreen / cart / sd +#define BUTTON_POWER ((u32)1 << 12) +#define BUTTON_HOME ((u32)1 << 13) +#define BUTTON_WIFI ((u32)1 << 14) +#define BUTTON_TOUCH ((u32)1 << 15) + +#define SHELL_OPEN ((u32)1 << 16) +#define SHELL_CLOSED ((u32)1 << 17) + +#define CART_INSERT ((u32)1 << 18) +#define CART_EJECT ((u32)1 << 19) +#define SD_INSERT ((u32)1 << 20) +#define SD_EJECT ((u32)1 << 21) + +#define TIMEOUT_HID ((u32)1 << 31) diff --git a/common/pxi.c b/common/pxi.c index 9f1904d..ce32f9e 100755 --- a/common/pxi.c +++ b/common/pxi.c @@ -1,59 +1,59 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 d0k3, Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -void PXI_Barrier(u8 barrier_id) -{ - PXI_SetRemote(barrier_id); - PXI_WaitRemote(barrier_id); -} - -void PXI_Reset(void) -{ - *PXI_SYNC_IRQ = 0; - *PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH | PXI_CNT_ENABLE_FIFO; - for (int i = 0; i < PXI_FIFO_LEN; i++) - *PXI_RECV; - - *PXI_CNT = 0; - *PXI_CNT = PXI_CNT_RECV_FIFO_AVAIL_IRQ | PXI_CNT_ENABLE_FIFO | - PXI_CNT_ACKNOWLEDGE_ERROR; - - PXI_SetRemote(0xFF); -} - -void PXI_SendArray(const u32 *w, u32 c) -{ - while(c--) - PXI_Send(*(w++)); -} - -void PXI_RecvArray(u32 *w, u32 c) -{ - while(c--) - *(w++) = PXI_Recv(); -} - -u32 PXI_DoCMD(u32 cmd, const u32 *args, u32 argc) -{ - PXI_Send((argc << 16) | cmd); - PXI_SendArray(args, argc); - return PXI_Recv(); -} +/* + * This file is part of GodMode9 + * Copyright (C) 2019 d0k3, Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +void PXI_Barrier(u8 barrier_id) +{ + PXI_SetRemote(barrier_id); + PXI_WaitRemote(barrier_id); +} + +void PXI_Reset(void) +{ + *PXI_SYNC_IRQ = 0; + *PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH | PXI_CNT_ENABLE_FIFO; + for (int i = 0; i < PXI_FIFO_LEN; i++) + *PXI_RECV; + + *PXI_CNT = 0; + *PXI_CNT = PXI_CNT_RECV_FIFO_AVAIL_IRQ | PXI_CNT_ENABLE_FIFO | + PXI_CNT_ACKNOWLEDGE_ERROR; + + PXI_SetRemote(0xFF); +} + +void PXI_SendArray(const u32 *w, u32 c) +{ + while(c--) + PXI_Send(*(w++)); +} + +void PXI_RecvArray(u32 *w, u32 c) +{ + while(c--) + *(w++) = PXI_Recv(); +} + +u32 PXI_DoCMD(u32 cmd, const u32 *args, u32 argc) +{ + PXI_Send((argc << 16) | cmd); + PXI_SendArray(args, argc); + return PXI_Recv(); +} diff --git a/common/shmem.h b/common/shmem.h index 4c58f69..1e00929 100755 --- a/common/shmem.h +++ b/common/shmem.h @@ -1,39 +1,39 @@ -/* - * This file is part of GodMode9 - * Copyright (C) 2019 Wolfvak - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -typedef struct { - u64 hid_state; -} GlobalSharedMemory; - -#ifdef ARM9 -#include - -static inline const GlobalSharedMemory *ARM_GetSHMEM(void) -{ - return (const GlobalSharedMemory*)ARM_GetTID(); -} - -static void ARM_InitSHMEM(void) -{ - ARM_SetTID(PXI_DoCMD(PXI_GET_SHMEM, NULL, 0)); -} -#endif +/* + * This file is part of GodMode9 + * Copyright (C) 2019 Wolfvak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +typedef struct { + u64 hid_state; +} GlobalSharedMemory; + +#ifdef ARM9 +#include + +static inline const GlobalSharedMemory *ARM_GetSHMEM(void) +{ + return (const GlobalSharedMemory*)ARM_GetTID(); +} + +static void ARM_InitSHMEM(void) +{ + ARM_SetTID(PXI_DoCMD(PXI_GET_SHMEM, NULL, 0)); +} +#endif diff --git a/common/vram.h b/common/vram.h index 7b48461..0138f75 100644 --- a/common/vram.h +++ b/common/vram.h @@ -4,10 +4,8 @@ #define BOTTOM_VRAM (320*240*4) #define VRAM_START (0x18300000) + #define VRAM_TOP_LA (VRAM_START) -#define VRAM_TOP_LB (VRAM_TOP_LA + TOP_VRAM) -#define VRAM_TOP_RA (VRAM_TOP_LB + TOP_VRAM) -#define VRAM_TOP_RB (VRAM_TOP_RA + TOP_VRAM) -#define VRAM_BOT_A (VRAM_TOP_RB + TOP_VRAM) -#define VRAM_BOT_B (VRAM_BOT_A + BOTTOM_VRAM) -#define VRAM_END (VRAM_BOT_B + BOTTOM_VRAM) +#define VRAM_BOT_A (VRAM_TOP_LA + TOP_VRAM) + +#define VRAM_END (VRAM_BOT_A + BOTTOM_VRAM)