[nostalgia] Break part of core out into Turbine and TeaGBA libraries
This commit is contained in:
12
deps/gbastartup/CMakeLists.txt
vendored
12
deps/gbastartup/CMakeLists.txt
vendored
@ -1,12 +0,0 @@
|
||||
enable_language(CXX ASM)
|
||||
|
||||
add_library(
|
||||
GbaStartup OBJECT
|
||||
gba_crt0.s
|
||||
cstartup.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
GbaStartup PUBLIC
|
||||
OxStd
|
||||
)
|
1
deps/teagba/CMakeLists.txt
vendored
Normal file
1
deps/teagba/CMakeLists.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(src)
|
107
deps/teagba/include/teagba/addresses.hpp
vendored
Normal file
107
deps/teagba/include/teagba/addresses.hpp
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/array.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Interrupt Handler
|
||||
|
||||
using interrupt_handler = void (*)();
|
||||
#define REG_ISR *reinterpret_cast<interrupt_handler*>(0x0300'7FFC)
|
||||
#define REG_IE *reinterpret_cast<volatile uint16_t*>(0x0400'0200)
|
||||
#define REG_IF *reinterpret_cast<volatile uint16_t*>(0x0400'0202)
|
||||
#define REG_IME *reinterpret_cast<volatile uint16_t*>(0x0400'0208)
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Display Registers
|
||||
|
||||
#define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x0400'0000)
|
||||
#define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x0400'0004)
|
||||
#define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x0400'0006)
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Timers
|
||||
|
||||
#define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x0400'0100)
|
||||
#define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0102)
|
||||
|
||||
#define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x0400'0104)
|
||||
#define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0106)
|
||||
|
||||
#define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x0400'0108)
|
||||
#define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010a)
|
||||
|
||||
#define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400'010c)
|
||||
#define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010e)
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// background registers
|
||||
|
||||
// background control registers
|
||||
using BgCtl = uint16_t;
|
||||
#define REG_BG0CTL *reinterpret_cast<volatile BgCtl*>(0x0400'0008)
|
||||
#define REG_BG1CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000a)
|
||||
#define REG_BG2CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000c)
|
||||
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto ®BgCtl(auto bgIdx) noexcept {
|
||||
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
|
||||
}
|
||||
|
||||
// background horizontal scrolling registers
|
||||
#define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0010)
|
||||
#define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0014)
|
||||
#define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0018)
|
||||
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
|
||||
|
||||
[[nodiscard]]
|
||||
inline volatile auto ®BgHofs(auto bgIdx) noexcept {
|
||||
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
|
||||
}
|
||||
|
||||
// background vertical scrolling registers
|
||||
#define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0012)
|
||||
#define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0016)
|
||||
#define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001a)
|
||||
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
|
||||
|
||||
[[nodiscard]]
|
||||
inline volatile auto ®BgVofs(auto bgIdx) noexcept {
|
||||
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// User Input
|
||||
|
||||
#define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x0400'0130)
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Memory Addresses
|
||||
|
||||
#define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0200'0000)
|
||||
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203'FFFF)
|
||||
|
||||
#define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0300'0000)
|
||||
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x0300'7FFF)
|
||||
|
||||
#define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x0400'0050)
|
||||
|
||||
#define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x0500'0000)
|
||||
#define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x0500'0200)
|
||||
|
||||
using BgMapTile = ox::Array<uint16_t, 8192>;
|
||||
#define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x0600'0000)
|
||||
#define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600'e000)
|
||||
|
||||
#define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x0601'0000)
|
||||
#define MEM_OAM reinterpret_cast<uint64_t*>(0x0700'0000)
|
||||
|
||||
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
|
||||
|
||||
#define MEM_SRAM reinterpret_cast<char*>(0x0e00'0000)
|
||||
#define MEM_SRAM_SIZE 65535
|
22
deps/teagba/include/teagba/bios.hpp
vendored
Normal file
22
deps/teagba/include/teagba/bios.hpp
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Functions for accessing BIOS calls
|
||||
|
||||
extern "C" {
|
||||
|
||||
// waits for any interrupt
|
||||
void teagba_halt();
|
||||
|
||||
void teagba_stop();
|
||||
|
||||
// waits for interrupts specified in interSubs
|
||||
void teagba_intrwait(unsigned discardExistingIntrs, unsigned intrSubs);
|
||||
|
||||
// waits for vblank interrupt
|
||||
void teagba_vblankintrwait();
|
||||
|
||||
}
|
46
deps/teagba/include/teagba/gfx.hpp
vendored
Normal file
46
deps/teagba/include/teagba/gfx.hpp
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/array.hpp>
|
||||
#include <ox/std/stddef.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace teagba {
|
||||
|
||||
enum DispCtl {
|
||||
DispCtl_Mode0 = 0,
|
||||
DispCtl_Mode1 = 1,
|
||||
DispCtl_Mode2 = 2,
|
||||
DispCtl_Mode3 = 3,
|
||||
DispCtl_Mode4 = 4,
|
||||
DispCtl_Mode5 = 5,
|
||||
|
||||
DispCtl_SpriteMap1D = 1 << 6,
|
||||
|
||||
DispCtl_Bg0 = 1 << 8,
|
||||
DispCtl_Bg1 = 1 << 9,
|
||||
DispCtl_Bg2 = 1 << 10,
|
||||
DispCtl_Bg3 = 1 << 11,
|
||||
|
||||
DispCtl_Obj = 1 << 12,
|
||||
};
|
||||
|
||||
struct OX_ALIGN8 GbaSpriteAttrUpdate {
|
||||
uint16_t attr0 = 0;
|
||||
uint16_t attr1 = 0;
|
||||
uint16_t attr2 = 0;
|
||||
uint16_t idx = 0;
|
||||
|
||||
};
|
||||
|
||||
extern volatile uint16_t g_spriteUpdates;
|
||||
extern ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
||||
|
||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
|
||||
|
||||
void applySpriteUpdates() noexcept;
|
||||
|
||||
}
|
30
deps/teagba/include/teagba/irq.hpp
vendored
Normal file
30
deps/teagba/include/teagba/irq.hpp
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace teagba {
|
||||
|
||||
constexpr uint16_t DispStat_irq_vblank = 1 << 3;
|
||||
constexpr uint16_t DispStat_irq_hblank = 1 << 4;
|
||||
constexpr uint16_t DispStat_irq_vcount = 1 << 5;
|
||||
|
||||
constexpr uint16_t Int_vblank = 1 << 0;
|
||||
constexpr uint16_t Int_hblank = 1 << 1;
|
||||
constexpr uint16_t Int_vcount = 1 << 2;
|
||||
constexpr uint16_t Int_timer0 = 1 << 3;
|
||||
constexpr uint16_t Int_timer1 = 1 << 4;
|
||||
constexpr uint16_t Int_timer2 = 1 << 5;
|
||||
constexpr uint16_t Int_timer3 = 1 << 6;
|
||||
constexpr uint16_t Int_serial = 1 << 7; // link cable
|
||||
constexpr uint16_t Int_dma0 = 1 << 8;
|
||||
constexpr uint16_t Int_dma1 = 1 << 9;
|
||||
constexpr uint16_t Int_dma2 = 1 << 10;
|
||||
constexpr uint16_t Int_dma3 = 1 << 11;
|
||||
constexpr uint16_t Int_dma4 = 1 << 12;
|
||||
constexpr uint16_t Int_dma5 = 1 << 13;
|
||||
constexpr uint16_t Int_input = 1 << 14; // gamepad
|
||||
constexpr uint16_t Int_cart = 1 << 15; // cartridge removed
|
||||
|
||||
}
|
70
deps/teagba/include/teagba/registers.hpp
vendored
Normal file
70
deps/teagba/include/teagba/registers.hpp
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "addresses.hpp"
|
||||
|
||||
namespace teagba {
|
||||
|
||||
inline auto bgSetSbb(volatile BgCtl *bgCtl, unsigned sbb) noexcept {
|
||||
*bgCtl = (*bgCtl & ~0b11111'0000'0000u) | (sbb << 8);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr unsigned bgPri(BgCtl bgCtl) noexcept {
|
||||
return bgCtl & 1;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgPri(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgPri(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetPri(volatile BgCtl *bgCtl, unsigned pri) noexcept {
|
||||
pri = pri & 0b1;
|
||||
*bgCtl = (*bgCtl & ~0b1u) | (pri << 0);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr unsigned bgBpp(BgCtl bgCtl) noexcept {
|
||||
return ((bgCtl >> 7) & 1) ? 8 : 4;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgBpp(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgBpp(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetBpp(volatile BgCtl *bgCtl, unsigned bpp) noexcept {
|
||||
constexpr auto Bpp8 = 1 << 7;
|
||||
if (bpp == 4) {
|
||||
*bgCtl = *bgCtl | ((*bgCtl | Bpp8) ^ Bpp8); // set to use 4 bits per pixel
|
||||
} else {
|
||||
*bgCtl = *bgCtl | Bpp8; // set to use 8 bits per pixel
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr auto bgCbb(BgCtl bgCtl) noexcept {
|
||||
return (bgCtl >> 2) & 0b11u;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgCbb(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgCbb(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetCbb(volatile BgCtl *bgCtl, unsigned cbb) noexcept {
|
||||
cbb = cbb & 0b11;
|
||||
*bgCtl = (*bgCtl & ~0b1100u) | (cbb << 2);
|
||||
}
|
||||
|
||||
constexpr void iterateBgCtl(auto cb) noexcept {
|
||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||
cb(bgCtl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
deps/teagba/src/CMakeLists.txt
vendored
Normal file
21
deps/teagba/src/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
enable_language(CXX ASM)
|
||||
|
||||
set_source_files_properties(gfx.cpp PROPERTIES COMPILE_FLAGS -marm)
|
||||
|
||||
add_library(
|
||||
TeaGBA
|
||||
bios.s
|
||||
gba_crt0.s
|
||||
cstartup.cpp
|
||||
gfx.cpp
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
TeaGBA PUBLIC
|
||||
../include
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
TeaGBA PUBLIC
|
||||
OxStd
|
||||
)
|
37
deps/teagba/src/bios.s
vendored
Normal file
37
deps/teagba/src/bios.s
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright 2016 - 2023 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/.
|
||||
//
|
||||
|
||||
.section .iwram, "ax", %progbits
|
||||
.thumb
|
||||
.align
|
||||
|
||||
.global teagba_halt
|
||||
.type teagba_halt, %function
|
||||
teagba_halt:
|
||||
swi 2
|
||||
bx lr
|
||||
|
||||
.global teagba_stop
|
||||
.type teagba_stop, %function
|
||||
teagba_stop:
|
||||
swi 3
|
||||
bx lr
|
||||
|
||||
.global teagba_intrwait
|
||||
.type teagba_intrwait, %function
|
||||
teagba_intrwait:
|
||||
swi 4
|
||||
bx lr
|
||||
|
||||
.global teagba_vblankintrwait
|
||||
.type teagba_vblankintrwait, %function
|
||||
teagba_vblankintrwait:
|
||||
swi 5
|
||||
bx lr
|
||||
|
||||
// vim: ft=armv4
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 - 2021 gary@drinkingtea.net
|
||||
* Copyright 2016 - 2023 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
|
40
deps/teagba/src/gfx.cpp
vendored
Normal file
40
deps/teagba/src/gfx.cpp
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/bios.hpp>
|
||||
#include <teagba/irq.hpp>
|
||||
|
||||
#include <teagba/gfx.hpp>
|
||||
|
||||
namespace teagba {
|
||||
|
||||
volatile uint16_t g_spriteUpdates = 0;
|
||||
ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
||||
|
||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
||||
// block until g_spriteUpdates is less than buffer len
|
||||
if (g_spriteUpdates >= g_spriteBuffer.size()) [[unlikely]] {
|
||||
teagba_vblankintrwait();
|
||||
}
|
||||
const auto ie = REG_IE; // disable vblank interrupt handler
|
||||
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
|
||||
const auto updateCnt = g_spriteUpdates;
|
||||
g_spriteBuffer[updateCnt] = upd;
|
||||
g_spriteUpdates = updateCnt + 1;
|
||||
REG_IE = ie; // enable vblank interrupt handler
|
||||
}
|
||||
|
||||
void applySpriteUpdates() noexcept {
|
||||
// copy g_spriteUpdates to allow it to use a register instead of reading
|
||||
// from memory every iteration of the loop, needed because g_spriteUpdates
|
||||
// is volatile
|
||||
const unsigned updates = g_spriteUpdates;
|
||||
for (unsigned i = 0; i < updates; ++i) {
|
||||
const auto &oa = g_spriteBuffer[i];
|
||||
MEM_OAM[oa.idx] = *reinterpret_cast<const uint64_t*>(&oa);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user