From f10d318e542cadae2e0c21b6f8bd152be97f5407 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Wed, 15 Jul 2020 01:41:04 -0500 Subject: [PATCH] [nostalgia/core/gba] Add wfi functions --- src/nostalgia/core/gba/CMakeLists.txt | 1 + src/nostalgia/core/gba/bios.hpp | 21 +++++++++ src/nostalgia/core/gba/bios.s | 37 ++++++++++++++++ src/nostalgia/core/gba/core.cpp | 4 +- src/nostalgia/core/gba/gfx.cpp | 11 ++++- src/nostalgia/core/gba/irq.hpp | 6 +++ src/nostalgia/core/gba/irq.s | 62 ++++++++++++++++----------- src/nostalgia/core/gba/panic.cpp | 26 +++++++---- src/nostalgia/core/gfx.hpp | 2 + 9 files changed, 134 insertions(+), 36 deletions(-) create mode 100644 src/nostalgia/core/gba/bios.hpp create mode 100644 src/nostalgia/core/gba/bios.s diff --git a/src/nostalgia/core/gba/CMakeLists.txt b/src/nostalgia/core/gba/CMakeLists.txt index 0f5ffcaf..a85cee31 100644 --- a/src/nostalgia/core/gba/CMakeLists.txt +++ b/src/nostalgia/core/gba/CMakeLists.txt @@ -3,6 +3,7 @@ if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA") add_library( NostalgiaCore-GBA + bios.s core.cpp gfx.cpp irq.arm.cpp diff --git a/src/nostalgia/core/gba/bios.hpp b/src/nostalgia/core/gba/bios.hpp new file mode 100644 index 00000000..b2be8a1a --- /dev/null +++ b/src/nostalgia/core/gba/bios.hpp @@ -0,0 +1,21 @@ +/* + * Copyright 2016 - 2020 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +extern "C" { + +void nostalgia_core_halt(); + +void nostalgia_core_stop(); + +void nostalgia_core_wfi(); + +void nostalgia_core_vblankwfi(); + +} diff --git a/src/nostalgia/core/gba/bios.s b/src/nostalgia/core/gba/bios.s new file mode 100644 index 00000000..933dd445 --- /dev/null +++ b/src/nostalgia/core/gba/bios.s @@ -0,0 +1,37 @@ +// +// Copyright 2016 - 2020 gtalent2@gmail.com +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +.section .iwram, "ax", %progbits +.thumb +.align + +.global nostalgia_core_halt +.type nostalgia_core_halt, %function +nostalgia_core_halt: + swi 2 + bx lr + +.global nostalgia_core_stop +.type nostalgia_core_stop, %function +nostalgia_core_stop: + swi 3 + bx lr + +.global nostalgia_core_wfi +.type nostalgia_core_wfi, %function +nostalgia_core_wfi: + swi 4 + bx lr + +.global nostalgia_core_vblankwfi +.type nostalgia_core_vblankwfi, %function +nostalgia_core_vblankwfi: + swi 5 + bx lr + +// vim: ft=armv4 diff --git a/src/nostalgia/core/gba/core.cpp b/src/nostalgia/core/gba/core.cpp index 67d53fa5..ded1523b 100644 --- a/src/nostalgia/core/gba/core.cpp +++ b/src/nostalgia/core/gba/core.cpp @@ -10,6 +10,7 @@ #include #include "addresses.hpp" +#include "bios.hpp" #include "irq.hpp" extern "C" void isr(); @@ -19,7 +20,7 @@ namespace nostalgia::core { // Timer Consts constexpr auto NanoSecond = 1000000000; constexpr auto MilliSecond = 1000; -constexpr int TicksMs59ns = (NanoSecond / MilliSecond) / 59.59; +constexpr int TicksMs59ns = 65535 - (NanoSecond / MilliSecond) / 59.59; extern volatile ox::Uint g_timerMs; @@ -45,6 +46,7 @@ ox::Error init(Context *ctx) { ox::Error run(Context*) { while (1) { + nostalgia_core_vblankwfi(); } return OxError(0); } diff --git a/src/nostalgia/core/gba/gfx.cpp b/src/nostalgia/core/gba/gfx.cpp index deb5758b..64baa06a 100644 --- a/src/nostalgia/core/gba/gfx.cpp +++ b/src/nostalgia/core/gba/gfx.cpp @@ -14,12 +14,14 @@ #include #include "addresses.hpp" +#include "bios.hpp" #include "irq.hpp" #include "gfx.hpp" namespace nostalgia::core { constexpr auto GbaTileColumns = 32; +constexpr auto GbaTileRows = 32; constexpr uint16_t DispStat_irq_vblank = 1 << 3; constexpr uint16_t DispStat_irq_hblank = 1 << 4; @@ -209,6 +211,11 @@ void setTile(Context*, int layer, int column, int row, uint8_t tile) { MEM_BG_MAP[layer][row * GbaTileColumns + column] = tile; } +// Do NOT use Context in the GBA version of this function. +void clearTileLayer(Context*, int layer) { + memset(&MEM_BG_MAP[layer], 0, GbaTileRows * GbaTileColumns); +} + void setSprite(unsigned idx, unsigned x, unsigned y, unsigned tileIdx) { GbaSpriteAttrUpdate oa; oa.attr0 = static_cast(y & ox::onMask(7)) @@ -217,7 +224,9 @@ void setSprite(unsigned idx, unsigned x, unsigned y, unsigned tileIdx) { oa.attr2 = static_cast(tileIdx & ox::onMask(8)); oa.idx = idx; // block until g_spriteUpdates is less than buffer len - while (g_spriteUpdates >= config::GbaSpriteBufferLen); + if (g_spriteUpdates >= config::GbaSpriteBufferLen) { + nostalgia_core_vblankwfi(); + } REG_IE &= ~Int_vblank; // disable vblank interrupt handler g_spriteBuffer[g_spriteUpdates++] = oa; REG_IE |= Int_vblank; // enable vblank interrupt handler diff --git a/src/nostalgia/core/gba/irq.hpp b/src/nostalgia/core/gba/irq.hpp index e753e8db..cb72effa 100644 --- a/src/nostalgia/core/gba/irq.hpp +++ b/src/nostalgia/core/gba/irq.hpp @@ -26,3 +26,9 @@ constexpr uint16_t Int_input = 1 << 14; // gamepad constexpr uint16_t Int_cart = 1 << 15; // cartridge removed } + +extern "C" { + +void nostalgia_core_wfi(); + +} diff --git a/src/nostalgia/core/gba/irq.s b/src/nostalgia/core/gba/irq.s index 9e92e2ed..ab0af877 100644 --- a/src/nostalgia/core/gba/irq.s +++ b/src/nostalgia/core/gba/irq.s @@ -1,5 +1,5 @@ // -// Copyright 2016 - 2020 gtalent2@gmail.com +// Copyright 2016 - 2020 gary@drinkingtea.net // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -16,7 +16,7 @@ .extern nostalgia_core_isr_timer2 .extern nostalgia_core_isr_timer3 -.equ REG_IFBIOS, 0x03fffff8 +.equ REG_IFBIOS, 0x03007ff8 .equ REG_IE, 0x04000200 .equ REG_IF, 0x04000202 @@ -54,51 +54,59 @@ isr: strh r1, [r0, #2] ldr r0, =#REG_IFBIOS // Acknowledge IRQ in REG_IFBIOS - ldrh r2, [r0] // r2 becomes REG_IFBIOS value + ldr r2, [r0] // r2 becomes REG_IFBIOS value orr r2, r2, r1 - strh r2, [r0] + str r2, [r0] // done with r2 as IFBIOS value - // done with r0 as REG_IE - - // clear IME to disable interrupts - ldr r2, =#REG_IME - mov r0, #0 - str r0, [r2] - - // enter system mode - mrs r0, cpsr - bic r0, r0, #0xDF - orr r0, r0, #0x1F - msr cpsr, r0 - - push {lr} - ldr lr, =isr_end + // done with r0 as REG_IFBIOS //////////////////////////////////////////////////// // Interrupt Table Begin // //////////////////////////////////////////////////// cmp r1, #Int_vblank - beq nostalgia_core_isr_vblank + ldreq r0, =nostalgia_core_isr_vblank + beq isr_call_handler cmp r1, #Int_timer0 - beq nostalgia_core_isr_timer0 + ldreq r0, =nostalgia_core_isr_timer0 + beq isr_call_handler cmp r1, #Int_timer1 - beq nostalgia_core_isr_timer1 + ldreq r0, =nostalgia_core_isr_timer1 + beq isr_call_handler cmp r1, #Int_timer2 - beq nostalgia_core_isr_timer2 + ldreq r0, =nostalgia_core_isr_timer2 + beq isr_call_handler cmp r1, #Int_timer3 - beq nostalgia_core_isr_timer3 + ldreq r0, =nostalgia_core_isr_timer3 + beq isr_call_handler //////////////////////////////////////////////////// // Interrupt Table End // //////////////////////////////////////////////////// -isr_end: - // restore lr from before the Interrupt Table + b isr_end + +isr_call_handler: + // clear IME to disable interrupts + ldr r2, =#REG_IME + mov r1, #0 + str r1, [r2] + + // enter system mode + mrs r1, cpsr + bic r1, r1, #0xDF + orr r1, r1, #0x1F + msr cpsr, r1 + + push {lr} + ldr lr, =isr_restore + bx r0 + +isr_restore: pop {lr} // re-enter irq mode @@ -112,6 +120,8 @@ isr_end: mov r0, #1 str r0, [r2] +isr_end: + bx lr // vim: ft=armv4 diff --git a/src/nostalgia/core/gba/panic.cpp b/src/nostalgia/core/gba/panic.cpp index 95ab46ba..1cdf1985 100644 --- a/src/nostalgia/core/gba/panic.cpp +++ b/src/nostalgia/core/gba/panic.cpp @@ -6,8 +6,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "../core.hpp" -#include "../gfx.hpp" +#include + +#include +#include + +#include "addresses.hpp" +#include "bios.hpp" namespace ox { @@ -16,15 +21,20 @@ using namespace nostalgia::core; void panic(const char*, int, const char *msg, ox::Error err) { oxIgnoreError(initGfx(nullptr)); oxIgnoreError(initConsole(nullptr)); + // enable only BG 0 + REG_DISPCTL = 0x0100; + clearTileLayer(nullptr, 0); ox::BString<23> serr = "Error code: "; serr += err; - puts(nullptr, 32 + 0, 1, "SADNESS..."); - puts(nullptr, 32 + 0, 4, "UNEXPECTED STATE:"); + puts(nullptr, 32 + 1, 1, "SADNESS..."); + puts(nullptr, 32 + 1, 4, "UNEXPECTED STATE:"); puts(nullptr, 32 + 2, 6, msg); - puts(nullptr, 32 + 2, 7, serr.c_str()); - puts(nullptr, 32 + 0, 10, "PLEASE RESTART THE SYSTEM"); - // TODO: properly end program execution, this wastes power - while (1); + puts(nullptr, 32 + 2, 8, serr.c_str()); + puts(nullptr, 32 + 1, 15, "PLEASE RESTART THE SYSTEM"); + // disable interrupts and wait for interrupt, halt and stop seem to have + // issues in mGBA + REG_IME = 0; + nostalgia_core_wfi(); } } diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index dc9f4d2d..6842bbf4 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -125,6 +125,8 @@ void puts(Context *ctx, int column, int row, const char *str); void setTile(Context *ctx, int layer, int column, int row, uint8_t tile); +void clearTileLayer(Context*, int layer); + void setSprite(unsigned idx, unsigned x, unsigned y, unsigned tileIdx); }