From 758907ab5a66e9ab5748fff638e4ce632d55668c Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 3 Nov 2019 21:32:40 -0600 Subject: [PATCH] [nostalgia] Restore GBA support --- src/nostalgia/CMakeLists.txt | 5 +- src/nostalgia/core/gba/gfx.cpp | 149 +++++++++++++--------------- src/nostalgia/player/CMakeLists.txt | 1 - src/nostalgia/player/main.cpp | 19 ++-- src/nostalgia/player/startup.s | 40 +++++++- src/nostalgia/tools/CMakeLists.txt | 3 - src/nostalgia/tools/pack.cpp | 10 +- src/nostalgia/tools/pack/pack.cpp | 31 ++++-- src/nostalgia/tools/pack/pack.hpp | 2 +- 9 files changed, 152 insertions(+), 108 deletions(-) diff --git a/src/nostalgia/CMakeLists.txt b/src/nostalgia/CMakeLists.txt index 708e6e23..23d11ad3 100644 --- a/src/nostalgia/CMakeLists.txt +++ b/src/nostalgia/CMakeLists.txt @@ -17,7 +17,10 @@ add_subdirectory(common) add_subdirectory(player) add_subdirectory(world) -if(NOSTALGIA_BUILD_STUDIO) +if(NOSTALGIA_BUILD_TYPE STREQUAL "Native") add_subdirectory(tools) +endif() + +if(NOSTALGIA_BUILD_STUDIO) add_subdirectory(studio) endif() diff --git a/src/nostalgia/core/gba/gfx.cpp b/src/nostalgia/core/gba/gfx.cpp index 27dbff09..02ccab73 100644 --- a/src/nostalgia/core/gba/gfx.cpp +++ b/src/nostalgia/core/gba/gfx.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include "../media.hpp" @@ -24,8 +25,8 @@ using namespace ox; #define TILE_ADDR ((CharBlock*) 0x06000000) #define TILE8_ADDR ((CharBlock8*) 0x06000000) -const auto GBA_TILE_COLUMNS = 32; -const auto GBA_TILE_ROWS = 32; +constexpr auto GBA_TILE_COLUMNS = 32; +constexpr auto GBA_TILE_ROWS = 32; // map ASCII values to the nostalgia charset static char charMap[128] = { @@ -159,22 +160,22 @@ static char charMap[128] = { }; struct GbaPaletteTarget { - uint16_t *palette = nullptr; + volatile uint16_t *palette = nullptr; }; struct GbaTileMapTarget { static constexpr auto Fields = 4; - uint8_t bpp = 0; + volatile uint32_t *bgCtl = nullptr; ox::FileAddress defaultPalette; GbaPaletteTarget pal; - uint16_t *tileMap = nullptr; + volatile uint16_t *tileMap = nullptr; }; template ox::Error modelRead(T *io, GbaPaletteTarget *t) { io->setTypeInfo("nostalgia::core::NostalgiaPalette", NostalgiaPalette::Fields); - oxReturnError(io->template field("colors", [t](auto i, uint16_t c) { - t->palette[i] = c; + oxReturnError(io->template field("colors", [t](auto i, Color *c) { + t->palette[i] = *c; return OxError(0); })); return OxError(0); @@ -183,20 +184,27 @@ ox::Error modelRead(T *io, GbaPaletteTarget *t) { template ox::Error modelRead(T *io, GbaTileMapTarget *t) { io->setTypeInfo("nostalgia::core::NostalgiaGraphic", NostalgiaGraphic::Fields); - oxReturnError(io->field("bpp", &t->bpp)); + + uint8_t bpp; + oxReturnError(io->field("bpp", &bpp)); + constexpr auto Bpp8 = 1 << 7; + *t->bgCtl = (*t->bgCtl | Bpp8) ^ Bpp8; // set to use 4 bits per pixel + *t->bgCtl |= Bpp8; // set to use 8 bits per pixel + *t->bgCtl = (28 << 8) | 1; + oxReturnError(io->field("defaultPalette", &t->defaultPalette)); oxReturnError(io->field("pal", &t->pal)); - uint16_t intermediate; - oxReturnError(io->template field("tileMap", [t, &intermediate](auto i, uint8_t tile) { + uint16_t intermediate = 0; + auto err = io->template field("tileMap", [t, &intermediate](auto i, uint8_t *tile) { if (i & 1) { // i is odd - intermediate |= tile >> 8; + intermediate |= static_cast(*tile) << 8; t->tileMap[i / 2] = intermediate; } else { // i is even - intermediate = tile & 0xff; + intermediate = *tile & 0x00ff; } return OxError(0); - })); - return OxError(0); + }); + return OxError(err); } ox::Error initGfx(Context*) { @@ -214,75 +222,58 @@ ox::Error shutdownGfx() { return OxError(0); } -// Do NOT use Context in the GBA version of this function. -ox::Error initConsole(Context*) { - const auto PaletteStart = sizeof(GbaImageDataHeader); - ox::Error err(0); - ox::FileStore32 fs(loadRom(), 32 * ox::units::MB); - ox::FileSystem32 fileSystem(fs); - const auto CharsetInode = fileSystem.stat("/TileSheets/Charset.ng").value.inode; - - GbaImageDataHeader imgData; - - REG_BG0CNT = (28 << 8) | 1; - if (fs.valid()) { - // load the header - err |= fs.read(CharsetInode, 0, sizeof(imgData), &imgData, nullptr); - - // load palette - err |= fs.read(CharsetInode, PaletteStart, - 512, (uint16_t*) &MEM_PALLETE_BG[0], nullptr); - - if (imgData.bpp == 4) { - err |= fs.read(CharsetInode, __builtin_offsetof(GbaImageData, tiles), - sizeof(Tile) * imgData.tileCount, (uint16_t*) &TILE_ADDR[0][1], nullptr); - } else if (imgData.bpp == 8) { - REG_BG0CNT |= (1 << 7); // set to use 8 bits per pixel - err |= fs.read(CharsetInode, __builtin_offsetof(GbaImageData, tiles), - sizeof(Tile8) * imgData.tileCount, (uint16_t*) &TILE8_ADDR[0][1], nullptr); - } else { - err = OxError(1); - } - } else { - err = OxError(1); +[[nodiscard]] constexpr volatile uint32_t &bgCtl(int bg) noexcept { + switch (bg) { + case 0: + return REG_BG0CNT; + case 1: + return REG_BG1CNT; + case 2: + return REG_BG2CNT; + case 3: + return REG_BG3CNT; + default: + panic("Looking up non-existent register"); + return REG_BG0CNT; } - return err; } -ox::Error loadTileSheet(Context*, - TileSheetSpace, - int, - ox::FileAddress tilesheetPath, - ox::FileAddress) { - auto inode = tilesheetPath.getInode().value; - ox::Error err(0); - constexpr auto PaletteStart = sizeof(GbaImageDataHeader); - GbaImageDataHeader imgData; - - ox::FileStore32 fs(loadRom(), 32 * 1024 * 1024); - REG_BG0CNT = (28 << 8) | 1; - if (fs.valid()) { - // load the header - err |= fs.read(inode, 0, sizeof(imgData), &imgData, nullptr); - - // load palette - err |= fs.read(inode, PaletteStart, - 512, (uint16_t*) &MEM_PALLETE_BG[0], nullptr); - - if (imgData.bpp == 4) { - err |= fs.read(inode, __builtin_offsetof(GbaImageData, tiles), - sizeof(Tile) * imgData.tileCount, (uint16_t*) &TILE_ADDR[0][1], nullptr); - } else if (imgData.bpp == 8) { - REG_BG0CNT |= (1 << 7); // set to use 8 bits per pixel - err |= fs.read(inode, __builtin_offsetof(GbaImageData, tiles), - sizeof(Tile8) * imgData.tileCount, (uint16_t*) &TILE8_ADDR[0][1], nullptr); - } else { - err = OxError(1); - } - } else { - err = OxError(1); +// Do NOT rely on Context in the GBA version of this function. +ox::Error initConsole(Context *ctx) { + constexpr auto TilesheetAddr = "/TileSheets/Charset.ng"; + constexpr auto PaletteAddr = "/Palettes/Charset.npal"; + if (!ctx) { + ctx = new (ox_alloca(sizeof(Context))) Context(); + ox::FileStore32 fs(loadRom(), 32 * ox::units::MB); + ctx->rom = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs); } - return err; + return loadTileSheet(ctx, TileSheetSpace::Background, 0, TilesheetAddr, PaletteAddr); +} + +ox::Error loadTileSheet(Context *ctx, + TileSheetSpace, + int section, + ox::FileAddress tilesheetAddr, + ox::FileAddress paletteAddr) { + auto [tsStat, tsStatErr] = ctx->rom->stat(tilesheetAddr); + oxReturnError(tsStatErr); + auto [ts, tserr] = ctx->rom->read(tilesheetAddr); + oxReturnError(tserr); + GbaTileMapTarget target; + target.pal.palette = &MEM_PALLETE_BG[section]; + target.bgCtl = &bgCtl(section); + target.tileMap = reinterpret_cast(&TILE_ADDR[section][0]); + oxReturnError(ox::readMC(ts, tsStat.size, &target)); + // load external palette if available + if (paletteAddr) { + auto [palStat, palStatErr] = ctx->rom->stat(paletteAddr); + oxReturnError(palStatErr); + auto [pal, palErr] = ctx->rom->read(paletteAddr); + oxReturnError(palErr); + oxReturnError(ox::readMC(pal, palStat.size, &target.pal)); + } + + return OxError(0); } // Do NOT use Context in the GBA version of this function. diff --git a/src/nostalgia/player/CMakeLists.txt b/src/nostalgia/player/CMakeLists.txt index f381bfa3..9676bb7d 100644 --- a/src/nostalgia/player/CMakeLists.txt +++ b/src/nostalgia/player/CMakeLists.txt @@ -1,4 +1,3 @@ - add_executable( nostalgia main.cpp diff --git a/src/nostalgia/player/main.cpp b/src/nostalgia/player/main.cpp index 5d864446..7ad0da2b 100644 --- a/src/nostalgia/player/main.cpp +++ b/src/nostalgia/player/main.cpp @@ -16,11 +16,13 @@ using namespace nostalgia::world; ox::Error run(ox::FileSystem *fs) { Context ctx; - oxReturnError(init(&ctx)); ctx.rom = fs; - Zone zone; - oxReturnError(zone.init(&ctx, Bounds{0, 0, 40, 40}, "/TileSheets/Charset.ng", "/Palettes/Charset.npal")); - zone.draw(&ctx); + oxReturnError(init(&ctx)); + //Zone zone; + //oxReturnError(zone.init(&ctx, Bounds{0, 0, 40, 40}, "/TileSheets/Charset.ng", "/Palettes/Charset.npal")); + //zone.draw(&ctx); + oxReturnError(initConsole(&ctx)); + puts(nullptr, 9 * 32 + 10, "DOPENESS!!!"); oxReturnError(run()); oxReturnError(shutdownGfx()); return OxError(0); @@ -28,9 +30,14 @@ ox::Error run(ox::FileSystem *fs) { #ifndef OX_USE_STDLIB -extern "C" void _start() { - ox::FileSystem32 fs(ox::FileStore32(loadRom(), 32 * ox::units::MB)); +int main() { + auto rom = loadRom(); + if (!rom) { + return 1; + } + ox::FileSystem32 fs(ox::FileStore32(rom, 32 * ox::units::MB)); run(&fs); + return 0; } #else diff --git a/src/nostalgia/player/startup.s b/src/nostalgia/player/startup.s index f26cfb3c..cf91eb47 100644 --- a/src/nostalgia/player/startup.s +++ b/src/nostalgia/player/startup.s @@ -1,9 +1,39 @@ + .section ".crt0","ax" + .global _start + .align -_entry: + .arm + .cpu arm7tdmi + +_start: + // disable interrupts + //cpsid if + b _reset + .fill 156,1,0 // make room for Nintendo logo + .fill 16,1,0 + .byte 0x30,0x31 -reset: - @ disable interrupts - @ cpsid if +_initCpp: + // copy data + ldr r0,=__data_lma + ldr r1,=__data_start__ + ldr r2,=__data_end__ + // loop over data until copied +data_copy_loop: + cmp r1,r2 + ldmltia r0!,{r3} + stmltia r1!,{r3} + blt data_copy_loop -@ vim:ft=arm +_reset: + ldr r0,=_reset + ldr r1,=_initCpp + mov lr,r1 + ldr sp,=__ewram_end + b _initCpp + + .size _start, . - _start + .end + +// vim:ft=arm diff --git a/src/nostalgia/tools/CMakeLists.txt b/src/nostalgia/tools/CMakeLists.txt index ac4eddd2..f3f080dd 100644 --- a/src/nostalgia/tools/CMakeLists.txt +++ b/src/nostalgia/tools/CMakeLists.txt @@ -1,6 +1,3 @@ -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) - add_executable(nost-pack pack.cpp) target_link_libraries( diff --git a/src/nostalgia/tools/pack.cpp b/src/nostalgia/tools/pack.cpp index d5a614c6..2e0cf1db 100644 --- a/src/nostalgia/tools/pack.cpp +++ b/src/nostalgia/tools/pack.cpp @@ -66,21 +66,21 @@ using namespace nostalgia::common; oxReturnError(ox::FileSystem32::format(buff.data(), buff.size())); ox::PassThroughFS src(argSrc.c_str()); ox::FileSystem32 dst(ox::FileStore32(buff.data(), buff.size())); - auto err = nostalgia::pack(&src, &dst); - if (err) { - std::cerr << "pack failed..."; - } + oxReturnError(nostalgia::pack(&src, &dst)); oxReturnError(dst.resize()); std::cout << "new size: " << dst.size() << '\n'; buff.resize(dst.size()); oxReturnError(writeFileBuff(argDst, buff)); - return err; + return OxError(0); } int main(int argc, const char **args) { auto err = run(ClArgs(argc, args)); oxAssert(err, "pack failed"); + if (err) { + std::cerr << "pack failed...\n"; + } return static_cast(err); } diff --git a/src/nostalgia/tools/pack/pack.cpp b/src/nostalgia/tools/pack/pack.cpp index fa4f8245..ea66242e 100644 --- a/src/nostalgia/tools/pack/pack.cpp +++ b/src/nostalgia/tools/pack/pack.cpp @@ -39,6 +39,7 @@ namespace { // transformations need to be done after the copy to the new FS is complete [[nodiscard]] ox::Error transformClaw(ox::FileSystem32 *dest, std::string path) { // copy + oxTrace("pack::transformClaw") << "path:" << path.c_str(); return dest->ls(path.c_str(), [dest, path](const char *name, ox::InodeId_t) { auto [stat, err] = dest->stat(path.c_str()); oxReturnError(err); @@ -68,10 +69,16 @@ namespace { return OxError(buff == expected ? 0 : 1); } +struct VerificationPair { + std::string path; + std::vector buff; +}; + [[nodiscard]] ox::Error copy(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) { std::cout << "copying directory: " << path << '\n'; + std::vector verficationPairs; // copy - return src->ls(path.c_str(), [src, dest, path](const char *name, ox::InodeId_t) { + oxReturnError(src->ls(path.c_str(), [&verficationPairs, src, dest, path](const char *name, ox::InodeId_t) { std::cout << "reading " << name << '\n'; auto currentFile = path + name; auto [stat, err] = src->stat((currentFile).c_str()); @@ -90,16 +97,26 @@ namespace { std::cout << "writing " << currentFile << '\n'; oxReturnError(dest->write(currentFile.c_str(), buff.data(), buff.size())); oxReturnError(verifyFile(dest, currentFile, buff)); + verficationPairs.push_back({currentFile, buff}); } return OxError(0); - }); -} + })); -} + // verify all at once in addition to right after the files are written + for (auto v : verficationPairs) { + oxReturnError(verifyFile(dest, v.path, v.buff)); + } -[[nodiscard]] ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path) { - oxReturnError(copy(src, dest, path)); - oxReturnError(transformClaw(dest, path)); + return OxError(0); +} + +} + +[[nodiscard]] ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest) { + oxReturnError(copy(src, dest, "/")); + oxReturnError(dest->stat("/TileSheets/Charset.ng").error); + oxReturnError(dest->stat("/Palettes/Charset.npal").error); + oxReturnError(transformClaw(dest, "/")); return OxError(0); } diff --git a/src/nostalgia/tools/pack/pack.hpp b/src/nostalgia/tools/pack/pack.hpp index d81cee6a..7ead6b1a 100644 --- a/src/nostalgia/tools/pack/pack.hpp +++ b/src/nostalgia/tools/pack/pack.hpp @@ -12,6 +12,6 @@ namespace nostalgia { -ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest, std::string path = "/"); +ox::Error pack(ox::PassThroughFS *src, ox::FileSystem32 *dest); }