| @@ -0,0 +1,129 @@ | ||
| +/* Copyright (c) 2013-2017 Jeffrey Pfau | ||
| + * | ||
| + * 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/. */ | ||
| +#include <mgba/internal/gb/renderers/cache-set.h> | ||
| + | ||
| +#include <mgba/core/cache-set.h> | ||
| +#include <mgba/internal/gb/gb.h> | ||
| +#include <mgba/internal/gb/io.h> | ||
| +#include <mgba/internal/gb/video.h> | ||
| + | ||
| +void GBVideoCacheInit(struct mCacheSet* cache) { | ||
| + mCacheSetInit(cache, 2, 1); | ||
| + mTileCacheConfiguration config = 0; | ||
| + config = mTileCacheSystemInfoSetPaletteBPP(config, 1); // 2^(2^1) = 4 entries | ||
| + config = mTileCacheSystemInfoSetPaletteCount(config, 4); // 16 palettes | ||
| + config = mTileCacheSystemInfoSetMaxTiles(config, 1024); | ||
| + mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0)); | ||
| + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), config, 0, 0); | ||
| + | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0)); | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1)); | ||
| + mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| +} | ||
| + | ||
| +void GBVideoCacheAssociate(struct mCacheSet* cache, struct GBVideo* video) { | ||
| + mCacheSetAssignVRAM(cache, video->vram); | ||
| + video->renderer->cache = cache; | ||
| + size_t i; | ||
| + for (i = 0; i < 64; ++i) { | ||
| + mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i])); | ||
| + } | ||
| + mMapCacheSystemInfo sysconfig = mMapCacheSystemInfoSetPaletteCount(0, 0); | ||
| + if (video->p->model >= GB_MODEL_CGB) { | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteCount(0, 2); | ||
| + } | ||
| + mMapCacheConfigureSystem(mMapCacheSetGetPointer(&cache->maps, 0), sysconfig); | ||
| + mMapCacheConfigureSystem(mMapCacheSetGetPointer(&cache->maps, 1), sysconfig); | ||
| + | ||
| + GBVideoCacheWriteVideoRegister(cache, REG_LCDC, video->p->memory.io[REG_LCDC]); | ||
| +} | ||
| + | ||
| +static void mapParserDMG0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + int map = *(uint8_t*) vram; | ||
| + entry->tileId = map; | ||
| + entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, 0); | ||
| +} | ||
| + | ||
| +static void mapParserDMG1(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + int map = *(int8_t*) vram; | ||
| + entry->tileId = map + 128; | ||
| + entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, 0); | ||
| +} | ||
| + | ||
| +static void mapParserCGB0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + int map = *(uint8_t*) vram; | ||
| + uint8_t attr = ((uint8_t*) vram)[0x2000]; | ||
| + entry->tileId = map + GBObjAttributesGetBank(attr) * 512; | ||
| + entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBObjAttributesGetXFlip(attr)); | ||
| + entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, GBObjAttributesGetYFlip(attr)); | ||
| + entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBObjAttributesGetCGBPalette(attr)); | ||
| +} | ||
| + | ||
| +static void mapParserCGB1(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + int map = *(int8_t*) vram; | ||
| + uint8_t attr = ((uint8_t*) vram)[0x2000]; | ||
| + entry->tileId = map + 128 + GBObjAttributesGetBank(attr) * 512; | ||
| + entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBObjAttributesGetXFlip(attr)); | ||
| + entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, GBObjAttributesGetYFlip(attr)); | ||
| + entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBObjAttributesGetCGBPalette(attr)); | ||
| +} | ||
| + | ||
| +void GBVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint16_t address, uint8_t value) { | ||
| + if (address != REG_LCDC) { | ||
| + return; | ||
| + } | ||
| + struct mMapCache* map = mMapCacheSetGetPointer(&cache->maps, 0); | ||
| + struct mMapCache* window = mMapCacheSetGetPointer(&cache->maps, 1); | ||
| + | ||
| + mMapCacheSystemInfo sysconfig = mMapCacheSystemInfoIsPaletteCount(map->sysConfig); | ||
| + int tileStart = 0; | ||
| + int mapStart = GB_BASE_MAP; | ||
| + int windowStart = GB_BASE_MAP; | ||
| + if (GBRegisterLCDCIsTileMap(value)) { | ||
| + mapStart += GB_SIZE_MAP; | ||
| + } | ||
| + if (GBRegisterLCDCIsWindowTileMap(value)) { | ||
| + windowStart += GB_SIZE_MAP; | ||
| + } | ||
| + if (GBRegisterLCDCIsTileData(value)) { | ||
| + if (!sysconfig) { | ||
| + map->mapParser = mapParserDMG0; | ||
| + window->mapParser = mapParserDMG0; | ||
| + } else { | ||
| + map->mapParser = mapParserCGB0; | ||
| + window->mapParser = mapParserCGB0; | ||
| + } | ||
| + } else { | ||
| + if (!sysconfig) { | ||
| + map->mapParser = mapParserDMG1; | ||
| + window->mapParser = mapParserDMG1; | ||
| + } else { | ||
| + map->mapParser = mapParserCGB1; | ||
| + window->mapParser = mapParserCGB1; | ||
| + } | ||
| + tileStart = 0x80; | ||
| + } | ||
| + map->tileStart = tileStart; | ||
| + window->tileStart = tileStart; | ||
| + sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5); | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 1); | ||
| + sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0); | ||
| + sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, 5); | ||
| + sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, 5); | ||
| + mMapCacheConfigureSystem(map, sysconfig); | ||
| + mMapCacheConfigureSystem(window, sysconfig); | ||
| + mMapCacheConfigureMap(map, mapStart); | ||
| + mMapCacheConfigureMap(window, windowStart); | ||
| +} |
| @@ -1,27 +0,0 @@ | ||
| -/* Copyright (c) 2013-2016 Jeffrey Pfau | ||
| - * | ||
| - * 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/. */ | ||
| -#include <mgba/internal/gb/renderers/tile-cache.h> | ||
| - | ||
| -#include <mgba/core/tile-cache.h> | ||
| -#include <mgba/internal/gb/video.h> | ||
| -#include <mgba/internal/gb/renderers/tile-cache.h> | ||
| - | ||
| -void GBVideoTileCacheInit(struct mTileCache* cache) { | ||
| - mTileCacheInit(cache); | ||
| - mTileCacheConfiguration config = 0; | ||
| - config = mTileCacheSystemInfoSetPalette0BPP(config, 1); // 2^(2^2) = 4 entries | ||
| - config = mTileCacheSystemInfoSetPalette0Count(config, 4); // 16 palettes | ||
| - config = mTileCacheSystemInfoSetPalette1BPP(config, 0); // Disable | ||
| - config = mTileCacheSystemInfoSetPalette1Count(config, 0); // Disable | ||
| - config = mTileCacheSystemInfoSetMaxTiles(config, 1024); | ||
| - mTileCacheConfigureSystem(cache, config); | ||
| -} | ||
| - | ||
| -void GBVideoTileCacheAssociate(struct mTileCache* cache, struct GBVideo* video) { | ||
| - cache->vram = (uint16_t*) video->vram; | ||
| - cache->palette = video->palette; | ||
| - video->renderer->cache = cache; | ||
| -} |
| @@ -0,0 +1,233 @@ | ||
| +/* Copyright (c) 2013-2017 Jeffrey Pfau | ||
| + * | ||
| + * 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/. */ | ||
| +#include <mgba/internal/gb/sio/printer.h> | ||
| + | ||
| +#include <mgba/internal/gb/gb.h> | ||
| +#include <mgba/internal/gb/io.h> | ||
| + | ||
| + | ||
| +static bool GBPrinterInit(struct GBSIODriver* driver); | ||
| +static void GBPrinterDeinit(struct GBSIODriver* driver); | ||
| +static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value); | ||
| +static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value); | ||
| + | ||
| +void GBPrinterCreate(struct GBPrinter* printer) { | ||
| + printer->d.init = GBPrinterInit; | ||
| + printer->d.deinit = GBPrinterDeinit; | ||
| + printer->d.writeSB = GBPrinterWriteSB; | ||
| + printer->d.writeSC = GBPrinterWriteSC; | ||
| + printer->print = NULL; | ||
| +} | ||
| + | ||
| +bool GBPrinterInit(struct GBSIODriver* driver) { | ||
| + struct GBPrinter* printer = (struct GBPrinter*) driver; | ||
| + | ||
| + printer->checksum = 0; | ||
| + printer->command = 0; | ||
| + printer->remainingBytes = 0; | ||
| + printer->currentIndex = 0; | ||
| + printer->compression = false; | ||
| + printer->byte = 0; | ||
| + printer->next = GB_PRINTER_BYTE_MAGIC_0; | ||
| + printer->status = 0; | ||
| + printer->printWait = -1; | ||
| + | ||
| + printer->buffer = malloc(GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS / 2); | ||
| + | ||
| + return true; | ||
| +} | ||
| + | ||
| +void GBPrinterDeinit(struct GBSIODriver* driver) { | ||
| + struct GBPrinter* printer = (struct GBPrinter*) driver; | ||
| + free(printer->buffer); | ||
| +} | ||
| + | ||
| +static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value) { | ||
| + struct GBPrinter* printer = (struct GBPrinter*) driver; | ||
| + printer->byte = value; | ||
| +} | ||
| + | ||
| +static void _processByte(struct GBPrinter* printer) { | ||
| + switch (printer->command) { | ||
| + case GB_PRINTER_COMMAND_DATA: | ||
| + if (printer->currentIndex < GB_VIDEO_VERTICAL_PIXELS * GB_VIDEO_HORIZONTAL_PIXELS / 2) { | ||
| + printer->buffer[printer->currentIndex] = printer->byte; | ||
| + ++printer->currentIndex; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_COMMAND_PRINT: | ||
| + // TODO | ||
| + break; | ||
| + default: | ||
| + break; | ||
| + } | ||
| +} | ||
| + | ||
| +static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value) { | ||
| + struct GBPrinter* printer = (struct GBPrinter*) driver; | ||
| + if ((value & 0x81) == 0x81) { | ||
| + switch (printer->next) { | ||
| + driver->p->pendingSB = 0; | ||
| + case GB_PRINTER_BYTE_MAGIC_0: | ||
| + if (printer->byte == 0x88) { | ||
| + printer->next = GB_PRINTER_BYTE_MAGIC_1; | ||
| + } else { | ||
| + printer->next = GB_PRINTER_BYTE_MAGIC_0; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_MAGIC_1: | ||
| + if (printer->byte == 0x33) { | ||
| + printer->next = GB_PRINTER_BYTE_COMMAND; | ||
| + } else { | ||
| + printer->next = GB_PRINTER_BYTE_MAGIC_0; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_COMMAND: | ||
| + printer->checksum = printer->byte; | ||
| + printer->command = printer->byte; | ||
| + printer->next = GB_PRINTER_BYTE_COMPRESSION; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_COMPRESSION: | ||
| + printer->checksum += printer->byte; | ||
| + printer->compression = printer->byte; | ||
| + printer->next = GB_PRINTER_BYTE_LENGTH_0; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_LENGTH_0: | ||
| + printer->checksum += printer->byte; | ||
| + printer->remainingBytes = printer->byte; | ||
| + printer->next = GB_PRINTER_BYTE_LENGTH_1; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_LENGTH_1: | ||
| + printer->checksum += printer->byte; | ||
| + printer->remainingBytes |= printer->byte << 8; | ||
| + if (printer->remainingBytes) { | ||
| + printer->next = GB_PRINTER_BYTE_DATA; | ||
| + } else { | ||
| + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; | ||
| + } | ||
| + switch (printer->command) { | ||
| + case GB_PRINTER_COMMAND_INIT: | ||
| + printer->currentIndex = 0; | ||
| + printer->status &= ~(GB_PRINTER_STATUS_PRINT_REQ | GB_PRINTER_STATUS_READY); | ||
| + break; | ||
| + default: | ||
| + break; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_DATA: | ||
| + printer->checksum += printer->byte; | ||
| + if (!printer->compression) { | ||
| + _processByte(printer); | ||
| + } else { | ||
| + printer->next = printer->byte & 0x80 ? GB_PRINTER_BYTE_COMPRESSED_DATUM : GB_PRINTER_BYTE_UNCOMPRESSED_DATA; | ||
| + printer->remainingCmpBytes = (printer->byte & 0x7F) + 1; | ||
| + if (printer->byte & 0x80) { | ||
| + ++printer->remainingCmpBytes; | ||
| + } | ||
| + } | ||
| + --printer->remainingBytes; | ||
| + if (!printer->remainingBytes) { | ||
| + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_UNCOMPRESSED_DATA: | ||
| + printer->checksum += printer->byte; | ||
| + _processByte(printer); | ||
| + --printer->remainingCmpBytes; | ||
| + if (!printer->remainingCmpBytes) { | ||
| + printer->next = GB_PRINTER_BYTE_DATA; | ||
| + } | ||
| + --printer->remainingBytes; | ||
| + if (!printer->remainingBytes) { | ||
| + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_COMPRESSED_DATUM: | ||
| + printer->checksum += printer->byte; | ||
| + while (printer->remainingCmpBytes) { | ||
| + _processByte(printer); | ||
| + --printer->remainingCmpBytes; | ||
| + } | ||
| + --printer->remainingBytes; | ||
| + if (!printer->remainingBytes) { | ||
| + printer->next = GB_PRINTER_BYTE_CHECKSUM_0; | ||
| + } else { | ||
| + printer->next = GB_PRINTER_BYTE_DATA; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_BYTE_CHECKSUM_0: | ||
| + printer->checksum ^= printer->byte; | ||
| + printer->next = GB_PRINTER_BYTE_CHECKSUM_1; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_CHECKSUM_1: | ||
| + printer->checksum ^= printer->byte << 8; | ||
| + printer->next = GB_PRINTER_BYTE_KEEPALIVE; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_KEEPALIVE: | ||
| + driver->p->pendingSB = 0x81; | ||
| + printer->next = GB_PRINTER_BYTE_STATUS; | ||
| + break; | ||
| + case GB_PRINTER_BYTE_STATUS: | ||
| + switch (printer->command) { | ||
| + case GB_PRINTER_COMMAND_DATA: | ||
| + if (printer->currentIndex >= 0x280 && !(printer->status & GB_PRINTER_STATUS_CHECKSUM_ERROR)) { | ||
| + printer->status |= GB_PRINTER_STATUS_READY; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_COMMAND_PRINT: | ||
| + if (printer->currentIndex >= GB_VIDEO_HORIZONTAL_PIXELS * 2) { | ||
| + printer->printWait = 0; | ||
| + } | ||
| + break; | ||
| + case GB_PRINTER_COMMAND_STATUS: | ||
| + if (!printer->printWait) { | ||
| + printer->status &= ~GB_PRINTER_STATUS_READY; | ||
| + printer->status |= GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ; | ||
| + if (printer->print) { | ||
| + size_t y; | ||
| + for (y = 0; y < printer->currentIndex / (2 * GB_VIDEO_HORIZONTAL_PIXELS); ++y) { | ||
| + uint8_t lineBuffer[GB_VIDEO_HORIZONTAL_PIXELS * 2]; | ||
| + uint8_t* buffer = &printer->buffer[sizeof(lineBuffer) * y]; | ||
| + size_t i; | ||
| + for (i = 0; i < sizeof(lineBuffer); i += 2) { | ||
| + uint8_t ilo = buffer[i + 0x0]; | ||
| + uint8_t ihi = buffer[i + 0x1]; | ||
| + uint8_t olo = 0; | ||
| + uint8_t ohi = 0; | ||
| + olo |= ((ihi & 0x80) >> 0) | ((ilo & 0x80) >> 1); | ||
| + olo |= ((ihi & 0x40) >> 1) | ((ilo & 0x40) >> 2); | ||
| + olo |= ((ihi & 0x20) >> 2) | ((ilo & 0x20) >> 3); | ||
| + olo |= ((ihi & 0x10) >> 3) | ((ilo & 0x10) >> 4); | ||
| + ohi |= ((ihi & 0x08) << 4) | ((ilo & 0x08) << 3); | ||
| + ohi |= ((ihi & 0x04) << 3) | ((ilo & 0x04) << 2); | ||
| + ohi |= ((ihi & 0x02) << 2) | ((ilo & 0x02) << 1); | ||
| + ohi |= ((ihi & 0x01) << 1) | ((ilo & 0x01) << 0); | ||
| + lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) & ~1)] = olo; | ||
| + lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) | 1)] = ohi; | ||
| + } | ||
| + memcpy(buffer, lineBuffer, sizeof(lineBuffer)); | ||
| + } | ||
| + printer->print(printer, printer->currentIndex * 4 / GB_VIDEO_HORIZONTAL_PIXELS, printer->buffer); | ||
| + } | ||
| + } | ||
| + if (printer->printWait >= 0) { | ||
| + --printer->printWait; | ||
| + } | ||
| + default: | ||
| + break; | ||
| + } | ||
| + driver->p->pendingSB = printer->status; | ||
| + printer->next = GB_PRINTER_BYTE_MAGIC_0; | ||
| + break; | ||
| + } | ||
| + printer->byte = 0; | ||
| + } | ||
| + return value; | ||
| +} | ||
| + | ||
| +void GBPrinterDonePrinting(struct GBPrinter* printer) { | ||
| + printer->status &= ~GB_PRINTER_STATUS_PRINTING; | ||
| +} |
| @@ -1,20 +0,0 @@ | ||
| -/* Copyright (c) 2013-2016 Jeffrey Pfau | ||
| - * | ||
| - * 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/. */ | ||
| -#include "util/test/suite.h" | ||
| - | ||
| -M_TEST_SUITE_DECLARE(GBCore); | ||
| -M_TEST_SUITE_DECLARE(GBMBC); | ||
| -M_TEST_SUITE_DECLARE(GBMemory); | ||
| -M_TEST_SUITE_DECLARE(GBRTC); | ||
| - | ||
| -int TestRunGB(void) { | ||
| - int failures = 0; | ||
| - failures += M_TEST_SUITE_RUN(GBCore); | ||
| - failures += M_TEST_SUITE_RUN(GBMBC); | ||
| - failures += M_TEST_SUITE_RUN(GBMemory); | ||
| - failures += M_TEST_SUITE_RUN(GBRTC); | ||
| - return failures; | ||
| -} |
| @@ -1,12 +0,0 @@ | ||
| -/* Copyright (c) 2013-2016 Jeffrey Pfau | ||
| - * | ||
| - * 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/. */ | ||
| -#ifndef TEST_GB_H | ||
| -#define TEST_GB_H | ||
| -#include <mgba-util/common.h> | ||
| - | ||
| -int TestRunGB(void); | ||
| - | ||
| -#endif |
| @@ -0,0 +1,168 @@ | ||
| +/* Copyright (c) 2013-2017 Jeffrey Pfau | ||
| + * | ||
| + * 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/. */ | ||
| +#include <mgba/internal/gba/renderers/cache-set.h> | ||
| + | ||
| +#include <mgba/core/cache-set.h> | ||
| +#include <mgba/internal/gba/gba.h> | ||
| +#include <mgba/internal/gba/io.h> | ||
| +#include <mgba/internal/gba/video.h> | ||
| + | ||
| +void GBAVideoCacheInit(struct mCacheSet* cache) { | ||
| + mCacheSetInit(cache, 4, 4); | ||
| + mTileCacheSystemInfo sysconfig = 0; | ||
| + mTileCacheConfiguration config = mTileCacheConfigurationFillShouldStore(0); | ||
| + sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 2); // 2^(2^2) = 16 entries | ||
| + sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 4); // 16 palettes | ||
| + sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048); | ||
| + mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0)); | ||
| + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config); | ||
| + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), sysconfig, 0, 0); | ||
| + sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024); | ||
| + mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 2)); | ||
| + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 2), config); | ||
| + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 2), sysconfig, 0x10000, 0x100); | ||
| + | ||
| + sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 3); // 2^(2^3) = 256 entries | ||
| + sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 0); // 1 palettes | ||
| + sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048); | ||
| + mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 1)); | ||
| + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 1), config); | ||
| + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 1), sysconfig, 0, 0); | ||
| + sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024); | ||
| + mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 3)); | ||
| + mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 3), config); | ||
| + mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 3), sysconfig, 0x10000, 0x100); | ||
| + | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0)); | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1)); | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 2)); | ||
| + mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 3)); | ||
| +} | ||
| + | ||
| +void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) { | ||
| + mCacheSetAssignVRAM(cache, video->vram); | ||
| + video->renderer->cache = cache; | ||
| + size_t i; | ||
| + for (i = 0; i < SIZE_PALETTE_RAM / 2; ++i) { | ||
| + mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i])); | ||
| + } | ||
| + GBAVideoCacheWriteVideoRegister(cache, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]); | ||
| + GBAVideoCacheWriteVideoRegister(cache, REG_BG0CNT, video->p->memory.io[REG_BG0CNT >> 1]); | ||
| + GBAVideoCacheWriteVideoRegister(cache, REG_BG1CNT, video->p->memory.io[REG_BG1CNT >> 1]); | ||
| + GBAVideoCacheWriteVideoRegister(cache, REG_BG2CNT, video->p->memory.io[REG_BG2CNT >> 1]); | ||
| + GBAVideoCacheWriteVideoRegister(cache, REG_BG3CNT, video->p->memory.io[REG_BG3CNT >> 1]); | ||
| +} | ||
| + | ||
| +static void mapParser0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + uint16_t map = *(uint16_t*) vram; | ||
| + entry->tileId = GBA_TEXT_MAP_TILE(map); | ||
| + entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, !!GBA_TEXT_MAP_HFLIP(map)); | ||
| + entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, !!GBA_TEXT_MAP_VFLIP(map)); | ||
| + entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBA_TEXT_MAP_PALETTE(map)); | ||
| +} | ||
| + | ||
| +static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { | ||
| + UNUSED(cache); | ||
| + entry->tileId = *(uint8_t*) vram; | ||
| + entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags); | ||
| + entry->flags = mMapCacheEntryFlagsClearPaletteId(entry->flags); | ||
| +} | ||
| + | ||
| +static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) { | ||
| + switch (GBARegisterDISPCNTGetMode(value)) { | ||
| + case 0: | ||
| + default: | ||
| + mMapCacheSetGetPointer(&cache->maps, 0)->mapParser = mapParser0; | ||
| + mMapCacheSetGetPointer(&cache->maps, 1)->mapParser = mapParser0; | ||
| + mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser0; | ||
| + mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser0; | ||
| + | ||
| + mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + break; | ||
| + case 1: | ||
| + case 2: | ||
| + mMapCacheSetGetPointer(&cache->maps, 0)->mapParser = mapParser0; | ||
| + mMapCacheSetGetPointer(&cache->maps, 1)->mapParser = mapParser0; | ||
| + mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser2; | ||
| + mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser2; | ||
| + | ||
| + mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0); | ||
| + mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1); | ||
| + mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1); | ||
| + break; | ||
| + } | ||
| +} | ||
| + | ||
| +static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t value) { | ||
| + struct mMapCache* map = mMapCacheSetGetPointer(&cache->maps, bg); | ||
| + map->context = (void*) (uintptr_t) value; | ||
| + | ||
| + int tileStart = GBARegisterBGCNTGetCharBase(value) * 256; | ||
| + bool p = GBARegisterBGCNTGet256Color(value); | ||
| + int size = GBARegisterBGCNTGetSize(value); | ||
| + int tilesWide = 0; | ||
| + int tilesHigh = 0; | ||
| + mMapCacheSystemInfo sysconfig = 0; | ||
| + if (map->mapParser == mapParser0) { | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 2 + p); | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 4 * !p); | ||
| + sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5); | ||
| + sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 1); | ||
| + tilesWide = 5; | ||
| + tilesHigh = 5; | ||
| + if (size & 1) { | ||
| + ++tilesWide; | ||
| + } | ||
| + if (size & 2) { | ||
| + ++tilesHigh; | ||
| + } | ||
| + map->tileStart = tileStart * 2; | ||
| + } else if (map->mapParser == mapParser2) { | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 3); | ||
| + sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 0); | ||
| + sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 4 + size); | ||
| + sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0); | ||
| + | ||
| + tilesHigh = 4 + size; | ||
| + tilesWide = 4 + size; | ||
| + map->tileStart = tileStart; | ||
| + } | ||
| + sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, tilesHigh); | ||
| + sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, tilesWide); | ||
| + mMapCacheConfigureSystem(map, sysconfig); | ||
| + mMapCacheConfigureMap(map, GBARegisterBGCNTGetScreenBase(value) << 11); | ||
| +} | ||
| + | ||
| +void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value) { | ||
| + switch (address) { | ||
| + case REG_DISPCNT: | ||
| + GBAVideoCacheWriteDISPCNT(cache, value); | ||
| + GBAVideoCacheWriteBGCNT(cache, 0, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 0)->context); | ||
| + GBAVideoCacheWriteBGCNT(cache, 1, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 1)->context); | ||
| + GBAVideoCacheWriteBGCNT(cache, 2, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 2)->context); | ||
| + GBAVideoCacheWriteBGCNT(cache, 3, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 3)->context); | ||
| + break; | ||
| + case REG_BG0CNT: | ||
| + GBAVideoCacheWriteBGCNT(cache, 0, value); | ||
| + break; | ||
| + case REG_BG1CNT: | ||
| + GBAVideoCacheWriteBGCNT(cache, 1, value); | ||
| + break; | ||
| + case REG_BG2CNT: | ||
| + GBAVideoCacheWriteBGCNT(cache, 2, value); | ||
| + break; | ||
| + case REG_BG3CNT: | ||
| + GBAVideoCacheWriteBGCNT(cache, 3, value); | ||
| + break; | ||
| + | ||
| + } | ||
| +} |
| @@ -1,26 +0,0 @@ | ||
| -/* Copyright (c) 2013-2016 Jeffrey Pfau | ||
| - * | ||
| - * 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/. */ | ||
| -#include <mgba/internal/gba/renderers/tile-cache.h> | ||
| - | ||
| -#include <mgba/core/tile-cache.h> | ||
| -#include <mgba/internal/gba/video.h> | ||
| - | ||
| -void GBAVideoTileCacheInit(struct mTileCache* cache) { | ||
| - mTileCacheInit(cache); | ||
| - mTileCacheConfiguration config = 0; | ||
| - config = mTileCacheSystemInfoSetPalette0BPP(config, 2); // 2^(2^2) = 16 entries | ||
| - config = mTileCacheSystemInfoSetPalette0Count(config, 5); // 32 palettes | ||
| - config = mTileCacheSystemInfoSetPalette1BPP(config, 3); // 2^(2^3) = 256 entries | ||
| - config = mTileCacheSystemInfoSetPalette1Count(config, 1); // 2 palettes | ||
| - config = mTileCacheSystemInfoSetMaxTiles(config, 3072); | ||
| - mTileCacheConfigureSystem(cache, config); | ||
| -} | ||
| - | ||
| -void GBAVideoTileCacheAssociate(struct mTileCache* cache, struct GBAVideo* video) { | ||
| - cache->vram = video->vram; | ||
| - cache->palette = video->palette; | ||
| - video->renderer->cache = cache; | ||
| -} |