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)