View
@@ -0,0 +1,79 @@
+/* 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/. */
+#ifndef M_MAP_CACHE_H
+#define M_MAP_CACHE_H
+
+#include <mgba-util/common.h>
+
+CXX_GUARD_START
+
+#include <mgba/core/interface.h>
+#include <mgba/core/tile-cache.h>
+
+DECL_BITFIELD(mMapCacheConfiguration, uint32_t);
+DECL_BIT(mMapCacheConfiguration, ShouldStore, 0);
+
+DECL_BITFIELD(mMapCacheSystemInfo, uint32_t);
+DECL_BITS(mMapCacheSystemInfo, PaletteBPP, 0, 2);
+DECL_BITS(mMapCacheSystemInfo, PaletteCount, 2, 4);
+DECL_BITS(mMapCacheSystemInfo, TilesWide, 8, 4);
+DECL_BITS(mMapCacheSystemInfo, TilesHigh, 12, 4);
+DECL_BITS(mMapCacheSystemInfo, MacroTileSize, 16, 7);
+DECL_BITS(mMapCacheSystemInfo, MapAlign, 23, 2);
+
+DECL_BITFIELD(mMapCacheEntryFlags, uint16_t);
+DECL_BITS(mMapCacheEntryFlags, PaletteId, 0, 4);
+DECL_BIT(mMapCacheEntryFlags, VramClean, 4);
+DECL_BIT(mMapCacheEntryFlags, HMirror, 5);
+DECL_BIT(mMapCacheEntryFlags, VMirror, 6);
+DECL_BITS(mMapCacheEntryFlags, Mirror, 5, 2);
+
+struct mMapCacheEntry {
+ uint32_t vramVersion;
+ uint16_t tileId;
+ mMapCacheEntryFlags flags;
+ struct mTileCacheEntry tileStatus[16];
+};
+
+struct mTileCache;
+struct mTileCacheEntry;
+struct mMapCache {
+ color_t* cache;
+ struct mTileCache* tileCache;
+ struct mMapCacheEntry* status;
+
+ uint8_t* vram;
+
+ uint32_t mapStart;
+ uint32_t mapSize;
+
+ uint32_t tileStart;
+
+ mMapCacheConfiguration config;
+ mMapCacheSystemInfo sysConfig;
+
+ void (*mapParser)(struct mMapCache*, struct mMapCacheEntry* entry, void* vram);
+ void* context;
+};
+
+void mMapCacheInit(struct mMapCache* cache);
+void mMapCacheDeinit(struct mMapCache* cache);
+void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config);
+void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config);
+void mMapCacheConfigureMap(struct mMapCache* cache, uint32_t mapStart);
+void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address);
+
+uint32_t mMapCacheTileId(struct mMapCache* cache, unsigned x, unsigned y);
+
+bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y);
+void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y);
+
+void mMapCacheCleanRow(struct mMapCache* cache, unsigned y);
+const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y);
+
+CXX_GUARD_END
+
+#endif
View
@@ -34,6 +34,8 @@ struct mCoreThread {
ThreadCallback cleanCallback;
ThreadCallback frameCallback;
ThreadCallback sleepCallback;
+ ThreadCallback pauseCallback;
+ ThreadCallback unpauseCallback;
void* userData;
void (*run)(struct mCoreThread*);
@@ -50,13 +52,19 @@ enum mCoreThreadState {
THREAD_RUNNING = 0,
THREAD_REWINDING,
THREAD_MAX_RUNNING = THREAD_REWINDING,
+
+ THREAD_WAITING,
THREAD_INTERRUPTED,
- THREAD_INTERRUPTING,
THREAD_PAUSED,
+ THREAD_MAX_WAITING = THREAD_PAUSED,
+
THREAD_PAUSING,
THREAD_RUN_ON,
- THREAD_WAITING,
THREAD_RESETING,
+ THREAD_MIN_DEFERRED = THREAD_PAUSING,
+ THREAD_MAX_DEFERRED = THREAD_RESETING,
+
+ THREAD_INTERRUPTING,
THREAD_EXITING,
THREAD_SHUTDOWN,
THREAD_CRASHED
View
@@ -10,39 +10,37 @@
CXX_GUARD_START
+#include <mgba/core/interface.h>
+
DECL_BITFIELD(mTileCacheConfiguration, uint32_t);
DECL_BIT(mTileCacheConfiguration, ShouldStore, 0);
DECL_BITFIELD(mTileCacheSystemInfo, uint32_t);
-DECL_BITS(mTileCacheSystemInfo, Palette0BPP, 0, 2);
-DECL_BITS(mTileCacheSystemInfo, Palette0Count, 2, 4);
-DECL_BITS(mTileCacheSystemInfo, Palette1BPP, 8, 2);
-DECL_BITS(mTileCacheSystemInfo, Palette1Count, 10, 4);
+DECL_BITS(mTileCacheSystemInfo, PaletteBPP, 0, 2);
+DECL_BITS(mTileCacheSystemInfo, PaletteCount, 2, 4);
DECL_BITS(mTileCacheSystemInfo, MaxTiles, 16, 13);
struct mTileCacheEntry {
uint32_t paletteVersion;
uint32_t vramVersion;
uint8_t vramClean;
uint8_t paletteId;
- uint8_t activePalette;
- uint8_t padding;
+ uint16_t padding;
};
struct mTileCache {
- uint16_t* cache;
+ color_t* cache;
struct mTileCacheEntry* status;
- uint32_t* globalPaletteVersion[2];
+ uint32_t* globalPaletteVersion;
- int activePalette;
- unsigned entries;
- unsigned count;
+ uint32_t tileBase;
+ uint32_t paletteBase;
unsigned entriesPerTile;
unsigned bpp;
uint16_t* vram;
- uint16_t* palette;
- uint16_t temporaryTile[64];
+ color_t* palette;
+ color_t temporaryTile[64];
mTileCacheConfiguration config;
mTileCacheSystemInfo sysConfig;
@@ -51,15 +49,14 @@ struct mTileCache {
void mTileCacheInit(struct mTileCache* cache);
void mTileCacheDeinit(struct mTileCache* cache);
void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config);
-void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config);
+void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config, uint32_t tileBase, uint32_t paletteBase);
void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address);
-void mTileCacheWritePalette(struct mTileCache* cache, uint32_t address);
-void mTileCacheSetPalette(struct mTileCache* cache, int palette);
+void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t color);
-const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId);
-const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId);
-const uint8_t* mTileCacheGetRawTile(struct mTileCache* cache, unsigned tileId);
-const uint16_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId);
+const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId);
+const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId);
+const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId);
+const uint16_t* mTileCacheGetVRAM(struct mTileCache* cache, unsigned tileId);
CXX_GUARD_END
View
@@ -23,6 +23,7 @@ struct mTimingEvent {
struct mTiming {
struct mTimingEvent* root;
+ struct mTimingEvent* reroot;
uint32_t masterCycles;
int32_t* relativeCycles;
View
@@ -12,10 +12,12 @@ CXX_GUARD_START
enum GBModel {
GB_MODEL_AUTODETECT = 0xFF,
- GB_MODEL_DMG = 0x00,
- GB_MODEL_SGB = 0x40,
- GB_MODEL_CGB = 0x80,
- GB_MODEL_AGB = 0xC0
+ GB_MODEL_DMG = 0x00,
+ GB_MODEL_SGB = 0x20,
+ GB_MODEL_MGB = 0x40,
+ GB_MODEL_SGB2 = 0x60,
+ GB_MODEL_CGB = 0x80,
+ GB_MODEL_AGB = 0xC0
};
enum GBMemoryBankControllerType {
@@ -31,6 +33,7 @@ enum GBMemoryBankControllerType {
GB_HuC1 = 0x11,
GB_HuC3 = 0x12,
GB_POCKETCAM = 0x13,
+ GB_TAMA5 = 0x14,
GB_MBC3_RTC = 0x103,
GB_MBC5_RUMBLE = 0x105
};
@@ -44,6 +47,9 @@ struct GBSIODriver {
uint8_t (*writeSC)(struct GBSIODriver* driver, uint8_t value);
};
+enum GBModel GBNameToModel(const char*);
+const char* GBModelToName(enum GBModel);
+
CXX_GUARD_END
#endif
View
@@ -142,6 +142,7 @@ struct GBAudioNoiseChannel {
enum GBAudioStyle {
GB_AUDIO_DMG,
+ GB_AUDIO_MGB = GB_AUDIO_DMG, // TODO
GB_AUDIO_CGB,
GB_AUDIO_AGB, // GB in GBA
GB_AUDIO_GBA, // GBA PSG
View
@@ -44,6 +44,34 @@ enum GBIRQVector {
GB_VECTOR_KEYPAD = 0x60,
};
+enum GBSGBCommand {
+ SGB_PAL01 = 0,
+ SGB_PAL23,
+ SGB_PAL03,
+ SGB_PAL12,
+ SGB_ATTR_BLK,
+ SGB_ATTR_LIN,
+ SGB_ATTR_DIV,
+ SGB_ATTR_CHR,
+ SGB_SOUND,
+ SGB_SOU_TRN,
+ SGB_PAL_SET,
+ SGB_PAL_TRN,
+ SGB_ATRC_EN,
+ SGB_TEST_EN,
+ SGB_PICON_EN,
+ SGB_DATA_SND,
+ SGB_DATA_TRN,
+ SGB_MLT_REG,
+ SGB_JUMP,
+ SGB_CHR_TRN,
+ SGB_PCT_TRN,
+ SGB_ATTR_TRN,
+ SGB_ATTR_SET,
+ SGB_MASK_EN,
+ SGB_OBJ_TRN
+};
+
struct LR35902Core;
struct mCoreSync;
struct mAVStream;
@@ -76,6 +104,10 @@ struct GB {
int32_t sramDirtAge;
bool sramMaskWriteback;
+ int sgbBit;
+ int currentSgbBits;
+ uint8_t sgbPacket[16];
+
struct mCoreCallbacksList coreCallbacks;
struct mAVStream* stream;
View
@@ -19,8 +19,14 @@ struct GBMemory;
void GBMBCInit(struct GB* gb);
void GBMBCSwitchBank(struct GB* gb, int bank);
void GBMBCSwitchBank0(struct GB* gb, int bank);
+void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank);
void GBMBCSwitchSramBank(struct GB* gb, int bank);
+enum GBCam {
+ GBCAM_WIDTH = 128,
+ GBCAM_HEIGHT = 112
+};
+
struct GBMBCRTCSaveBuffer {
uint32_t sec;
uint32_t min;
@@ -37,8 +43,6 @@ struct GBMBCRTCSaveBuffer {
void GBMBCRTCRead(struct GB* gb);
void GBMBCRTCWrite(struct GB* gb);
-void GBMBC7Write(struct GBMemory*, uint16_t address, uint8_t value);
-
CXX_GUARD_END
#endif
View
@@ -22,6 +22,8 @@ struct GB;
enum {
GB_BASE_CART_BANK0 = 0x0000,
GB_BASE_CART_BANK1 = 0x4000,
+ GB_BASE_CART_HALFBANK1 = 0x4000,
+ GB_BASE_CART_HALFBANK2 = 0x6000,
GB_BASE_VRAM = 0x8000,
GB_BASE_EXTERNAL_RAM = 0xA000,
GB_BASE_WORKING_RAM_BANK0 = 0xC000,
@@ -46,6 +48,7 @@ enum {
enum {
GB_SIZE_CART_BANK0 = 0x4000,
+ GB_SIZE_CART_HALFBANK = 0x2000,
GB_SIZE_CART_MAX = 0x800000,
GB_SIZE_VRAM = 0x4000,
GB_SIZE_VRAM_BANK0 = 0x2000,
@@ -86,11 +89,29 @@ enum GBMBC7MachineState {
GBMBC7_STATE_EEPROM_ERASE = 0x1C,
};
+enum GBTAMA5Register {
+ GBTAMA5_BANK_LO = 0x0,
+ GBTAMA5_BANK_HI = 0x1,
+ GBTAMA5_WRITE_LO = 0x4,
+ GBTAMA5_WRITE_HI = 0x5,
+ GBTAMA5_CS = 0x6,
+ GBTAMA5_ADDR_LO = 0x7,
+ GBTAMA5_MAX = 0x8,
+ GBTAMA5_ACTIVE = 0xA,
+ GBTAMA5_READ_LO = 0xC,
+ GBTAMA5_READ_HI = 0xD,
+};
+
struct GBMBC1State {
int mode;
int multicartStride;
};
+struct GBMBC6State {
+ int currentBank1;
+ uint8_t* romBank1;
+};
+
struct GBMBC7State {
enum GBMBC7MachineState state;
uint16_t sr;
@@ -104,12 +125,20 @@ struct GBMBC7State {
struct GBPocketCamState {
bool registersActive;
+ uint8_t registers[0x36];
+};
+
+struct GBTAMA5State {
+ uint8_t reg;
+ uint8_t registers[GBTAMA5_MAX];
};
union GBMBCState {
struct GBMBC1State mbc1;
+ struct GBMBC6State mbc6;
struct GBMBC7State mbc7;
struct GBPocketCamState pocketCam;
+ struct GBTAMA5State tama5;
};
struct mRotationSource;
@@ -160,6 +189,7 @@ struct GBMemory {
struct mRTCSource* rtc;
struct mRotationSource* rotation;
struct mRumble* rumble;
+ struct mImageSource* cam;
};
struct LR35902Core;
View
@@ -17,7 +17,7 @@ struct GBCartridgeOverride {
enum GBModel model;
enum GBMemoryBankControllerType mbc;
- uint32_t gbColors[4];
+ uint32_t gbColors[12];
};
struct Configuration;
View
@@ -11,10 +11,12 @@
CXX_GUARD_START
struct GBVideo;
-struct mTileCache;
+struct mCacheSet;
-void GBVideoTileCacheInit(struct mTileCache* cache);
-void GBVideoTileCacheAssociate(struct mTileCache* cache, struct GBVideo* video);
+void GBVideoCacheInit(struct mCacheSet* cache);
+void GBVideoCacheAssociate(struct mCacheSet* cache, struct GBVideo* video);
+
+void GBVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint16_t address, uint8_t value);
CXX_GUARD_END
View
@@ -23,6 +23,7 @@ struct GBVideoSoftwareRenderer {
uint8_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8];
color_t palette[128];
+ uint8_t lookup[64];
uint32_t* temporaryBuffer;
@@ -34,6 +35,14 @@ struct GBVideoSoftwareRenderer {
GBRegisterLCDC lcdc;
enum GBModel model;
+
+ int sgbTransfer;
+ uint8_t sgbPacket[16];
+ uint8_t sgbCommandHeader;
+ int sgbPacketId;
+ int sgbDataSets;
+ uint8_t sgbPartialDataSet[15];
+ bool sgbBorders;
};
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
View
@@ -19,7 +19,7 @@ extern const uint32_t GB_SAVESTATE_VERSION;
mLOG_DECLARE_CATEGORY(GB_STATE);
/* Savestate format:
- * 0x00000 - 0x00003: Version Magic (0x01000001)
+ * 0x00000 - 0x00003: Version Magic (0x01000002)
* 0x00004 - 0x00007: ROM CRC32
* 0x00008: Game Boy model
* 0x00009 - 0x0000B: Reserved (leave zero)
@@ -42,7 +42,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | 0x00036 - 0x00037: Index address
* | 0x00038: Bus value
* | 0x00039: Execution state
- * | 0x0003A - 0x0003B: IRQ vector
+ * | 0x0003A - 0x0003B: Reserved
* | 0x0003C - 0x0003F: EI pending cycles
* | 0x00040 - 0x00043: Reserved (DI pending cycles)
* | 0x00044 - 0x00047: Flags
@@ -161,7 +161,22 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* 0x003FF: Interrupts enabled
* 0x00400 - 0x043FF: VRAM
* 0x04400 - 0x0C3FF: WRAM
- * Total size: 0xC400 (50,176) bytes
+ * 0x0C400 - 0x0C77F: Reserved
+ * 0x0C780 - 0x117FF: Super Game Boy
+ * | 0x0C780 - 0x0C7D9: Current attributes
+ * | 0x0C7DA: Current command
+ * | 0x0C7DB: Current bit count
+ * | 0x0C7DC - 0x0C7DF: Flags
+ * | bits 0 - 1: Current P1 bits
+ * | bits 2 - 3: Current render mode
+ * | bits 4 - 31: Reserved (leave 0)
+ * | 0x0C7E0 - 0x0C7EF: Current packet
+ * | 0x0C7F0 - 0x0C7FF: Reserved
+ * | 0x0C800 - 0x0E7FF: Character VRAM
+ * | 0x0E800 - 0x0F7FF: Tile map VRAM
+ * | 0x0F800 - 0x107FF: Palette VRAM
+ * | 0x10800 - 0x117FF: Attribute file
+ * Total size: 0x11800 (71,680) bytes
*/
DECL_BITFIELD(GBSerializedAudioFlags, uint32_t);
@@ -238,6 +253,10 @@ DECL_BIT(GBSerializedMemoryFlags, Ime, 3);
DECL_BIT(GBSerializedMemoryFlags, IsHdma, 4);
DECL_BITS(GBSerializedMemoryFlags, ActiveRtcReg, 5, 3);
+DECL_BITFIELD(GBSerializedSGBFlags, uint32_t);
+DECL_BITS(GBSerializedSGBFlags, P1Bits, 0, 2);
+DECL_BITS(GBSerializedSGBFlags, RenderMode, 2, 2);
+
#pragma pack(push, 1)
struct GBSerializedState {
uint32_t versionMagic;
@@ -268,7 +287,7 @@ struct GBSerializedState {
uint8_t bus;
uint8_t executionState;
- uint16_t irqVector;
+ uint16_t reserved;
uint32_t eiPending;
int32_t reservedDiPending;
@@ -366,6 +385,21 @@ struct GBSerializedState {
uint8_t vram[GB_SIZE_VRAM];
uint8_t wram[GB_SIZE_WORKING_RAM];
+
+ uint32_t reserved2[0xE0];
+
+ struct {
+ uint8_t attributes[90];
+ uint8_t command;
+ uint8_t bits;
+ GBSerializedSGBFlags flags;
+ uint8_t packet[16];
+ uint32_t reserved[4];
+ uint8_t charRam[SGB_SIZE_CHAR_RAM];
+ uint8_t mapRam[SGB_SIZE_MAP_RAM];
+ uint8_t palRam[SGB_SIZE_PAL_RAM];
+ uint8_t atfRam[SGB_SIZE_ATF_RAM];
+ } sgb;
};
#pragma pack(pop)
View
@@ -0,0 +1,74 @@
+/* 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/. */
+#ifndef GB_PRINTER_H
+#define GB_PRINTER_H
+
+#include <mgba-util/common.h>
+
+CXX_GUARD_START
+
+#include <mgba/gb/interface.h>
+
+enum GBPrinterPacketByte {
+ GB_PRINTER_BYTE_MAGIC_0,
+ GB_PRINTER_BYTE_MAGIC_1,
+ GB_PRINTER_BYTE_COMMAND,
+ GB_PRINTER_BYTE_COMPRESSION,
+ GB_PRINTER_BYTE_LENGTH_0,
+ GB_PRINTER_BYTE_LENGTH_1,
+ GB_PRINTER_BYTE_DATA,
+ GB_PRINTER_BYTE_CHECKSUM_0,
+ GB_PRINTER_BYTE_CHECKSUM_1,
+ GB_PRINTER_BYTE_KEEPALIVE,
+ GB_PRINTER_BYTE_STATUS,
+
+ GB_PRINTER_BYTE_COMPRESSED_DATUM,
+ GB_PRINTER_BYTE_UNCOMPRESSED_DATA
+};
+
+enum GBPrinterStatus {
+ GB_PRINTER_STATUS_CHECKSUM_ERROR = 0x01,
+ GB_PRINTER_STATUS_PRINTING = 0x02,
+ GB_PRINTER_STATUS_PRINT_REQ = 0x04,
+ GB_PRINTER_STATUS_READY = 0x08,
+ GB_PRINTER_STATUS_LOW_BATTERY = 0x10,
+ GB_PRINTER_STATUS_TIMEOUT = 0x20,
+ GB_PRINTER_STATUS_PAPER_JAM = 0x40,
+ GB_PRINTER_STATUS_TEMPERATURE_ISSUE = 0x80
+};
+
+enum GBPrinterCommand {
+ GB_PRINTER_COMMAND_INIT = 0x1,
+ GB_PRINTER_COMMAND_PRINT = 0x2,
+ GB_PRINTER_COMMAND_DATA = 0x4,
+ GB_PRINTER_COMMAND_STATUS = 0xF,
+};
+
+struct GBPrinter {
+ struct GBSIODriver d;
+
+ void (*print)(struct GBPrinter*, int height, const uint8_t* data);
+
+ uint8_t* buffer;
+ uint16_t checksum;
+ enum GBPrinterCommand command;
+ uint16_t remainingBytes;
+ uint8_t remainingCmpBytes;
+ unsigned currentIndex;
+ bool compression;
+
+ uint8_t byte;
+ enum GBPrinterPacketByte next;
+ uint8_t status;
+ int printWait;
+};
+
+void GBPrinterCreate(struct GBPrinter* printer);
+void GBPrinterDonePrinting(struct GBPrinter* printer);
+
+CXX_GUARD_END
+
+#endif
View
@@ -30,7 +30,12 @@ enum {
GB_VIDEO_TOTAL_LENGTH = 70224,
GB_BASE_MAP = 0x1800,
- GB_SIZE_MAP = 0x0400
+ GB_SIZE_MAP = 0x0400,
+
+ SGB_SIZE_CHAR_RAM = 0x2000,
+ SGB_SIZE_MAP_RAM = 0x1000,
+ SGB_SIZE_PAL_RAM = 0x1000,
+ SGB_SIZE_ATF_RAM = 0x1000
};
DECL_BITFIELD(GBObjAttributes, uint8_t);
@@ -41,6 +46,13 @@ DECL_BIT(GBObjAttributes, XFlip, 5);
DECL_BIT(GBObjAttributes, YFlip, 6);
DECL_BIT(GBObjAttributes, Priority, 7);
+DECL_BITFIELD(SGBBgAttributes, uint16_t);
+DECL_BITS(SGBBgAttributes, Tile, 0, 10);
+DECL_BITS(SGBBgAttributes, Palette, 10, 3);
+DECL_BIT(SGBBgAttributes, Priority, 13);
+DECL_BIT(SGBBgAttributes, XFlip, 14);
+DECL_BIT(SGBBgAttributes, YFlip, 15);
+
struct GBObj {
uint8_t y;
uint8_t x;
@@ -53,12 +65,13 @@ union GBOAM {
uint8_t raw[160];
};
-struct mTileCache;
+struct mCacheSet;
struct GBVideoRenderer {
- void (*init)(struct GBVideoRenderer* renderer, enum GBModel model);
+ void (*init)(struct GBVideoRenderer* renderer, enum GBModel model, bool borders);
void (*deinit)(struct GBVideoRenderer* renderer);
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
+ void (*writeSGBPacket)(struct GBVideoRenderer* renderer, uint8_t* data);
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value);
void (*writeOAM)(struct GBVideoRenderer* renderer, uint16_t oam);
@@ -71,7 +84,14 @@ struct GBVideoRenderer {
uint8_t* vram;
union GBOAM* oam;
- struct mTileCache* cache;
+ struct mCacheSet* cache;
+
+ uint8_t* sgbCharRam;
+ uint8_t* sgbMapRam;
+ uint8_t* sgbPalRam;
+ int sgbRenderMode;
+ uint8_t* sgbAttributes;
+ uint8_t* sgbAttributeFiles;
bool disableBG;
bool disableOBJ;
@@ -123,10 +143,13 @@ struct GBVideo {
bool bcpIncrement;
int ocpIndex;
bool ocpIncrement;
+ uint8_t sgbCommandHeader;
- uint16_t dmgPalette[4];
+ uint16_t dmgPalette[12];
uint16_t palette[64];
+ bool sgbBorders;
+
int32_t frameCounter;
int frameskip;
int frameskipCounter;
@@ -144,8 +167,11 @@ void GBVideoWriteLYC(struct GBVideo* video, uint8_t value);
void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value);
void GBVideoSwitchBank(struct GBVideo* video, uint8_t value);
+void GBVideoDisableCGB(struct GBVideo* video);
void GBVideoSetPalette(struct GBVideo* video, unsigned index, uint32_t color);
+void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data);
+
struct GBSerializedState;
void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state);
void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state);
View
@@ -67,10 +67,11 @@ enum {
SIZE_CART0 = 0x02000000,
SIZE_CART1 = 0x02000000,
SIZE_CART2 = 0x02000000,
- SIZE_CART_SRAM = 0x00010000,
+ SIZE_CART_SRAM = 0x00008000,
SIZE_CART_FLASH512 = 0x00010000,
SIZE_CART_FLASH1M = 0x00020000,
- SIZE_CART_EEPROM = 0x00002000
+ SIZE_CART_EEPROM = 0x00002000,
+ SIZE_CART_EEPROM512 = 0x00000200
};
enum {
View
@@ -28,7 +28,7 @@ void GBAOverrideSave(struct Configuration*, const struct GBACartridgeOverride* o
struct GBA;
void GBAOverrideApply(struct GBA*, const struct GBACartridgeOverride*);
-void GBAOverrideApplyDefaults(struct GBA*);
+void GBAOverrideApplyDefaults(struct GBA*, const struct Configuration*);
CXX_GUARD_END
View
@@ -3,18 +3,19 @@
* 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 GBA_TILE_CACHE_H
-#define GBA_TILE_CACHE_H
+#ifndef GBA_CACHE_SET_H
+#define GBA_CACHE_SET_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct GBAVideo;
-struct mTileCache;
+struct mCacheSet;
-void GBAVideoTileCacheInit(struct mTileCache* cache);
-void GBAVideoTileCacheAssociate(struct mTileCache* cache, struct GBAVideo* video);
+void GBAVideoCacheInit(struct mCacheSet* cache);
+void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video);
+void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value);
CXX_GUARD_END
View
@@ -11,6 +11,7 @@
CXX_GUARD_START
#include <mgba/core/core.h>
+#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/video.h>
struct GBAVideoSoftwareSprite {
@@ -167,6 +168,14 @@ struct GBAVideoSoftwareRenderer {
int bitmapStride;
bool combinedObjSort;
+ uint32_t scanlineDirty[5];
+ uint16_t nextIo[REG_SOUND1CNT_LO];
+ struct ScanlineCache {
+ uint16_t io[REG_SOUND1CNT_LO];
+ int32_t scale[2][2];
+ } cache[VIDEO_VERTICAL_PIXELS];
+ int nextY;
+
int start;
int end;
int masterEnd;
View
@@ -169,7 +169,7 @@ struct GBAVideoRenderer {
uint16_t* vramBG[32];
uint16_t* vramOBJ[32];
union GBAOAM* oam;
- struct mTileCache* cache;
+ struct mCacheSet* cache;
bool disableBG[4];
bool disableOBJ;
View
@@ -66,6 +66,7 @@ struct LR35902InterruptHandler {
void (*reset)(struct LR35902Core* cpu);
void (*processEvents)(struct LR35902Core* cpu);
void (*setInterrupts)(struct LR35902Core* cpu, bool enable);
+ uint16_t (*irqVector)(struct LR35902Core* cpu);
void (*halt)(struct LR35902Core* cpu);
void (*stop)(struct LR35902Core* cpu);
@@ -118,7 +119,6 @@ struct LR35902Core {
LR35902Instruction instruction;
bool irqPending;
- uint16_t irqVector;
struct LR35902Memory memory;
struct LR35902InterruptHandler irqh;
@@ -136,7 +136,7 @@ void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot);
void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot);
void LR35902Reset(struct LR35902Core* cpu);
-void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector);
+void LR35902RaiseIRQ(struct LR35902Core* cpu);
void LR35902Tick(struct LR35902Core* cpu);
void LR35902Run(struct LR35902Core* cpu);
View
Binary file not shown.
View
@@ -2,8 +2,8 @@ Jaime J. Denizard
Fog
Reilly Grant
Philip Horton
-Jordan Jorgensen
mars
+pr1ntf
Rohit Nirmal
Rhys Powell
rootfather
View
@@ -817,8 +817,9 @@ DEFINE_INSTRUCTION_ARM(MSR,
}
_ARMReadCPSR(cpu);
if (cpu->executionMode == MODE_THUMB) {
- LOAD_16(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & cpu->memory.activeMask, cpu->memory.activeRegion);
- LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
+ cpu->prefetch[0] = 0x46C0; // nop
+ cpu->prefetch[1] &= 0xFFFF;
+ cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
} else {
LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & cpu->memory.activeMask, cpu->memory.activeRegion);
LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
@@ -858,8 +859,9 @@ DEFINE_INSTRUCTION_ARM(MSRI,
}
_ARMReadCPSR(cpu);
if (cpu->executionMode == MODE_THUMB) {
- LOAD_16(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & cpu->memory.activeMask, cpu->memory.activeRegion);
- LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
+ cpu->prefetch[0] = 0x46C0; // nop
+ cpu->prefetch[1] &= 0xFFFF;
+ cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
} else {
LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & cpu->memory.activeMask, cpu->memory.activeRegion);
LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
View
@@ -0,0 +1,62 @@
+/* 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/core/cache-set.h>
+
+DEFINE_VECTOR(mMapCacheSet, struct mMapCache);
+DEFINE_VECTOR(mTileCacheSet, struct mTileCache);
+
+void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nTiles) {
+ mMapCacheSetInit(&cache->maps, nMaps);
+ mMapCacheSetResize(&cache->maps, nMaps);
+ mTileCacheSetInit(&cache->tiles, nTiles);
+ mTileCacheSetResize(&cache->tiles, nTiles);
+
+ size_t i;
+ for (i = 0; i < nMaps; ++i) {
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, i));
+ }
+ for (i = 0; i < nTiles; ++i) {
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, i));
+ }
+}
+
+void mCacheSetDeinit(struct mCacheSet* cache) {
+ size_t i;
+ for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
+ mMapCacheDeinit(mMapCacheSetGetPointer(&cache->maps, i));
+ }
+ for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
+ mTileCacheDeinit(mTileCacheSetGetPointer(&cache->tiles, i));
+ }
+}
+
+void mCacheSetAssignVRAM(struct mCacheSet* cache, void* vram) {
+ size_t i;
+ for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
+ mMapCacheSetGetPointer(&cache->maps, i)->vram = vram;
+ }
+ for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
+ struct mTileCache* tileCache = mTileCacheSetGetPointer(&cache->tiles, i);
+ tileCache->vram = (void*) ((uintptr_t) vram + tileCache->tileBase);
+ }
+}
+
+void mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
+ size_t i;
+ for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) {
+ mMapCacheWriteVRAM(mMapCacheSetGetPointer(&cache->maps, i), address);
+ }
+ for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
+ mTileCacheWriteVRAM(mTileCacheSetGetPointer(&cache->tiles, i), address);
+ }
+}
+
+void mCacheSetWritePalette(struct mCacheSet* cache, uint32_t entry, color_t color) {
+ size_t i;
+ for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) {
+ mTileCacheWritePalette(mTileCacheSetGetPointer(&cache->tiles, i), entry, color);
+ }
+}
View
@@ -256,35 +256,23 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
if (!cheats->enabled) {
return;
}
- bool condition = true;
- int conditionRemaining = 0;
- int negativeConditionRemaining = 0;
cheats->refresh(cheats, device);
+ size_t elseLoc = 0;
+ size_t endLoc = 0;
size_t nCodes = mCheatListSize(&cheats->list);
size_t i;
for (i = 0; i < nCodes; ++i) {
- if (conditionRemaining > 0) {
- --conditionRemaining;
- if (!condition) {
- continue;
- }
- } else if (negativeConditionRemaining > 0) {
- conditionRemaining = negativeConditionRemaining - 1;
- negativeConditionRemaining = 0;
- condition = !condition;
- if (!condition) {
- continue;
- }
- } else {
- condition = true;
- }
struct mCheat* cheat = mCheatListGetPointer(&cheats->list, i);
int32_t value = 0;
int32_t operand = cheat->operand;
uint32_t operationsRemaining = cheat->repeat;
uint32_t address = cheat->address;
bool performAssignment = false;
+ bool condition = true;
+ int conditionRemaining = 0;
+ int negativeConditionRemaining = 0;
+
for (; operationsRemaining; --operationsRemaining) {
switch (cheat->type) {
case CHEAT_ASSIGN:
@@ -312,46 +300,55 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
condition = _readMem(device->p, address, cheat->width) == operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_NE:
condition = _readMem(device->p, address, cheat->width) != operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_LT:
condition = _readMem(device->p, address, cheat->width) < operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_GT:
condition = _readMem(device->p, address, cheat->width) > operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_ULT:
condition = (uint32_t) _readMem(device->p, address, cheat->width) < (uint32_t) operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_UGT:
condition = (uint32_t) _readMem(device->p, address, cheat->width) > (uint32_t) operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_AND:
condition = _readMem(device->p, address, cheat->width) & operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_LAND:
condition = _readMem(device->p, address, cheat->width) && operand;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
case CHEAT_IF_NAND:
condition = !(_readMem(device->p, address, cheat->width) & operand);
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
break;
}
@@ -362,6 +359,18 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
address += cheat->addressOffset;
operand += cheat->operandOffset;
}
+
+
+ if (elseLoc && i == elseLoc) {
+ i = endLoc;
+ endLoc = 0;
+ }
+ if (conditionRemaining > 0 && !condition) {
+ i += conditionRemaining;
+ } else if (negativeConditionRemaining > 0) {
+ elseLoc = i + conditionRemaining;
+ endLoc = elseLoc + negativeConditionRemaining;
+ }
}
}
View
@@ -0,0 +1,205 @@
+/* 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/core/map-cache.h>
+
+#include <mgba-util/memory.h>
+
+void mMapCacheInit(struct mMapCache* cache) {
+ // TODO: Reconfigurable cache for space savings
+ cache->cache = NULL;
+ cache->config = mMapCacheConfigurationFillShouldStore(0);
+ cache->status = NULL;
+}
+
+static void _freeCache(struct mMapCache* cache) {
+ size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
+ mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles);
+ mappedMemoryFree(cache->status, tiles * sizeof(*cache->status));
+ cache->cache = NULL;
+ cache->status = NULL;
+}
+
+static void _redoCacheSize(struct mMapCache* cache) {
+ if (!mMapCacheConfigurationIsShouldStore(cache->config)) {
+ return;
+ }
+
+ size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
+ cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles);
+ cache->status = anonymousMemoryMap(tiles * sizeof(*cache->status));
+}
+
+void mMapCacheConfigure(struct mMapCache* cache, mMapCacheConfiguration config) {
+ if (config == cache->config) {
+ return;
+ }
+ _freeCache(cache);
+ cache->config = config;
+ _redoCacheSize(cache);
+}
+
+void mMapCacheConfigureSystem(struct mMapCache* cache, mMapCacheSystemInfo config) {
+ if (config == cache->sysConfig) {
+ return;
+ }
+ _freeCache(cache);
+ cache->sysConfig = config;
+ _redoCacheSize(cache);
+
+ size_t mapSize = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
+ cache->mapSize = mapSize << mMapCacheSystemInfoGetMapAlign(cache->sysConfig);
+}
+
+void mMapCacheConfigureMap(struct mMapCache* cache, uint32_t mapStart) {
+ size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
+ memset(cache->status, 0, tiles * sizeof(*cache->status));
+ cache->mapStart = mapStart;
+}
+
+void mMapCacheDeinit(struct mMapCache* cache) {
+ _freeCache(cache);
+}
+
+void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
+ if (address >= cache->mapStart && address < cache->mapStart + cache->mapSize) {
+ address -= cache->mapStart;
+ struct mMapCacheEntry* status = &cache->status[address >> mMapCacheSystemInfoGetMapAlign(cache->sysConfig)];
+ ++status->vramVersion;
+ status->flags = mMapCacheEntryFlagsClearVramClean(status->flags);
+ status->tileStatus[mMapCacheEntryFlagsGetPaletteId(status->flags)].vramClean = 0;
+ }
+}
+
+static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, color_t* mapOut, const struct mMapCacheEntry* status) {
+ size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ int x, y;
+ switch (mMapCacheEntryFlagsGetMirror(status->flags)) {
+ case 0:
+ memcpy(mapOut, tile, sizeof(color_t) * 8);
+ memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
+ break;
+ case 1:
+ for (y = 0; y < 8; ++y) {
+ for (x = 0; x < 8; ++x) {
+ mapOut[y * stride + (7 - x)] = tile[y * 8 + x];
+ }
+ }
+ break;
+ case 2:
+ memcpy(&mapOut[stride * 7], tile, sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(color_t) * 8);
+ memcpy(&mapOut[stride], &tile[0x30], sizeof(color_t) * 8);
+ memcpy(mapOut, &tile[0x38], sizeof(color_t) * 8);
+ break;
+ case 3:
+ for (y = 0; y < 8; ++y) {
+ for (x = 0; x < 8; ++x) {
+ mapOut[(7 - y) * stride + (7 - x)] = tile[y * 8 + x];
+ }
+ }
+ break;
+ }
+}
+
+uint32_t mMapCacheTileId(struct mMapCache* cache, unsigned x, unsigned y) {
+ int tilesWide = mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ int tilesHigh = mMapCacheSystemInfoGetTilesHigh(cache->sysConfig);
+ int stride = 1 << mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig);
+ x &= (1 << tilesWide) - 1;
+ y &= (1 << tilesHigh) - 1;
+ unsigned xMajor = x & ~(stride - 1);
+ unsigned yMajor = y >> mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig);
+ x &= stride - 1;
+ y &= stride - 1;
+ yMajor <<= tilesWide;
+ y += xMajor + yMajor;
+ return stride * y + x;
+}
+
+void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
+ size_t location = mMapCacheTileId(cache, x, y);
+ struct mMapCacheEntry* status = &cache->status[location];
+ const color_t* tile = NULL;
+ if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
+ status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
+ cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
+ }
+ unsigned tileId = status->tileId + cache->tileStart;
+ if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
+ tileId = 0;
+ }
+ tile = mTileCacheGetTileIfDirty(cache->tileCache, status->tileStatus, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
+ if (!tile) {
+ if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
+ return;
+ }
+ tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
+ }
+
+ size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ color_t* mapOut = &cache->cache[(y * stride + x) * 8];
+ _cleanTile(cache, tile, mapOut, status);
+ entry[location] = *status;
+}
+
+bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* entry, unsigned x, unsigned y) {
+ size_t location = mMapCacheTileId(cache, x, y);
+ struct mMapCacheEntry* status = &cache->status[location];
+ int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
+ const color_t* tile = NULL;
+ if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
+ unsigned tileId = status->tileId + cache->tileStart;
+ if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
+ tileId = 0;
+ }
+ tile = mTileCacheGetTileIfDirty(cache->tileCache, &status->tileStatus[paletteId], tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
+ return !tile;
+ }
+ return false;
+}
+
+void mMapCacheCleanRow(struct mMapCache* cache, unsigned y) {
+ // TODO: Cache
+ int tilesWide = 1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ int macroTile = (1 << mMapCacheSystemInfoGetMacroTileSize(cache->sysConfig)) - 1;
+ size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ int location = 0;
+ int x;
+ for (x = 0; x < tilesWide; ++x) {
+ if (!(x & macroTile)) {
+ location = mMapCacheTileId(cache, x, y);
+ } else {
+ ++location;
+ }
+ struct mMapCacheEntry* status = &cache->status[location];
+ if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
+ status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
+ cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
+ }
+ unsigned tileId = status->tileId + cache->tileStart;
+ if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
+ tileId = 0;
+ }
+ const color_t* tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
+ color_t* mapOut = &cache->cache[(y * stride + x) * 8];
+ _cleanTile(cache, tile, mapOut, status);
+ }
+}
+
+const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
+ size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
+ return &cache->cache[y * stride];
+}
View
@@ -407,11 +407,8 @@ void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtda
}
#endif
ssize_t stateSize = core->stateSize(core);
- vf->seek(vf, 0, SEEK_SET);
- if (vf->size(vf) < stateSize) {
- return false;
- }
void* state = anonymousMemoryMap(stateSize);
+ vf->seek(vf, 0, SEEK_SET);
if (vf->read(vf, state, stateSize) != stateSize) {
mappedMemoryFree(state, stateSize);
return 0;
View
@@ -34,9 +34,3 @@ M_TEST_SUITE_DEFINE(mCore,
#endif
cmocka_unit_test(findNullVF),
cmocka_unit_test(findEmpty))
-
-int TestRunCore(void) {
- int failures = 0;
- failures += M_TEST_SUITE_RUN(mCore);
- return failures;
-}
View
@@ -158,7 +158,6 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
};
core->addCoreCallbacks(core, &callbacks);
core->setSync(core, &threadContext->impl->sync);
- core->reset(core);
struct mLogFilter filter;
if (!threadContext->logger.d.filter) {
@@ -168,12 +167,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
mCoreThreadRewindParamsChanged(threadContext);
-
- _changeState(threadContext->impl, THREAD_RUNNING, true);
-
if (threadContext->startCallback) {
threadContext->startCallback(threadContext);
}
+
+ core->reset(core);
+ _changeState(threadContext->impl, THREAD_RUNNING, true);
+
if (threadContext->resetCallback) {
threadContext->resetCallback(threadContext);
}
@@ -195,38 +195,58 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
}
- int resetScheduled = 0;
+ enum mCoreThreadState deferred = THREAD_RUNNING;
MutexLock(&impl->stateMutex);
while (impl->state > THREAD_MAX_RUNNING && impl->state < THREAD_EXITING) {
- if (impl->state == THREAD_PAUSING) {
- impl->state = THREAD_PAUSED;
- ConditionWake(&impl->stateCond);
- }
+ deferred = impl->state;
+
if (impl->state == THREAD_INTERRUPTING) {
impl->state = THREAD_INTERRUPTED;
ConditionWake(&impl->stateCond);
}
- if (impl->state == THREAD_RUN_ON) {
- if (threadContext->run) {
- threadContext->run(threadContext);
- }
- impl->state = impl->savedState;
- ConditionWake(&impl->stateCond);
+
+ if (impl->state == THREAD_PAUSING) {
+ impl->state = THREAD_PAUSED;
}
if (impl->state == THREAD_RESETING) {
impl->state = THREAD_RUNNING;
- resetScheduled = 1;
}
- while (impl->state == THREAD_PAUSED || impl->state == THREAD_INTERRUPTED || impl->state == THREAD_WAITING) {
+
+ if (deferred >= THREAD_MIN_DEFERRED && deferred <= THREAD_MAX_DEFERRED) {
+ break;
+ }
+
+ deferred = impl->state;
+ while (impl->state >= THREAD_WAITING && impl->state <= THREAD_MAX_WAITING) {
ConditionWait(&impl->stateCond, &impl->stateMutex);
}
}
MutexUnlock(&impl->stateMutex);
- if (resetScheduled) {
+ switch (deferred) {
+ case THREAD_PAUSING:
+ if (threadContext->pauseCallback) {
+ threadContext->pauseCallback(threadContext);
+ }
+ break;
+ case THREAD_PAUSED:
+ if (threadContext->unpauseCallback) {
+ threadContext->unpauseCallback(threadContext);
+ }
+ break;
+ case THREAD_RUN_ON:
+ if (threadContext->run) {
+ threadContext->run(threadContext);
+ }
+ threadContext->impl->state = threadContext->impl->savedState;
+ break;
+ case THREAD_RESETING:
core->reset(core);
if (threadContext->resetCallback) {
threadContext->resetCallback(threadContext);
}
+ break;
+ default:
+ break;
}
}
View
@@ -12,60 +12,42 @@ void mTileCacheInit(struct mTileCache* cache) {
cache->cache = NULL;
cache->config = mTileCacheConfigurationFillShouldStore(0);
cache->status = NULL;
- cache->activePalette = 0;
- memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion));
+ cache->globalPaletteVersion = NULL;
+ cache->palette = NULL;
}
static void _freeCache(struct mTileCache* cache) {
- unsigned count0;
- count0 = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
- unsigned count1;
- count1 = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
+ unsigned size = 1 << mTileCacheSystemInfoGetPaletteCount(cache->sysConfig);
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
- unsigned size = count0 > count1 ? count0 : count1;
if (cache->cache) {
- mappedMemoryFree(cache->cache, 8 * 8 * 2 * tiles * size);
+ mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles * size);
cache->cache = NULL;
}
if (cache->status) {
mappedMemoryFree(cache->status, tiles * size * sizeof(*cache->status));
cache->status = NULL;
}
- free(cache->globalPaletteVersion[0]);
- free(cache->globalPaletteVersion[1]);
- memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion));
+ free(cache->globalPaletteVersion);
+ cache->globalPaletteVersion = NULL;
+ free(cache->palette);
+ cache->palette = NULL;
}
static void _redoCacheSize(struct mTileCache* cache) {
if (!mTileCacheConfigurationIsShouldStore(cache->config)) {
return;
}
- unsigned count0 = mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
- unsigned bpp0 = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig);
- bpp0 = 1 << (1 << bpp0);
- if (count0) {
- count0 = 1 << count0;
- }
- unsigned count1 = mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
- unsigned bpp1 = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig);
- bpp1 = 1 << (1 << bpp1);
- if (count1) {
- count1 = 1 << count1;
- }
- unsigned size = count0 > count1 ? count0 : count1;
- if (!size) {
- return;
- }
+ unsigned size = mTileCacheSystemInfoGetPaletteCount(cache->sysConfig);
+ unsigned bpp = mTileCacheSystemInfoGetPaletteBPP(cache->sysConfig);
+ cache->bpp = bpp;
+ bpp = 1 << (1 << bpp);
+ size = 1 << size;
cache->entriesPerTile = size;
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
- cache->cache = anonymousMemoryMap(8 * 8 * 2 * tiles * size);
+ cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles * size);
cache->status = anonymousMemoryMap(tiles * size * sizeof(*cache->status));
- if (count0) {
- cache->globalPaletteVersion[0] = malloc(count0 * bpp0 * sizeof(*cache->globalPaletteVersion[0]));
- }
- if (count1) {
- cache->globalPaletteVersion[1] = malloc(count1 * bpp1 * sizeof(*cache->globalPaletteVersion[1]));
- }
+ cache->globalPaletteVersion = malloc(size * sizeof(*cache->globalPaletteVersion));
+ cache->palette = malloc(size * bpp * sizeof(*cache->palette));
}
void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config) {
@@ -74,9 +56,11 @@ void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration confi
_redoCacheSize(cache);
}
-void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config) {
+void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config, uint32_t tileBase, uint32_t paletteBase) {
_freeCache(cache);
cache->sysConfig = config;
+ cache->tileBase = tileBase;
+ cache->paletteBase = paletteBase;
_redoCacheSize(cache);
}
@@ -85,149 +69,156 @@ void mTileCacheDeinit(struct mTileCache* cache) {
}
void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address) {
+ if (address < cache->tileBase) {
+ return;
+ }
+ address -= cache->tileBase;
unsigned bpp = cache->bpp + 3;
unsigned count = cache->entriesPerTile;
+ address >>= bpp;
+ if (address >= mTileCacheSystemInfoGetMaxTiles(cache->sysConfig)) {
+ return;
+ }
size_t i;
for (i = 0; i < count; ++i) {
- cache->status[(address >> bpp) * count + i].vramClean = 0;
- ++cache->status[(address >> bpp) * count + i].vramVersion;
+ cache->status[address * count + i].vramClean = 0;
+ ++cache->status[address * count + i].vramVersion;
}
}
-void mTileCacheWritePalette(struct mTileCache* cache, uint32_t address) {
- if (cache->globalPaletteVersion[0]) {
- ++cache->globalPaletteVersion[0][address >> 1];
- }
- if (cache->globalPaletteVersion[1]) {
- ++cache->globalPaletteVersion[1][address >> 1];
+void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t color) {
+ if (entry < cache->paletteBase) {
+ return;
}
-}
-
-void mTileCacheSetPalette(struct mTileCache* cache, int palette) {
- cache->activePalette = palette;
- if (palette == 0) {
- cache->bpp = mTileCacheSystemInfoGetPalette0BPP(cache->sysConfig);
- cache->count = 1 << mTileCacheSystemInfoGetPalette0Count(cache->sysConfig);
- } else {
- cache->bpp = mTileCacheSystemInfoGetPalette1BPP(cache->sysConfig);
- cache->count = 1 << mTileCacheSystemInfoGetPalette1Count(cache->sysConfig);
+ entry -= cache->paletteBase;
+ unsigned maxEntry = (1 << (1 << cache->bpp)) * cache->entriesPerTile;
+ if (entry >= maxEntry) {
+ return;
}
- cache->entries = 1 << (1 << cache->bpp);
+ cache->palette[entry] = color;
+ entry >>= (1 << mTileCacheSystemInfoGetPaletteBPP(cache->sysConfig));
+ ++cache->globalPaletteVersion[entry];
}
-static void _regenerateTile4(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
+static void _regenerateTile4(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
uint8_t* start = (uint8_t*) &cache->vram[tileId << 3];
paletteId <<= 2;
- uint16_t* palette = &cache->palette[paletteId];
+ color_t* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint8_t tileDataLower = start[0];
uint8_t tileDataUpper = start[1];
start += 2;
int pixel;
pixel = ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7);
- tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[0] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6);
- tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[1] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5);
- tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[2] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4);
- tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[3] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3);
- tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[4] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2);
- tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[5] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (tileDataUpper & 2) | ((tileDataLower & 2) >> 1);
- tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[6] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
- tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[7] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
tile += 8;
}
}
-static void _regenerateTile16(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
+static void _regenerateTile16(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
uint32_t* start = (uint32_t*) &cache->vram[tileId << 4];
paletteId <<= 4;
- uint16_t* palette = &cache->palette[paletteId];
+ color_t* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint32_t line = *start;
++start;
int pixel;
pixel = line & 0xF;
- tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[0] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 4) & 0xF;
- tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[1] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 8) & 0xF;
- tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[2] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 12) & 0xF;
- tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[3] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 16) & 0xF;
- tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[4] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 20) & 0xF;
- tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[5] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 24) & 0xF;
- tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[6] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 28) & 0xF;
- tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[7] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
tile += 8;
}
}
-static void _regenerateTile256(struct mTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) {
+static void _regenerateTile256(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
uint32_t* start = (uint32_t*) &cache->vram[tileId << 5];
paletteId <<= 8;
- uint16_t* palette = &cache->palette[paletteId];
+ color_t* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint32_t line = *start;
++start;
int pixel;
pixel = line & 0xFF;
- tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[0] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 8) & 0xFF;
- tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[1] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 16) & 0xFF;
- tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[2] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 24) & 0xFF;
- tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[3] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
line = *start;
++start;
pixel = line & 0xFF;
- tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[4] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 8) & 0xFF;
- tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[5] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 16) & 0xFF;
- tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[6] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
pixel = (line >> 24) & 0xFF;
- tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF;
+ tile[7] = pixel ? palette[pixel] | 0xFF000000 : palette[pixel];
tile += 8;
}
}
-static inline uint16_t* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
+static inline color_t* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
if (mTileCacheConfigurationIsShouldStore(cache->config)) {
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
+#ifndef NDEBUG
+ if (tileId >= tiles) {
+ abort();
+ }
+ if (paletteId >= 1 << mTileCacheSystemInfoGetPaletteCount(cache->sysConfig)) {
+ abort();
+ }
+#endif
return &cache->cache[(tileId + paletteId * tiles) << 6];
} else {
return cache->temporaryTile;
}
}
-const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
- unsigned cPaletteId = cache->activePalette;
+const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
unsigned count = cache->entriesPerTile;
unsigned bpp = cache->bpp;
struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
struct mTileCacheEntry desiredStatus = {
- .paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId],
+ .paletteVersion = cache->globalPaletteVersion[paletteId],
.vramVersion = status->vramVersion,
.vramClean = 1,
- .paletteId = paletteId,
- .activePalette = cPaletteId
+ .paletteId = paletteId
};
- uint16_t* tile = _tileLookup(cache, tileId, paletteId);
+ color_t* tile = _tileLookup(cache, tileId, paletteId);
if (!mTileCacheConfigurationIsShouldStore(cache->config) || memcmp(status, &desiredStatus, sizeof(*status))) {
switch (bpp) {
case 0:
@@ -247,19 +238,17 @@ const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, uns
return tile;
}
-const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) {
- unsigned cPaletteId = cache->activePalette;
+const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) {
unsigned count = cache->entriesPerTile;
unsigned bpp = cache->bpp;
struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
struct mTileCacheEntry desiredStatus = {
- .paletteVersion = cache->globalPaletteVersion[cPaletteId][paletteId],
+ .paletteVersion = cache->globalPaletteVersion[paletteId],
.vramVersion = status->vramVersion,
.vramClean = 1,
- .paletteId = paletteId,
- .activePalette = cPaletteId
+ .paletteId = paletteId
};
- uint16_t* tile = NULL;
+ color_t* tile = NULL;
if (memcmp(status, &desiredStatus, sizeof(*status))) {
tile = _tileLookup(cache, tileId, paletteId);
switch (bpp) {
@@ -284,26 +273,10 @@ const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileC
return tile;
}
-const uint8_t* mTileCacheGetRawTile(struct mTileCache* cache, unsigned tileId) {
- unsigned bpp = cache->bpp;
- switch (bpp) {
- case 0:
- return NULL;
- default:
- return (uint8_t*) &cache->vram[tileId << (2 + bpp)];
- }
+const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId) {
+ return &cache->palette[paletteId << (1 << cache->bpp)];
}
-const uint16_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId) {
- unsigned bpp = cache->bpp;
- switch (bpp) {
- default:
- return NULL;
- case 1:
- return &cache->palette[paletteId << 2];
- case 2:
- return &cache->palette[paletteId << 4];
- case 3:
- return &cache->palette[paletteId << 8];
- }
+const uint16_t* mTileCacheGetVRAM(struct mTileCache* cache, unsigned tileId) {
+ return &cache->vram[tileId << (cache->bpp + 2)];
}
View
@@ -7,6 +7,7 @@
void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) {
timing->root = NULL;
+ timing->reroot = NULL;
timing->masterCycles = 0;
timing->relativeCycles = relativeCycles;
timing->nextEvent = nextEvent;
@@ -17,6 +18,7 @@ void mTimingDeinit(struct mTiming* timing) {
void mTimingClear(struct mTiming* timing) {
timing->root = NULL;
+ timing->reroot = NULL;
timing->masterCycles = 0;
}
@@ -77,6 +79,11 @@ int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
timing->root = next->next;
next->callback(timing, next->context, -nextWhen);
}
+ if (timing->reroot) {
+ timing->root = timing->reroot;
+ timing->reroot = NULL;
+ *timing->nextEvent = mTimingNextEvent(timing);
+ }
return *timing->nextEvent;
}
View
@@ -687,8 +687,16 @@ void mVideoLogContextDestroy(struct mCore* core, struct mVideoLogContext* contex
void mVideoLogContextRewind(struct mVideoLogContext* context, struct mCore* core) {
_readHeader(context);
- if (core && core->stateSize(core) == context->initialStateSize) {
- core->loadState(core, context->initialState);
+ if (core) {
+ size_t size = core->stateSize(core);
+ if (size <= context->initialStateSize) {
+ core->loadState(core, context->initialState);
+ } else {
+ void* extendedState = anonymousMemoryMap(size);
+ memcpy(extendedState, context->initialState, context->initialStateSize);
+ core->loadState(core, extendedState);
+ mappedMemoryFree(extendedState, size);
+ }
}
off_t pointer = context->backing->seek(context->backing, 0, SEEK_CUR);
View
@@ -25,7 +25,7 @@ const int GB_AUDIO_VOLUME_MAX = 0x100;
static bool _writeSweep(struct GBAudioSweep* sweep, uint8_t value);
static void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value);
-static bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value);
+static bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudioStyle style);
static void _resetSweep(struct GBAudioSweep* sweep);
static bool _resetEnvelope(struct GBAudioEnvelope* sweep);
@@ -153,6 +153,10 @@ void GBAudioReset(struct GBAudio* audio) {
audio->playingCh2 = false;
audio->playingCh3 = false;
audio->playingCh4 = false;
+ if (audio->p && (audio->p->model == GB_MODEL_DMG || audio->p->model == GB_MODEL_CGB)) {
+ audio->playingCh1 = true;
+ *audio->nr52 |= 0x01;
+ }
}
void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples) {
@@ -178,7 +182,7 @@ void GBAudioWriteNR11(struct GBAudio* audio, uint8_t value) {
}
void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) {
- if (!_writeEnvelope(&audio->ch1.envelope, value)) {
+ if (!_writeEnvelope(&audio->ch1.envelope, value, audio->style)) {
mTimingDeschedule(audio->timing, &audio->ch1Event);
audio->playingCh1 = false;
*audio->nr52 &= ~0x0001;
@@ -236,7 +240,7 @@ void GBAudioWriteNR21(struct GBAudio* audio, uint8_t value) {
}
void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) {
- if (!_writeEnvelope(&audio->ch2.envelope, value)) {
+ if (!_writeEnvelope(&audio->ch2.envelope, value, audio->style)) {
mTimingDeschedule(audio->timing, &audio->ch2Event);
audio->playingCh2 = false;
*audio->nr52 &= ~0x0002;
@@ -354,7 +358,7 @@ void GBAudioWriteNR41(struct GBAudio* audio, uint8_t value) {
}
void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) {
- if (!_writeEnvelope(&audio->ch4.envelope, value)) {
+ if (!_writeEnvelope(&audio->ch4.envelope, value, audio->style)) {
mTimingDeschedule(audio->timing, &audio->ch4Event);
audio->playingCh4 = false;
*audio->nr52 &= ~0x0008;
@@ -696,17 +700,16 @@ void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value) {
envelope->duty = GBAudioRegisterDutyGetDuty(value);
}
-bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value) {
+bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudioStyle style) {
envelope->stepTime = GBAudioRegisterSweepGetStepTime(value);
envelope->direction = GBAudioRegisterSweepGetDirection(value);
envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value);
- if (!envelope->stepTime) {
+ if (style == GB_AUDIO_DMG && !envelope->stepTime) {
// TODO: Improve "zombie" mode
++envelope->currentVolume;
envelope->currentVolume &= 0xF;
}
_updateEnvelopeDead(envelope);
- envelope->nextStep = envelope->stepTime;
return (envelope->initialVolume || envelope->direction) && envelope->dead != 2;
}
@@ -960,6 +963,8 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
mTimingSchedule(audio->timing, &audio->frameEvent, when);
LOAD_32LE(flags, 0, flagsIn);
+ audio->frame = GBSerializedAudioFlagsGetFrame(flags);
+
LOAD_32LE(ch1Flags, 0, &state->ch1.envelope);
audio->ch1.envelope.currentVolume = GBSerializedAudioFlagsGetCh1Volume(flags);
audio->ch1.envelope.dead = GBSerializedAudioFlagsGetCh1Dead(flags);
View
@@ -31,8 +31,8 @@
static const struct mCoreChannelInfo _GBVideoLayers[] = {
{ 0, "bg", "Background", NULL },
- { 1, "obj", "Objects", NULL },
- { 2, "win", "Window", NULL },
+ { 1, "bgwin", "Window", NULL },
+ { 2, "obj", "Objects", NULL },
};
static const struct mCoreChannelInfo _GBAudioChannels[] = {
@@ -176,21 +176,50 @@ static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* conf
gb->video.frameskip = core->opts.frameskip;
int color;
- if (mCoreConfigGetIntValue(&core->config, "gb.pal[0]", &color)) {
- GBVideoSetPalette(&gb->video, 0, color);
+ if (mCoreConfigGetIntValue(config, "gb.pal[0]", &color)) {
+ GBVideoSetPalette(&gb->video, 0, color);
}
- if (mCoreConfigGetIntValue(&core->config, "gb.pal[1]", &color)) {
- GBVideoSetPalette(&gb->video, 1, color);
+ if (mCoreConfigGetIntValue(config, "gb.pal[1]", &color)) {
+ GBVideoSetPalette(&gb->video, 1, color);
}
- if (mCoreConfigGetIntValue(&core->config, "gb.pal[2]", &color)) {
- GBVideoSetPalette(&gb->video, 2, color);
+ if (mCoreConfigGetIntValue(config, "gb.pal[2]", &color)) {
+ GBVideoSetPalette(&gb->video, 2, color);
}
- if (mCoreConfigGetIntValue(&core->config, "gb.pal[3]", &color)) {
- GBVideoSetPalette(&gb->video, 3, color);
+ if (mCoreConfigGetIntValue(config, "gb.pal[3]", &color)) {
+ GBVideoSetPalette(&gb->video, 3, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[4]", &color)) {
+ GBVideoSetPalette(&gb->video, 4, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[5]", &color)) {
+ GBVideoSetPalette(&gb->video, 5, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[6]", &color)) {
+ GBVideoSetPalette(&gb->video, 6, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[7]", &color)) {
+ GBVideoSetPalette(&gb->video, 7, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[8]", &color)) {
+ GBVideoSetPalette(&gb->video, 8, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[9]", &color)) {
+ GBVideoSetPalette(&gb->video, 9, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[10]", &color)) {
+ GBVideoSetPalette(&gb->video, 10, color);
+ }
+ if (mCoreConfigGetIntValue(config, "gb.pal[11]", &color)) {
+ GBVideoSetPalette(&gb->video, 11, color);
}
mCoreConfigCopyValue(&core->config, config, "gb.bios");
+ mCoreConfigCopyValue(&core->config, config, "sgb.bios");
mCoreConfigCopyValue(&core->config, config, "gbc.bios");
+ mCoreConfigCopyValue(&core->config, config, "gb.model");
+ mCoreConfigCopyValue(&core->config, config, "sgb.model");
+ mCoreConfigCopyValue(&core->config, config, "cgb.model");
+ mCoreConfigCopyValue(&core->config, config, "sgb.borders");
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
struct GBCore* gbcore = (struct GBCore*) core;
@@ -199,9 +228,14 @@ static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* conf
}
static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
- UNUSED(core);
- *width = GB_VIDEO_HORIZONTAL_PIXELS;
- *height = GB_VIDEO_VERTICAL_PIXELS;
+ struct GB* gb = core->board;
+ if (gb && (gb->model != GB_MODEL_SGB || !gb->video.sgbBorders)) {
+ *width = GB_VIDEO_HORIZONTAL_PIXELS;
+ *height = GB_VIDEO_VERTICAL_PIXELS;
+ } else {
+ *width = 256;
+ *height = 224;
+ }
}
static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
@@ -333,6 +367,25 @@ static void _GBCoreReset(struct mCore* core) {
}
}
+ const char* modelGB = mCoreConfigGetValue(&core->config, "gb.model");
+ const char* modelCGB = mCoreConfigGetValue(&core->config, "cgb.model");
+ const char* modelSGB = mCoreConfigGetValue(&core->config, "sgb.model");
+ if (modelGB || modelCGB || modelSGB) {
+ GBDetectModel(gb);
+ if (gb->model == GB_MODEL_DMG && modelGB) {
+ gb->model = GBNameToModel(modelGB);
+ } else if (gb->model == GB_MODEL_CGB && modelCGB) {
+ gb->model = GBNameToModel(modelCGB);
+ } else if (gb->model == GB_MODEL_SGB && modelSGB) {
+ gb->model = GBNameToModel(modelSGB);
+ }
+ }
+
+ int fakeBool;
+ if (mCoreConfigGetIntValue(&core->config, "sgb.borders", &fakeBool)) {
+ gb->video.sgbBorders = fakeBool;
+ }
+
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
if (!gb->biosVf && core->opts.useBios) {
struct VFile* bios = NULL;
@@ -352,9 +405,13 @@ static void _GBCoreReset(struct mCore* core) {
switch (gb->model) {
case GB_MODEL_DMG:
- case GB_MODEL_SGB: // TODO
+ case GB_MODEL_MGB: // TODO
configPath = mCoreConfigGetValue(&core->config, "gb.bios");
break;
+ case GB_MODEL_SGB:
+ case GB_MODEL_SGB2: // TODO
+ configPath = mCoreConfigGetValue(&core->config, "sgb.bios");
+ break;
case GB_MODEL_CGB:
case GB_MODEL_AGB:
configPath = mCoreConfigGetValue(&core->config, "gbc.bios");
@@ -377,9 +434,13 @@ static void _GBCoreReset(struct mCore* core) {
mCoreConfigDirectory(path, PATH_MAX);
switch (gb->model) {
case GB_MODEL_DMG:
- case GB_MODEL_SGB: // TODO
+ case GB_MODEL_MGB: // TODO
strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path));
break;
+ case GB_MODEL_SGB:
+ case GB_MODEL_SGB2: // TODO
+ strncat(path, PATH_SEP "sgb_bios.bin", PATH_MAX - strlen(path));
+ break;
case GB_MODEL_CGB:
case GB_MODEL_AGB:
strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path));
@@ -502,6 +563,9 @@ static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
case mPERIPH_RUMBLE:
gb->memory.rumble = periph;
break;
+ case mPERIPH_IMAGE_SOURCE:
+ gb->memory.cam = periph;
+ break;
default:
return;
}
@@ -581,7 +645,9 @@ size_t _GBListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlo
const struct GB* gb = core->board;
switch (gb->model) {
case GB_MODEL_DMG:
+ case GB_MODEL_MGB:
case GB_MODEL_SGB:
+ case GB_MODEL_SGB2:
default:
*blocks = _GBMemoryBlocks;
return sizeof(_GBMemoryBlocks) / sizeof(*_GBMemoryBlocks);
View
@@ -5,15 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gb/renderers/proxy.h>
-#include <mgba/core/tile-cache.h>
+#include <mgba/core/cache-set.h>
#include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/io.h>
#define BUFFER_OAM 1
+#define BUFFER_SGB 2
-static void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);
+static void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model, bool borders);
static void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer);
static uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
+static void GBVideoProxyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data);
static void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
static void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int address, uint16_t value);
@@ -30,6 +32,7 @@ void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GB
renderer->d.init = GBVideoProxyRendererInit;
renderer->d.deinit = GBVideoProxyRendererDeinit;
renderer->d.writeVideoRegister = GBVideoProxyRendererWriteVideoRegister;
+ renderer->d.writeSGBPacket = GBVideoProxyRendererWriteSGBPacket;
renderer->d.writeVRAM = GBVideoProxyRendererWriteVRAM;
renderer->d.writeOAM = GBVideoProxyRendererWriteOAM;
renderer->d.writePalette = GBVideoProxyRendererWritePalette;
@@ -93,12 +96,12 @@ void GBVideoProxyRendererUnshim(struct GBVideo* video, struct GBVideoProxyRender
mVideoLoggerRendererDeinit(renderer->logger);
}
-void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model) {
+void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model, bool borders) {
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
_init(proxyRenderer);
- proxyRenderer->backend->init(proxyRenderer->backend, model);
+ proxyRenderer->backend->init(proxyRenderer->backend, model, borders);
}
void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer) {
@@ -111,6 +114,7 @@ void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer) {
static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
struct GBVideoProxyRenderer* proxyRenderer = logger->context;
+ uint8_t sgbPacket[16];
switch (item->type) {
case DIRTY_REGISTER:
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
@@ -154,6 +158,11 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
return false;
}
logger->readData(logger, &proxyRenderer->objThisLine, item->value2, true);
+ break;
+ case BUFFER_SGB:
+ logger->readData(logger, sgbPacket, 16, true);
+ proxyRenderer->backend->writeSGBPacket(proxyRenderer->backend, sgbPacket);
+ break;
}
break;
case DIRTY_FLUSH:
@@ -179,14 +188,22 @@ uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer,
return value;
}
+void GBVideoProxyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) {
+ struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
+ if (!proxyRenderer->logger->block) {
+ proxyRenderer->backend->writeSGBPacket(proxyRenderer->backend, data);
+ }
+ mVideoLoggerWriteBuffer(proxyRenderer->logger, BUFFER_SGB, 0, 16, data);
+}
+
void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);
if (!proxyRenderer->logger->block) {
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
}
if (renderer->cache) {
- mTileCacheWriteVRAM(renderer->cache, address);
+ mCacheSetWriteVRAM(renderer->cache, address);
}
}
@@ -197,7 +214,7 @@ void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int addr
proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
}
if (renderer->cache) {
- mTileCacheWritePalette(renderer->cache, address);
+ mCacheSetWritePalette(renderer->cache, address, mColorFrom555(value));
}
}
View
@@ -28,6 +28,8 @@ static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
#define DMG_BIOS_CHECKSUM 0xC2F5CC97
#define DMG_2_BIOS_CHECKSUM 0x59C8598E
+#define MGB_BIOS_CHECKSUM 0xE6920754
+#define SGB_BIOS_CHECKSUM 0xEC8A83B9
#define CGB_BIOS_CHECKSUM 0x41884E46
mLOG_DEFINE_CATEGORY(GB, "GB", "gb");
@@ -37,6 +39,7 @@ static void GBDeinit(struct mCPUComponent* component);
static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
static void GBProcessEvents(struct LR35902Core* cpu);
static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
+static uint16_t GBIRQVector(struct LR35902Core* cpu);
static void GBIllegal(struct LR35902Core* cpu);
static void GBStop(struct LR35902Core* cpu);
@@ -162,7 +165,6 @@ void GBResizeSram(struct GB* gb, size_t size) {
if (gb->memory.sram && size <= gb->sramSize) {
return;
}
- mLOG(GB, INFO, "Resizing SRAM to %"PRIz"u bytes", size);
struct VFile* vf = gb->sramVf;
if (vf) {
if (vf == gb->sramRealVf) {
@@ -220,7 +222,7 @@ void GBResizeSram(struct GB* gb, size_t size) {
void GBSramClean(struct GB* gb, uint32_t frameCount) {
// TODO: Share with GBASavedataClean
- if (!gb->sramVf || gb->sramVf != gb->sramRealVf) {
+ if (!gb->sramVf) {
return;
}
if (gb->sramDirty & GB_SRAM_DIRT_NEW) {
@@ -230,6 +232,9 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) {
gb->sramDirty |= GB_SRAM_DIRT_SEEN;
}
} else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) {
+ if (gb->sramMaskWriteback) {
+ GBSavedataUnmask(gb);
+ }
if (gb->memory.mbcType == GB_MBC3_RTC) {
GBMBCRTCWrite(gb);
}
@@ -259,7 +264,9 @@ void GBSavedataUnmask(struct GB* gb) {
gb->sramVf = gb->sramRealVf;
gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
if (gb->sramMaskWriteback) {
+ vf->seek(vf, 0, SEEK_SET);
vf->read(vf, gb->memory.sram, gb->sramSize);
+ gb->sramMaskWriteback = false;
}
vf->close(vf);
}
@@ -287,13 +294,17 @@ void GBUnloadROM(struct GB* gb) {
gb->memory.mbcType = GB_MBC_AUTODETECT;
gb->isPristine = false;
+ gb->sramMaskWriteback = false;
GBSavedataUnmask(gb);
GBSramDeinit(gb);
if (gb->sramRealVf) {
gb->sramRealVf->close(gb->sramRealVf);
}
gb->sramRealVf = NULL;
gb->sramVf = NULL;
+ if (gb->memory.cam && gb->memory.cam->stopRequestImage) {
+ gb->memory.cam->stopRequestImage(gb->memory.cam);
+ }
}
void GBSynthesizeROM(struct VFile* vf) {
@@ -361,6 +372,7 @@ void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
irqh->reset = GBReset;
irqh->processEvents = GBProcessEvents;
irqh->setInterrupts = GBSetInterrupts;
+ irqh->irqVector = GBIRQVector;
irqh->hitIllegal = GBIllegal;
irqh->stop = GBStop;
irqh->halt = GBHalt;
@@ -381,6 +393,8 @@ bool GBIsBIOS(struct VFile* vf) {
switch (_GBBiosCRC32(vf)) {
case DMG_BIOS_CHECKSUM:
case DMG_2_BIOS_CHECKSUM:
+ case MGB_BIOS_CHECKSUM:
+ case SGB_BIOS_CHECKSUM:
case CGB_BIOS_CHECKSUM:
return true;
default:
@@ -420,32 +434,72 @@ void GBReset(struct LR35902Core* cpu) {
cpu->b = 0;
cpu->d = 0;
+ gb->timer.internalDiv = 0;
+ int nextDiv = 0;
if (!gb->biosVf) {
switch (gb->model) {
- case GB_MODEL_DMG:
- // TODO: SGB
- case GB_MODEL_SGB:
case GB_MODEL_AUTODETECT: // Silence warnings
gb->model = GB_MODEL_DMG;
+ case GB_MODEL_DMG:
+ cpu->a = 1;
+ cpu->f.packed = 0xB0;
+ cpu->c = 0x13;
+ cpu->e = 0xD8;
+ cpu->h = 1;
+ cpu->l = 0x4D;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_SGB:
cpu->a = 1;
+ cpu->f.packed = 0x00;
+ cpu->c = 0x14;
+ cpu->e = 0x00;
+ cpu->h = 0xC0;
+ cpu->l = 0x60;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_MGB:
+ cpu->a = 0xFF;
cpu->f.packed = 0xB0;
cpu->c = 0x13;
cpu->e = 0xD8;
cpu->h = 1;
cpu->l = 0x4D;
- gb->timer.internalDiv = 0x2AF3;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_SGB2:
+ cpu->a = 0xFF;
+ cpu->f.packed = 0x00;
+ cpu->c = 0x14;
+ cpu->e = 0x00;
+ cpu->h = 0xC0;
+ cpu->l = 0x60;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
break;
case GB_MODEL_AGB:
+ cpu->a = 0x11;
cpu->b = 1;
- // Fall through
+ cpu->f.packed = 0x00;
+ cpu->c = 0;
+ cpu->e = 0x08;
+ cpu->h = 0;
+ cpu->l = 0x7C;
+ gb->timer.internalDiv = 0x1EA;
+ nextDiv = 0xC;
+ break;
case GB_MODEL_CGB:
cpu->a = 0x11;
cpu->f.packed = 0x80;
cpu->c = 0;
cpu->e = 0x08;
cpu->h = 0;
cpu->l = 0x7C;
- gb->timer.internalDiv = 0x7A8;
+ gb->timer.internalDiv = 0x1EA;
+ nextDiv = 0xC;
break;
}
@@ -464,15 +518,19 @@ void GBReset(struct LR35902Core* cpu) {
gb->yankedRomSize = 0;
}
+ gb->sgbBit = -1;
+ gb->currentSgbBits = 0;
+ memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
+
mTimingClear(&gb->timing);
GBMemoryReset(gb);
GBVideoReset(&gb->video);
GBTimerReset(&gb->timer);
- mTimingSchedule(&gb->timing, &gb->timer.event, GB_DMG_DIV_PERIOD);
+ mTimingSchedule(&gb->timing, &gb->timer.event, nextDiv);
- GBAudioReset(&gb->audio);
GBIOReset(gb);
+ GBAudioReset(&gb->audio);
GBSIOReset(&gb->sio);
GBSavedataUnmask(gb);
@@ -488,6 +546,12 @@ void GBDetectModel(struct GB* gb) {
case DMG_2_BIOS_CHECKSUM:
gb->model = GB_MODEL_DMG;
break;
+ case MGB_BIOS_CHECKSUM:
+ gb->model = GB_MODEL_MGB;
+ break;
+ case SGB_BIOS_CHECKSUM:
+ gb->model = GB_MODEL_SGB;
+ break;
case CGB_BIOS_CHECKSUM:
gb->model = GB_MODEL_CGB;
break;
@@ -500,6 +564,8 @@ void GBDetectModel(struct GB* gb) {
const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
if (cart->cgb & 0x80) {
gb->model = GB_MODEL_CGB;
+ } else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
+ gb->model = GB_MODEL_SGB;
} else {
gb->model = GB_MODEL_DMG;
}
@@ -511,6 +577,10 @@ void GBDetectModel(struct GB* gb) {
case GB_MODEL_AUTODETECT: //Silence warnings
gb->audio.style = GB_AUDIO_DMG;
break;
+ case GB_MODEL_MGB:
+ case GB_MODEL_SGB2:
+ gb->audio.style = GB_AUDIO_MGB;
+ break;
case GB_MODEL_AGB:
case GB_MODEL_CGB:
gb->audio.style = GB_AUDIO_CGB;
@@ -528,31 +598,7 @@ void GBUpdateIRQs(struct GB* gb) {
if (!gb->memory.ime || gb->cpu->irqPending) {
return;
}
-
- if (irqs & (1 << GB_IRQ_VBLANK)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
- return;
- }
- if (irqs & (1 << GB_IRQ_LCDSTAT)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
- return;
- }
- if (irqs & (1 << GB_IRQ_TIMER)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
- return;
- }
- if (irqs & (1 << GB_IRQ_SIO)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
- return;
- }
- if (irqs & (1 << GB_IRQ_KEYPAD)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
- }
+ LR35902RaiseIRQ(gb->cpu);
}
void GBProcessEvents(struct LR35902Core* cpu) {
@@ -595,6 +641,33 @@ void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
}
}
+uint16_t GBIRQVector(struct LR35902Core* cpu) {
+ struct GB* gb = (struct GB*) cpu->master;
+ int irqs = gb->memory.ie & gb->memory.io[REG_IF];
+
+ if (irqs & (1 << GB_IRQ_VBLANK)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
+ return GB_VECTOR_VBLANK;
+ }
+ if (irqs & (1 << GB_IRQ_LCDSTAT)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
+ return GB_VECTOR_LCDSTAT;
+ }
+ if (irqs & (1 << GB_IRQ_TIMER)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
+ return GB_VECTOR_TIMER;
+ }
+ if (irqs & (1 << GB_IRQ_SIO)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
+ return GB_VECTOR_SIO;
+ }
+ if (irqs & (1 << GB_IRQ_KEYPAD)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
+ return GB_VECTOR_KEYPAD;
+ }
+ return 0;
+}
+
static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
@@ -613,7 +686,7 @@ void GBHalt(struct LR35902Core* cpu) {
void GBStop(struct LR35902Core* cpu) {
struct GB* gb = (struct GB*) cpu->master;
if (cpu->bus) {
- mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X\n", cpu->pc, cpu->bus);
+ mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X", cpu->pc, cpu->bus);
}
if (gb->memory.io[REG_KEY1] & 1) {
gb->doubleSpeed ^= 1;
@@ -639,7 +712,7 @@ void GBStop(struct LR35902Core* cpu) {
void GBIllegal(struct LR35902Core* cpu) {
struct GB* gb = (struct GB*) cpu->master;
- mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus);
+ mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X", cpu->pc, cpu->bus);
#ifdef USE_DEBUGGERS
if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
struct mDebuggerEntryInfo info = {
@@ -655,6 +728,9 @@ void GBIllegal(struct LR35902Core* cpu) {
}
bool GBIsROM(struct VFile* vf) {
+ if (!vf) {
+ return false;
+ }
vf->seek(vf, 0x104, SEEK_SET);
uint8_t header[4];
@@ -715,3 +791,40 @@ void GBFrameEnded(struct GB* gb) {
GBTestKeypadIRQ(gb);
}
+
+enum GBModel GBNameToModel(const char* model) {
+ if (strcasecmp(model, "DMG") == 0) {
+ return GB_MODEL_DMG;
+ } else if (strcasecmp(model, "CGB") == 0) {
+ return GB_MODEL_CGB;
+ } else if (strcasecmp(model, "AGB") == 0) {
+ return GB_MODEL_AGB;
+ } else if (strcasecmp(model, "SGB") == 0) {
+ return GB_MODEL_SGB;
+ } else if (strcasecmp(model, "MGB") == 0) {
+ return GB_MODEL_MGB;
+ } else if (strcasecmp(model, "SGB2") == 0) {
+ return GB_MODEL_SGB2;
+ }
+ return GB_MODEL_AUTODETECT;
+}
+
+const char* GBModelToName(enum GBModel model) {
+ switch (model) {
+ case GB_MODEL_DMG:
+ return "DMG";
+ case GB_MODEL_SGB:
+ return "SGB";
+ case GB_MODEL_MGB:
+ return "MGB";
+ case GB_MODEL_SGB2:
+ return "SGB2";
+ case GB_MODEL_CGB:
+ return "CGB";
+ case GB_MODEL_AGB:
+ return "AGB";
+ default:
+ case GB_MODEL_AUTODETECT:
+ return NULL;
+ }
+}
View
@@ -105,6 +105,33 @@ static const uint8_t _registerMask[] = {
[REG_IE] = 0xE0,
};
+static void _writeSGBBits(struct GB* gb, int bits) {
+ if (!bits) {
+ gb->sgbBit = 0;
+ memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
+ }
+ if (bits == gb->currentSgbBits) {
+ return;
+ }
+ gb->currentSgbBits = bits;
+ if (gb->sgbBit == 128 && bits == 2) {
+ GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
+ ++gb->sgbBit;
+ }
+ if (gb->sgbBit >= 128) {
+ return;
+ }
+ switch (bits) {
+ case 1:
+ gb->sgbPacket[gb->sgbBit >> 3] |= 1 << (gb->sgbBit & 7);
+ // Fall through
+ case 2:
+ ++gb->sgbBit;
+ default:
+ break;
+ }
+}
+
void GBIOInit(struct GB* gb) {
memset(gb->memory.io, 0, sizeof(gb->memory.io));
}
@@ -117,19 +144,19 @@ void GBIOReset(struct GB* gb) {
GBIOWrite(gb, REG_TAC, 0);
GBIOWrite(gb, REG_IF, 1);
GBIOWrite(gb, REG_NR52, 0xF1);
- GBIOWrite(gb, REG_NR14, 0xBF);
+ GBIOWrite(gb, REG_NR14, 0x3F);
GBIOWrite(gb, REG_NR10, 0x80);
GBIOWrite(gb, REG_NR11, 0xBF);
GBIOWrite(gb, REG_NR12, 0xF3);
GBIOWrite(gb, REG_NR13, 0xF3);
- GBIOWrite(gb, REG_NR24, 0xBF);
+ GBIOWrite(gb, REG_NR24, 0x3F);
GBIOWrite(gb, REG_NR21, 0x3F);
GBIOWrite(gb, REG_NR22, 0x00);
- GBIOWrite(gb, REG_NR34, 0xBF);
+ GBIOWrite(gb, REG_NR34, 0x3F);
GBIOWrite(gb, REG_NR30, 0x7F);
GBIOWrite(gb, REG_NR31, 0xFF);
GBIOWrite(gb, REG_NR32, 0x9F);
- GBIOWrite(gb, REG_NR44, 0xBF);
+ GBIOWrite(gb, REG_NR44, 0x3F);
GBIOWrite(gb, REG_NR41, 0xFF);
GBIOWrite(gb, REG_NR42, 0x00);
GBIOWrite(gb, REG_NR43, 0x00);
@@ -140,19 +167,26 @@ void GBIOReset(struct GB* gb) {
GBIOWrite(gb, REG_SCX, 0x00);
GBIOWrite(gb, REG_LYC, 0x00);
GBIOWrite(gb, REG_BGP, 0xFC);
- GBIOWrite(gb, REG_OBP0, 0xFF);
- GBIOWrite(gb, REG_OBP1, 0xFF);
+ if (gb->model < GB_MODEL_CGB) {
+ GBIOWrite(gb, REG_OBP0, 0xFF);
+ GBIOWrite(gb, REG_OBP1, 0xFF);
+ }
GBIOWrite(gb, REG_WY, 0x00);
GBIOWrite(gb, REG_WX, 0x00);
- GBIOWrite(gb, REG_VBK, 0);
- GBIOWrite(gb, REG_BCPS, 0);
- GBIOWrite(gb, REG_OCPS, 0);
- GBIOWrite(gb, REG_SVBK, 1);
- GBIOWrite(gb, REG_HDMA1, 0xFF);
- GBIOWrite(gb, REG_HDMA2, 0xFF);
- GBIOWrite(gb, REG_HDMA3, 0xFF);
- GBIOWrite(gb, REG_HDMA4, 0xFF);
- gb->memory.io[REG_HDMA5] = 0xFF;
+ if (gb->model >= GB_MODEL_CGB) {
+ GBIOWrite(gb, REG_JOYP, 0xFF);
+ GBIOWrite(gb, REG_VBK, 0);
+ GBIOWrite(gb, REG_BCPS, 0);
+ GBIOWrite(gb, REG_OCPS, 0);
+ GBIOWrite(gb, REG_SVBK, 1);
+ GBIOWrite(gb, REG_HDMA1, 0xFF);
+ GBIOWrite(gb, REG_HDMA2, 0xFF);
+ GBIOWrite(gb, REG_HDMA3, 0xFF);
+ GBIOWrite(gb, REG_HDMA4, 0xFF);
+ gb->memory.io[REG_HDMA5] = 0xFF;
+ } else if (gb->model == GB_MODEL_SGB) {
+ GBIOWrite(gb, REG_JOYP, 0xFF);
+ }
GBIOWrite(gb, REG_IE, 0x00);
}
@@ -341,6 +375,10 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
}
break;
case REG_JOYP:
+ if (gb->model == GB_MODEL_SGB) {
+ _writeSGBBits(gb, (value >> 4) & 3);
+ }
+ break;
case REG_TIMA:
case REG_TMA:
// Handled transparently by the registers
@@ -386,6 +424,10 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
free(gb->memory.romBase);
gb->memory.romBase = gb->memory.rom;
}
+ if (gb->model >= GB_MODEL_CGB && gb->memory.io[0x6C]) {
+ gb->model = GB_MODEL_DMG;
+ GBVideoDisableCGB(&gb->video);
+ }
break;
case REG_IE:
gb->memory.ie = value;
@@ -453,7 +495,8 @@ static uint8_t _readKeys(struct GB* gb) {
uint8_t keys = *gb->keySource;
switch (gb->memory.io[REG_JOYP] & 0x30) {
case 0x30:
- keys = 0;
+ // TODO: Increment
+ keys = (gb->video.sgbCommandHeader >> 3) == SGB_MLT_REG ? 0xF : 0;
break;
case 0x20:
keys >>= 4;
@@ -553,6 +596,9 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
case REG_SVBK:
// Handled transparently by the registers
goto success;
+ case REG_DMA:
+ mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address);
+ return 0;
default:
break;
}
@@ -580,9 +626,45 @@ void GBIOSerialize(const struct GB* gb, struct GBSerializedState* state) {
void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
memcpy(gb->memory.io, state->io, GB_SIZE_IO);
gb->memory.ie = state->ie;
+
+ if (GBAudioEnableGetEnable(*gb->audio.nr52)) {
+ GBIOWrite(gb, REG_NR10, gb->memory.io[REG_NR10]);
+ GBIOWrite(gb, REG_NR11, gb->memory.io[REG_NR11]);
+ GBIOWrite(gb, REG_NR12, gb->memory.io[REG_NR12]);
+ GBIOWrite(gb, REG_NR13, gb->memory.io[REG_NR13]);
+ gb->audio.ch1.control.frequency &= 0xFF;
+ gb->audio.ch1.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[REG_NR14] << 8);
+ gb->audio.ch1.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR14] << 8);
+ GBIOWrite(gb, REG_NR21, gb->memory.io[REG_NR21]);
+ GBIOWrite(gb, REG_NR22, gb->memory.io[REG_NR22]);
+ GBIOWrite(gb, REG_NR22, gb->memory.io[REG_NR23]);
+ gb->audio.ch2.control.frequency &= 0xFF;
+ gb->audio.ch2.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[REG_NR24] << 8);
+ gb->audio.ch2.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR24] << 8);
+ GBIOWrite(gb, REG_NR30, gb->memory.io[REG_NR30]);
+ GBIOWrite(gb, REG_NR31, gb->memory.io[REG_NR31]);
+ GBIOWrite(gb, REG_NR32, gb->memory.io[REG_NR32]);
+ GBIOWrite(gb, REG_NR32, gb->memory.io[REG_NR33]);
+ gb->audio.ch3.rate &= 0xFF;
+ gb->audio.ch3.rate |= GBAudioRegisterControlGetRate(gb->memory.io[REG_NR34] << 8);
+ gb->audio.ch3.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR34] << 8);
+ GBIOWrite(gb, REG_NR41, gb->memory.io[REG_NR41]);
+ GBIOWrite(gb, REG_NR42, gb->memory.io[REG_NR42]);
+ GBIOWrite(gb, REG_NR43, gb->memory.io[REG_NR43]);
+ gb->audio.ch4.stop = GBAudioRegisterNoiseControlGetStop(gb->memory.io[REG_NR44]);
+ GBIOWrite(gb, REG_NR50, gb->memory.io[REG_NR50]);
+ GBIOWrite(gb, REG_NR51, gb->memory.io[REG_NR51]);
+ }
+
gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_LCDC, state->io[REG_LCDC]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCY, state->io[REG_SCY]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCX, state->io[REG_SCX]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WY, state->io[REG_WY]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WX, state->io[REG_WX]);
+ if (gb->model == GB_MODEL_SGB) {
+ gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_BGP, state->io[REG_BGP]);
+ gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP0, state->io[REG_OBP0]);
+ gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP1, state->io[REG_OBP1]);
+ }
+ gb->video.stat = state->io[REG_STAT];
}
View
@@ -29,9 +29,15 @@ static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
+static void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
+static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
+
+static uint8_t _GBTAMA5Read(struct GBMemory*, uint16_t address);
+
static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
+static void _GBPocketCamCapture(struct GBMemory*);
void GBMBCSwitchBank(struct GB* gb, int bank) {
size_t bankStart = bank * GB_SIZE_CART_BANK0;
@@ -62,6 +68,28 @@ void GBMBCSwitchBank0(struct GB* gb, int bank) {
}
}
+void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) {
+ size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
+ if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) {
+ mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
+ bankStart &= (gb->memory.romSize - 1);
+ bank = bankStart / GB_SIZE_CART_HALFBANK;
+ if (!bank) {
+ ++bank;
+ }
+ }
+ if (!half) {
+ gb->memory.romBank = &gb->memory.rom[bankStart];
+ gb->memory.currentBank = bank;
+ } else {
+ gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart];
+ gb->memory.mbcState.mbc6.currentBank1 = bank;
+ }
+ if (gb->cpu->pc < GB_BASE_VRAM) {
+ gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
+ }
+}
+
static bool _isMulticart(const uint8_t* mem) {
bool success = true;
struct VFile* vf;
@@ -105,6 +133,12 @@ void GBMBCInit(struct GB* gb) {
case 3:
gb->sramSize = 0x8000;
break;
+ case 4:
+ gb->sramSize = 0x20000;
+ break;
+ case 5:
+ gb->sramSize = 0x10000;
+ break;
}
if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
@@ -160,11 +194,14 @@ void GBMBCInit(struct GB* gb) {
gb->memory.mbcType = GB_POCKETCAM;
break;
case 0xFD:
- gb->memory.mbcType = GB_HuC1;
+ gb->memory.mbcType = GB_TAMA5;
break;
case 0xFE:
gb->memory.mbcType = GB_HuC3;
break;
+ case 0xFF:
+ gb->memory.mbcType = GB_HuC1;
+ break;
}
}
} else {
@@ -211,6 +248,13 @@ void GBMBCInit(struct GB* gb) {
case GB_HuC3:
gb->memory.mbcWrite = _GBHuC3;
break;
+ case GB_TAMA5:
+ mLOG(GB_MBC, WARN, "unimplemented MBC: TAMA5");
+ memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
+ gb->memory.mbcWrite = _GBTAMA5;
+ gb->memory.mbcRead = _GBTAMA5Read;
+ gb->sramSize = 0x20;
+ break;
case GB_MBC3_RTC:
memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
gb->memory.mbcWrite = _GBMBC3;
@@ -221,6 +265,9 @@ void GBMBCInit(struct GB* gb) {
case GB_POCKETCAM:
gb->memory.mbcWrite = _GBPocketCam;
gb->memory.mbcRead = _GBPocketCamRead;
+ if (gb->memory.cam && gb->memory.cam->startRequestImage) {
+ gb->memory.cam->startRequestImage(gb->memory.cam, GBCAM_WIDTH, GBCAM_HEIGHT, mCOLOR_ANY);
+ }
break;
}
@@ -230,6 +277,15 @@ void GBMBCInit(struct GB* gb) {
gb->memory.rtcAccess = false;
gb->memory.activeRtcReg = 0;
gb->memory.rtcLatched = false;
+ gb->memory.rtcLastLatch = 0;
+ if (gb->memory.rtc) {
+ if (gb->memory.rtc->sample) {
+ gb->memory.rtc->sample(gb->memory.rtc);
+ }
+ gb->memory.rtcLastLatch = gb->memory.rtc->unixTime(gb->memory.rtc);
+ } else {
+ gb->memory.rtcLastLatch = time(0);
+ }
memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
GBResizeSram(gb, gb->sramSize);
@@ -462,11 +518,34 @@ void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
}
void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
- // TODO
- mLOG(GB_MBC, STUB, "MBC6 unimplemented");
- UNUSED(gb);
- UNUSED(address);
- UNUSED(value);
+ struct GBMemory* memory = &gb->memory;
+ int bank = value & 0x7F;
+ switch (address >> 10) {
+ case 0:
+ switch (value) {
+ case 0:
+ memory->sramAccess = false;
+ break;
+ case 0xA:
+ memory->sramAccess = true;
+ GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
+ break;
+ default:
+ // TODO
+ mLOG(GB_MBC, STUB, "MBC6 unknown value %02X", value);
+ break;
+ }
+ break;
+ case 0x9:
+ GBMBCSwitchHalfBank(gb, 0, bank);
+ break;
+ case 0xD:
+ GBMBCSwitchHalfBank(gb, 1, bank);
+ break;
+ default:
+ mLOG(GB_MBC, STUB, "MBC6 unknown address: %04X:%02X", address, value);
+ break;
+ }
}
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
@@ -493,6 +572,8 @@ void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
gb->memory.mbcState.mbc7.access &= ~2;
}
break;
+ case 0x5:
+ _GBMBC7Write(&gb->memory, address, value);
default:
// TODO
mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
@@ -547,7 +628,7 @@ uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
}
}
-void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
+static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
if (mbc7->access != 3) {
return;
@@ -734,6 +815,16 @@ void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value) {
memory->mbcState.pocketCam.registersActive = true;
}
break;
+ case 0x5:
+ address &= 0x7F;
+ if (address == 0 && value & 1) {
+ value &= 6; // TODO: Timing
+ _GBPocketCamCapture(memory);
+ }
+ if (address < sizeof(memory->mbcState.pocketCam.registers)) {
+ memory->mbcState.pocketCam.registers[address] = value;
+ }
+ break;
default:
mLOG(GB_MBC, STUB, "Pocket Cam unknown address: %04X:%02X", address, value);
break;
@@ -742,12 +833,170 @@ void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value) {
uint8_t _GBPocketCamRead(struct GBMemory* memory, uint16_t address) {
if (memory->mbcState.pocketCam.registersActive) {
+ if ((address & 0x7F) == 0) {
+ return memory->mbcState.pocketCam.registers[0];
+ }
return 0;
}
- if (!memory->sramAccess) {
+ return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
+}
+
+void _GBPocketCamCapture(struct GBMemory* memory) {
+ if (!memory->cam) {
+ return;
+ }
+ const void* image = NULL;
+ size_t stride;
+ enum mColorFormat format;
+ memory->cam->requestImage(memory->cam, &image, &stride, &format);
+ if (!image) {
+ return;
+ }
+ memset(&memory->sram[0x100], 0, GBCAM_HEIGHT * GBCAM_WIDTH / 4);
+ struct GBPocketCamState* pocketCam = &memory->mbcState.pocketCam;
+ size_t x, y;
+ for (y = 0; y < GBCAM_HEIGHT; ++y) {
+ for (x = 0; x < GBCAM_WIDTH; ++x) {
+ uint32_t gray;
+ uint32_t color;
+ switch (format) {
+ case mCOLOR_XBGR8:
+ case mCOLOR_XRGB8:
+ case mCOLOR_ARGB8:
+ case mCOLOR_ABGR8:
+ color = ((const uint32_t*) image)[y * stride + x];
+ gray = (color & 0xFF) + ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF);
+ break;
+ case mCOLOR_BGRX8:
+ case mCOLOR_RGBX8:
+ case mCOLOR_RGBA8:
+ case mCOLOR_BGRA8:
+ color = ((const uint32_t*) image)[y * stride + x];
+ gray = ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF) + ((color >> 24) & 0xFF);
+ break;
+ case mCOLOR_BGR5:
+ case mCOLOR_RGB5:
+ case mCOLOR_ARGB5:
+ case mCOLOR_ABGR5:
+ color = ((const uint16_t*) image)[y * stride + x];
+ gray = ((color << 3) & 0xF8) + ((color >> 2) & 0xF8) + ((color >> 7) & 0xF8);
+ break;
+ case mCOLOR_BGR565:
+ case mCOLOR_RGB565:
+ color = ((const uint16_t*) image)[y * stride + x];
+ gray = ((color << 3) & 0xF8) + ((color >> 3) & 0xFC) + ((color >> 8) & 0xF8);
+ break;
+ case mCOLOR_BGRA5:
+ case mCOLOR_RGBA5:
+ color = ((const uint16_t*) image)[y * stride + x];
+ gray = ((color << 2) & 0xF8) + ((color >> 3) & 0xF8) + ((color >> 8) & 0xF8);
+ break;
+ default:
+ mLOG(GB_MBC, WARN, "Unsupported pixel format: %X", format);
+ return;
+ }
+ uint16_t exposure = (pocketCam->registers[2] << 8) | (pocketCam->registers[3]);
+ gray = (gray + 1) * exposure / 0x300;
+ // TODO: Additional processing
+ int matrixEntry = 3 * ((x & 3) + 4 * (y & 3));
+ if (gray < pocketCam->registers[matrixEntry + 6]) {
+ gray = 0x101;
+ } else if (gray < pocketCam->registers[matrixEntry + 7]) {
+ gray = 0x100;
+ } else if (gray < pocketCam->registers[matrixEntry + 8]) {
+ gray = 0x001;
+ } else {
+ gray = 0;
+ }
+ int coord = (((x >> 3) & 0xF) * 8 + (y & 0x7)) * 2 + (y & ~0x7) * 0x20;
+ uint16_t existing;
+ LOAD_16LE(existing, coord + 0x100, memory->sram);
+ existing |= gray << (7 - (x & 7));
+ STORE_16LE(existing, coord + 0x100, memory->sram);
+ }
+ }
+}
+
+void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
+ struct GBMemory* memory = &gb->memory;
+ struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
+ switch (address >> 13) {
+ case 0x5:
+ if (address & 1) {
+ tama5->reg = value;
+ } else {
+ value &= 0xF;
+ if (tama5->reg < GBTAMA5_MAX) {
+ tama5->registers[tama5->reg] = value;
+ uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
+ uint8_t out = (tama5->registers[GBTAMA5_WRITE_HI] << 4) | tama5->registers[GBTAMA5_WRITE_LO];
+ switch (tama5->reg) {
+ case GBTAMA5_BANK_LO:
+ case GBTAMA5_BANK_HI:
+ GBMBCSwitchBank(gb, tama5->registers[GBTAMA5_BANK_LO] | (tama5->registers[GBTAMA5_BANK_HI] << 4));
+ break;
+ case GBTAMA5_WRITE_LO:
+ case GBTAMA5_WRITE_HI:
+ case GBTAMA5_CS:
+ break;
+ case GBTAMA5_ADDR_LO:
+ switch (tama5->registers[GBTAMA5_CS] >> 1) {
+ case 0x0: // RAM write
+ memory->sram[address] = out;
+ break;
+ case 0x1: // RAM read
+ break;
+ default:
+ mLOG(GB_MBC, STUB, "TAMA5 unknown address: %X-%02X:%02X", tama5->registers[GBTAMA5_CS] >> 1, address, out);
+ }
+ break;
+ default:
+ mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X:%X", tama5->reg, value);
+ break;
+ }
+ } else {
+ mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X", tama5->reg);
+ }
+ }
+ break;
+ default:
+ mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X:%02X", address, value);
+ }
+}
+
+uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) {
+ struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
+ if ((address & 0x1FFF) > 1) {
+ mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X", address);
+ }
+ if (address & 1) {
return 0xFF;
+ } else {
+ uint8_t value = 0xF0;
+ uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
+ switch (tama5->reg) {
+ case GBTAMA5_ACTIVE:
+ return 0xF1;
+ case GBTAMA5_READ_LO:
+ case GBTAMA5_READ_HI:
+ switch (tama5->registers[GBTAMA5_CS] >> 1) {
+ case 1:
+ value = memory->sram[address];
+ break;
+ default:
+ mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
+ break;
+ }
+ if (tama5->reg == GBTAMA5_READ_HI) {
+ value >>= 4;
+ }
+ value |= 0xF0;
+ return value;
+ default:
+ mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
+ return 0xF1;
+ }
}
- return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
}
void GBMBCRTCRead(struct GB* gb) {
@@ -756,17 +1005,10 @@ void GBMBCRTCRead(struct GB* gb) {
if (!vf) {
return;
}
- ssize_t end = vf->seek(vf, -sizeof(rtcBuffer), SEEK_END);
- switch (end & 0x1FFF) {
- case 0:
- break;
- case 0x1FFC:
- vf->seek(vf, -sizeof(rtcBuffer) - 4, SEEK_END);
- break;
- default:
+ vf->seek(vf, gb->sramSize, SEEK_SET);
+ if (vf->read(vf, &rtcBuffer, sizeof(rtcBuffer)) < (ssize_t) sizeof(rtcBuffer) - 4) {
return;
}
- vf->read(vf, &rtcBuffer, sizeof(rtcBuffer));
LOAD_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
LOAD_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
@@ -798,9 +1040,9 @@ void GBMBCRTCWrite(struct GB* gb) {
STORE_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
STORE_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
- STORE_64LE(rtcLastLatch, 0, &rtcBuffer.unixTime);
+ STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
- if (vf->size(vf) == gb->sramSize) {
+ if ((size_t) vf->size(vf) < gb->sramSize + sizeof(rtcBuffer)) {
// Writing past the end of the file can invalidate the file mapping
vf->unmap(vf, gb->memory.sram, gb->sramSize);
gb->memory.sram = NULL;
Oops, something went wrong.