85 lines
2.2 KiB
C++
85 lines
2.2 KiB
C++
/*
|
|
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
|
*/
|
|
|
|
#include <nostalgia/core/config.hpp>
|
|
#include <nostalgia/core/core.hpp>
|
|
#include <nostalgia/core/input.hpp>
|
|
|
|
#include "addresses.hpp"
|
|
#include "bios.hpp"
|
|
#include "irq.hpp"
|
|
#include "core.hpp"
|
|
|
|
extern "C" void isr();
|
|
|
|
namespace nostalgia::core {
|
|
|
|
// Timer Consts
|
|
constexpr int NanoSecond = 1000000000;
|
|
constexpr int MilliSecond = 1000;
|
|
constexpr int TicksMs59ns = 65535 - (NanoSecond / MilliSecond) / 59.59;
|
|
|
|
extern UpdateHandler g_updateHandler;
|
|
|
|
extern volatile gba_timer_t g_timerMs;
|
|
|
|
static void initIrq() noexcept {
|
|
REG_ISR = isr;
|
|
REG_IME = 1; // enable interrupts
|
|
}
|
|
|
|
static void initTimer() noexcept {
|
|
// make timer0 a ~1 millisecond timer
|
|
REG_TIMER0 = TicksMs59ns;
|
|
REG_TIMER0CTL = 0b11000000;
|
|
// enable interrupt for timer0
|
|
REG_IE = REG_IE | Int_timer0;
|
|
}
|
|
|
|
static ox::Result<std::size_t> findPreloadSection() noexcept {
|
|
// put the header in the wrong order to prevent mistaking this code for the
|
|
// media section
|
|
constexpr auto headerP2 = "D_HEADER________";
|
|
constexpr auto headerP1 = "NOSTALGIA_PRELOA";
|
|
constexpr auto headerP1Len = ox_strlen(headerP2);
|
|
constexpr auto headerP2Len = ox_strlen(headerP1);
|
|
constexpr auto headerLen = headerP1Len + headerP2Len;
|
|
for (auto current = MEM_ROM; current < reinterpret_cast<char*>(0x0a000000); current += headerLen) {
|
|
if (ox_memcmp(current, headerP1, headerP1Len) == 0 &&
|
|
ox_memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) {
|
|
return reinterpret_cast<std::size_t>(current + headerLen);
|
|
}
|
|
}
|
|
return OxError(1);
|
|
}
|
|
|
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
|
auto ctx = ox::make_unique<Context>();
|
|
ctx->rom = std::move(fs);
|
|
ctx->appName = appName;
|
|
oxReturnError(initGfx(ctx.get()));
|
|
initTimer();
|
|
initIrq();
|
|
oxReturnError(findPreloadSection().moveTo(&ctx->preloadSectionOffset));
|
|
return ctx;
|
|
}
|
|
|
|
void setUpdateHandler(Context*, UpdateHandler h) noexcept {
|
|
g_updateHandler = h;
|
|
}
|
|
|
|
uint64_t ticksMs(Context*) noexcept {
|
|
return g_timerMs;
|
|
}
|
|
|
|
bool buttonDown(Context*, Key k) noexcept {
|
|
return k <= Key::GamePad_L && !(REG_GAMEPAD & (1 << static_cast<int>(k)));
|
|
}
|
|
|
|
void shutdown(Context *ctx) noexcept {
|
|
ctx->running = false;
|
|
}
|
|
|
|
}
|