mirror of https://github.com/mgba-emu/mgba.git
LR35902, GB: Start work on GB core
This commit is contained in:
parent
811d654893
commit
64676529ba
|
@ -31,7 +31,9 @@ set(BUILD_GLES2 OFF CACHE STRING "Build with OpenGL|ES 2")
|
|||
set(USE_EPOXY ON CACHE STRING "Build with libepoxy")
|
||||
set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies")
|
||||
file(GLOB ARM_SRC ${CMAKE_SOURCE_DIR}/src/arm/*.c)
|
||||
file(GLOB LR35902_SRC ${CMAKE_SOURCE_DIR}/src/lr35902/*.c)
|
||||
file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
|
||||
file(GLOB GB_SRC ${CMAKE_SOURCE_DIR}/src/gb/*.c)
|
||||
file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c)
|
||||
file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c)
|
||||
file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)
|
||||
|
@ -45,8 +47,10 @@ list(APPEND GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
|
|||
set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c)
|
||||
set(VFS_SRC)
|
||||
source_group("ARM core" FILES ${ARM_SRC})
|
||||
source_group("LR35902 core" FILES ${LR35902_SRC})
|
||||
source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC})
|
||||
source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_CTX_SRC} ${GBA_SV_SRC} ${GBA_RR_SRC})
|
||||
source_group("GB board" FILES ${GBA_SRC})
|
||||
source_group("Utilities" FILES ${UTIL_SRC})
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/arm)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
|
@ -492,7 +496,9 @@ endif()
|
|||
# Binaries
|
||||
set(CORE_SRC
|
||||
${ARM_SRC}
|
||||
${LR35902_SRC}
|
||||
${GBA_SRC}
|
||||
${GB_SRC}
|
||||
${GBA_CHEATS_SRC}
|
||||
${GBA_CTX_SRC}
|
||||
${DEBUGGER_SRC}
|
||||
|
@ -621,6 +627,10 @@ if(BUILD_TEST)
|
|||
target_link_libraries(${BINARY_NAME}-fuzz ${BINARY_NAME})
|
||||
set_target_properties(${BINARY_NAME}-fuzz PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
|
||||
install(TARGETS ${BINARY_NAME}-fuzz DESTINATION bin COMPONENT ${BINARY_NAME}-test)
|
||||
|
||||
add_executable(${BINARY_NAME}-gb ${CMAKE_SOURCE_DIR}/src/platform/test/gb-main.c)
|
||||
target_link_libraries(${BINARY_NAME}-gb ${BINARY_NAME})
|
||||
set_target_properties(${BINARY_NAME}-gb PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
|
||||
endif()
|
||||
|
||||
# Packaging
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gb.h"
|
||||
|
||||
#include "util/crc32.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
#include "util/patch.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
const uint32_t DMG_LR35902_FREQUENCY = 0x400000;
|
||||
const uint32_t CGB_LR35902_FREQUENCY = 0x800000;
|
||||
const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E;
|
||||
|
||||
const uint32_t GB_COMPONENT_MAGIC = 0x400000;
|
||||
|
||||
static void GBInit(struct LR35902Core* cpu, struct LR35902Component* component);
|
||||
static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
|
||||
static void GBProcessEvents(struct LR35902Core* cpu);
|
||||
static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
|
||||
static void GBHitStub(struct LR35902Core* cpu);
|
||||
|
||||
void GBCreate(struct GB* gb) {
|
||||
gb->d.id = GB_COMPONENT_MAGIC;
|
||||
gb->d.init = GBInit;
|
||||
gb->d.deinit = 0;
|
||||
}
|
||||
|
||||
static void GBInit(struct LR35902Core* cpu, struct LR35902Component* component) {
|
||||
struct GB* gba = (struct GB*) component;
|
||||
gba->cpu = cpu;
|
||||
|
||||
GBInterruptHandlerInit(&cpu->irqh);
|
||||
GBMemoryInit(gba);
|
||||
|
||||
gba->romVf = 0;
|
||||
|
||||
gba->pristineRom = 0;
|
||||
gba->pristineRomSize = 0;
|
||||
gba->yankedRomSize = 0;
|
||||
}
|
||||
|
||||
bool GBLoadROM(struct GB* gb, struct VFile* vf, struct VFile* sav, const char* fname) {
|
||||
GBUnloadROM(gb);
|
||||
gb->romVf = vf;
|
||||
gb->pristineRomSize = vf->size(vf);
|
||||
vf->seek(vf, 0, SEEK_SET);
|
||||
#ifdef _3DS
|
||||
gb->pristineRom = 0;
|
||||
if (gb->pristineRomSize <= romBufferSize) {
|
||||
gb->pristineRom = romBuffer;
|
||||
vf->read(vf, romBuffer, gb->pristineRomSize);
|
||||
}
|
||||
#else
|
||||
gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ);
|
||||
#endif
|
||||
if (!gb->pristineRom) {
|
||||
return false;
|
||||
}
|
||||
gb->yankedRomSize = 0;
|
||||
gb->memory.rom = gb->pristineRom;
|
||||
gb->activeFile = fname;
|
||||
gb->memory.romSize = gb->pristineRomSize;
|
||||
gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
|
||||
return true;
|
||||
// TODO: error check
|
||||
}
|
||||
|
||||
void GBUnloadROM(struct GB* gb) {
|
||||
// TODO: Share with GBAUnloadROM
|
||||
if (gb->memory.rom && gb->pristineRom != gb->memory.rom) {
|
||||
if (gb->yankedRomSize) {
|
||||
gb->yankedRomSize = 0;
|
||||
}
|
||||
mappedMemoryFree(gb->memory.rom, 0x400000);
|
||||
}
|
||||
gb->memory.rom = 0;
|
||||
|
||||
if (gb->romVf) {
|
||||
#ifndef _3DS
|
||||
gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize);
|
||||
#endif
|
||||
gb->pristineRom = 0;
|
||||
gb->romVf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GBDestroy(struct GB* gb) {
|
||||
GBUnloadROM(gb);
|
||||
|
||||
GBMemoryDeinit(gb);
|
||||
}
|
||||
|
||||
void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
|
||||
irqh->reset = GBReset;
|
||||
irqh->processEvents = GBProcessEvents;
|
||||
irqh->setInterrupts = GBSetInterrupts;
|
||||
irqh->hitStub = GBHitStub;
|
||||
}
|
||||
|
||||
void GBReset(struct LR35902Core* cpu) {
|
||||
cpu->a = 1;
|
||||
cpu->f.packed = 0xB0;
|
||||
cpu->b = 0;
|
||||
cpu->c = 0x13;
|
||||
cpu->d = 0;
|
||||
cpu->e = 0xD8;
|
||||
cpu->h = 1;
|
||||
cpu->l = 0x4D;
|
||||
cpu->sp = 0xFFFE;
|
||||
cpu->pc = 0x100;
|
||||
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
|
||||
if (gb->yankedRomSize) {
|
||||
gb->memory.romSize = gb->yankedRomSize;
|
||||
gb->yankedRomSize = 0;
|
||||
}
|
||||
GBMemoryReset(gb);
|
||||
}
|
||||
|
||||
void GBProcessEvents(struct LR35902Core* cpu) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GBHitStub(struct LR35902Core* cpu) {
|
||||
// TODO
|
||||
printf("Hit stub at address %04X\n", cpu->pc);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GB_H
|
||||
#define GB_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "lr35902/lr35902.h"
|
||||
|
||||
#include "gb/memory.h"
|
||||
|
||||
extern const uint32_t DMG_LR35902_FREQUENCY;
|
||||
extern const uint32_t CGB_LR35902_FREQUENCY;
|
||||
extern const uint32_t SGB_LR35902_FREQUENCY;
|
||||
|
||||
// TODO: Prefix GBAIRQ
|
||||
enum GBIRQ {
|
||||
GB_IRQ_VBLANK = 0x0,
|
||||
GB_IRQ_LCDSTAT = 0x1,
|
||||
GB_IRQ_TIMER = 0x2,
|
||||
GB_IRQ_SIO = 0x3,
|
||||
GB_IRQ_KEYPAD = 0x4,
|
||||
};
|
||||
|
||||
struct GB {
|
||||
struct LR35902Component d;
|
||||
|
||||
struct LR35902Core* cpu;
|
||||
struct GBMemory memory;
|
||||
|
||||
int* keySource;
|
||||
|
||||
void* pristineRom;
|
||||
size_t pristineRomSize;
|
||||
size_t yankedRomSize;
|
||||
uint32_t romCrc32;
|
||||
struct VFile* romVf;
|
||||
|
||||
const char* activeFile;
|
||||
};
|
||||
|
||||
void GBCreate(struct GB* gb);
|
||||
void GBDestroy(struct GB* gb);
|
||||
|
||||
void GBReset(struct LR35902Core* cpu);
|
||||
|
||||
void GBWriteIE(struct GB* gb, uint8_t value);
|
||||
void GBRaiseIRQ(struct GB* gb, enum GBIRQ irq);
|
||||
void GBTestIRQ(struct LR35902Core* cpu);
|
||||
void GBHalt(struct GB* gb);
|
||||
void GBStop(struct GB* gb);
|
||||
|
||||
struct VFile;
|
||||
bool GBLoadROM(struct GB* gb, struct VFile* vf, struct VFile* sav, const char* fname);
|
||||
void GBYankROM(struct GB* gb);
|
||||
void GBUnloadROM(struct GB* gb);
|
||||
|
||||
struct Patch;
|
||||
void GBApplyPatch(struct GB* gb, struct Patch* patch);
|
||||
|
||||
bool GBIsROM(struct VFile* vf);
|
||||
|
||||
void GBFrameStarted(struct GB* gb);
|
||||
void GBFrameEnded(struct GB* gb);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,133 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "memory.h"
|
||||
|
||||
#include "gb/gb.h"
|
||||
|
||||
#include "util/memory.h"
|
||||
|
||||
static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GBMemoryInit(struct GB* gb) {
|
||||
struct LR35902Core* cpu = gb->cpu;
|
||||
cpu->memory.load16 = GBLoad16;
|
||||
cpu->memory.load8 = GBLoad8;
|
||||
cpu->memory.store16 = GBStore16;
|
||||
cpu->memory.store8 = GBStore8;
|
||||
cpu->memory.setActiveRegion = GBSetActiveRegion;
|
||||
|
||||
gb->memory.wram = 0;
|
||||
gb->memory.wramBank = 0;
|
||||
gb->memory.rom = 0;
|
||||
gb->memory.romBank = 0;
|
||||
gb->memory.romSize = 0;
|
||||
}
|
||||
|
||||
void GBMemoryDeinit(struct GB* gb) {
|
||||
mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
|
||||
if (gb->memory.rom) {
|
||||
mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
|
||||
}
|
||||
}
|
||||
|
||||
void GBMemoryReset(struct GB* gb) {
|
||||
if (gb->memory.wram) {
|
||||
mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
|
||||
}
|
||||
gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
|
||||
gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
|
||||
gb->memory.romBank = &gb->memory.rom[GB_BASE_CART_BANK0];
|
||||
|
||||
if (!gb->memory.wram) {
|
||||
GBMemoryDeinit(gb);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
switch (address >> 12) {
|
||||
case GB_REGION_CART_BANK0:
|
||||
case GB_REGION_CART_BANK0 + 1:
|
||||
case GB_REGION_CART_BANK0 + 2:
|
||||
case GB_REGION_CART_BANK0 + 3:
|
||||
return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
case GB_REGION_CART_BANK1:
|
||||
case GB_REGION_CART_BANK1 + 1:
|
||||
case GB_REGION_CART_BANK1 + 2:
|
||||
case GB_REGION_CART_BANK1 + 3:
|
||||
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
case GB_REGION_VRAM:
|
||||
case GB_REGION_VRAM + 1:
|
||||
// TODO
|
||||
return 0;
|
||||
case GB_REGION_EXTERNAL_RAM:
|
||||
case GB_REGION_EXTERNAL_RAM + 1:
|
||||
// TODO
|
||||
return 0;
|
||||
case GB_REGION_WORKING_RAM_BANK0:
|
||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||
case GB_REGION_WORKING_RAM_BANK1:
|
||||
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||
default:
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
switch (address >> 12) {
|
||||
case GB_REGION_CART_BANK0:
|
||||
case GB_REGION_CART_BANK0 + 1:
|
||||
case GB_REGION_CART_BANK0 + 2:
|
||||
case GB_REGION_CART_BANK0 + 3:
|
||||
// TODO
|
||||
return;
|
||||
case GB_REGION_CART_BANK1:
|
||||
case GB_REGION_CART_BANK1 + 1:
|
||||
case GB_REGION_CART_BANK1 + 2:
|
||||
case GB_REGION_CART_BANK1 + 3:
|
||||
// TODO
|
||||
return;
|
||||
case GB_REGION_VRAM:
|
||||
case GB_REGION_VRAM + 1:
|
||||
// TODO
|
||||
return;
|
||||
case GB_REGION_EXTERNAL_RAM:
|
||||
case GB_REGION_EXTERNAL_RAM + 1:
|
||||
// TODO
|
||||
return;
|
||||
case GB_REGION_WORKING_RAM_BANK0:
|
||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||
memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
||||
return;
|
||||
case GB_REGION_WORKING_RAM_BANK1:
|
||||
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
||||
return;
|
||||
default:
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
|
||||
uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
|
||||
|
||||
void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
|
||||
void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
|
|
@ -0,0 +1,77 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GB_MEMORY_H
|
||||
#define GB_MEMORY_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "lr35902/lr35902.h"
|
||||
|
||||
struct GB;
|
||||
|
||||
enum {
|
||||
GB_BASE_CART_BANK0 = 0x0000,
|
||||
GB_BASE_CART_BANK1 = 0x4000,
|
||||
GB_BASE_VRAM = 0x8000,
|
||||
GB_BASE_EXTERNAL_RAM = 0xA000,
|
||||
GB_BASE_WORKING_RAM_BANK0 = 0xC000,
|
||||
GB_BASE_WORKING_RAM_BANK1 = 0xD000,
|
||||
GB_BASE_OAM = 0xFE00,
|
||||
GB_BASE_IO = 0xFF00,
|
||||
GB_BASE_HRAM = 0xFF80,
|
||||
GB_BASE_IE = 0xFFFF
|
||||
};
|
||||
|
||||
enum {
|
||||
GB_REGION_CART_BANK0 = 0x0,
|
||||
GB_REGION_CART_BANK1 = 0x4,
|
||||
GB_REGION_VRAM = 0x8,
|
||||
GB_REGION_EXTERNAL_RAM = 0xA,
|
||||
GB_REGION_WORKING_RAM_BANK0 = 0xC,
|
||||
GB_REGION_WORKING_RAM_BANK1 = 0xD,
|
||||
GB_REGION_WORKING_RAM_BANK1_MIRROR = 0xE,
|
||||
GB_REGION_OTHER = 0xF,
|
||||
};
|
||||
|
||||
enum {
|
||||
GB_SIZE_CART_BANK0 = 0x4000,
|
||||
GB_SIZE_VRAM = 0x2000,
|
||||
GB_SIZE_EXTERNAL_RAM = 0x2000,
|
||||
GB_SIZE_WORKING_RAM = 0x8000,
|
||||
GB_SIZE_WORKING_RAM_BANK0 = 0x1000,
|
||||
GB_SIZE_OAM = 0xA0,
|
||||
GB_SIZE_IO = 0x80,
|
||||
GB_SIZE_HRAM = 0x7F,
|
||||
};
|
||||
|
||||
struct GBMemory {
|
||||
uint8_t* rom;
|
||||
uint8_t* romBank;
|
||||
|
||||
uint8_t* wram;
|
||||
uint8_t* wramBank;
|
||||
|
||||
size_t romSize;
|
||||
};
|
||||
|
||||
void GBMemoryInit(struct GB* gb);
|
||||
void GBMemoryDeinit(struct GB* gb);
|
||||
|
||||
void GBMemoryReset(struct GB* gb);
|
||||
|
||||
uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address);
|
||||
uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address);
|
||||
|
||||
void GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value);
|
||||
void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value);
|
||||
|
||||
uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
|
||||
uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
|
||||
|
||||
void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
|
||||
void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,227 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "isa-lr35902.h"
|
||||
|
||||
#include "lr35902/emitter-lr35902.h"
|
||||
#include "lr35902/lr35902.h"
|
||||
|
||||
#define DEFINE_INSTRUCTION_LR35902(NAME, BODY) \
|
||||
static void _LR35902Instruction ## NAME (struct LR35902Core* cpu) { \
|
||||
UNUSED(cpu); \
|
||||
BODY; \
|
||||
}
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(NOP,);
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(JPFinish,
|
||||
if (cpu->condition) {
|
||||
cpu->pc = (cpu->bus << 8) | cpu->index;
|
||||
cpu->memory.setActiveRegion(cpu, cpu->pc);
|
||||
// TODO: Stall properly
|
||||
cpu->cycles += 4;
|
||||
})
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(JPDelay,
|
||||
cpu->executionState = LR35902_CORE_READ_PC;
|
||||
cpu->instruction = _LR35902InstructionJPFinish;
|
||||
cpu->index = cpu->bus;)
|
||||
|
||||
#define DEFINE_JP_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
|
||||
DEFINE_INSTRUCTION_LR35902(JP ## CONDITION_NAME, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionJPDelay; \
|
||||
cpu->condition = CONDITION;)
|
||||
|
||||
DEFINE_JP_INSTRUCTION_LR35902(, true);
|
||||
DEFINE_JP_INSTRUCTION_LR35902(C, cpu->f.c);
|
||||
DEFINE_JP_INSTRUCTION_LR35902(Z, cpu->f.z);
|
||||
DEFINE_JP_INSTRUCTION_LR35902(NC, !cpu->f.c);
|
||||
DEFINE_JP_INSTRUCTION_LR35902(NZ, !cpu->f.z);
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(JRFinish,
|
||||
if (cpu->condition) {
|
||||
cpu->pc += (int8_t) cpu->bus;
|
||||
cpu->memory.setActiveRegion(cpu, cpu->pc);
|
||||
// TODO: Stall properly
|
||||
cpu->cycles += 4;
|
||||
})
|
||||
|
||||
#define DEFINE_JR_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
|
||||
DEFINE_INSTRUCTION_LR35902(JR ## CONDITION_NAME, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionJRFinish; \
|
||||
cpu->condition = CONDITION;)
|
||||
|
||||
DEFINE_JR_INSTRUCTION_LR35902(, true);
|
||||
DEFINE_JR_INSTRUCTION_LR35902(C, cpu->f.c);
|
||||
DEFINE_JR_INSTRUCTION_LR35902(Z, cpu->f.z);
|
||||
DEFINE_JR_INSTRUCTION_LR35902(NC, !cpu->f.c);
|
||||
DEFINE_JR_INSTRUCTION_LR35902(NZ, !cpu->f.z);
|
||||
|
||||
#define DEFINE_AND_INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(AND ## NAME, \
|
||||
cpu->a &= OPERAND; \
|
||||
cpu->f.z = !cpu->a; \
|
||||
cpu->f.n = 0; \
|
||||
cpu->f.c = 0; \
|
||||
cpu->f.h = 1;)
|
||||
|
||||
#define DEFINE_XOR_INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(XOR ## NAME, \
|
||||
cpu->a ^= OPERAND; \
|
||||
cpu->f.z = !cpu->a; \
|
||||
cpu->f.n = 0; \
|
||||
cpu->f.c = 0; \
|
||||
cpu->f.h = 0;)
|
||||
|
||||
#define DEFINE_OR_INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(OR ## NAME, \
|
||||
cpu->a |= OPERAND; \
|
||||
cpu->f.z = !cpu->a; \
|
||||
cpu->f.n = 0; \
|
||||
cpu->f.c = 0; \
|
||||
cpu->f.h = 0;)
|
||||
|
||||
#define DEFINE_CP_INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(CP ## NAME, \
|
||||
int diff = cpu->a - OPERAND; \
|
||||
cpu->f.n = 1; \
|
||||
cpu->f.z = !diff; \
|
||||
cpu->f.c = diff < 0; \
|
||||
/* TODO: Find explanation of H flag */)
|
||||
|
||||
#define DEFINE_LDB__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDB_ ## NAME, \
|
||||
cpu->b = OPERAND;)
|
||||
|
||||
#define DEFINE_LDC__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDC_ ## NAME, \
|
||||
cpu->c = OPERAND;)
|
||||
|
||||
#define DEFINE_LDD__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDD_ ## NAME, \
|
||||
cpu->d = OPERAND;)
|
||||
|
||||
#define DEFINE_LDE__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDE_ ## NAME, \
|
||||
cpu->e = OPERAND;)
|
||||
|
||||
#define DEFINE_LDH__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDH_ ## NAME, \
|
||||
cpu->h = OPERAND;)
|
||||
|
||||
#define DEFINE_LDL__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDL_ ## NAME, \
|
||||
cpu->l = OPERAND;)
|
||||
|
||||
#define DEFINE_LDHL__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDHL_ ## NAME, \
|
||||
cpu->bus = OPERAND; \
|
||||
cpu->executionState = LR35902_CORE_MEMORY_MOVE_INDEX_STORE; \
|
||||
cpu->instruction = _LR35902InstructionLDHL_Bus;)
|
||||
|
||||
#define DEFINE_LDA__INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LDA_ ## NAME, \
|
||||
cpu->a = OPERAND;)
|
||||
|
||||
#define DEFINE_LD_INSTRUCTION_LR35902(NAME, OPERAND) \
|
||||
DEFINE_INSTRUCTION_LR35902(LD ## NAME, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLD ## NAME ## _Bus;)
|
||||
|
||||
#define DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME) \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(A, cpu->a); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(B, cpu->b); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, cpu->c); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(D, cpu->d); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(E, cpu->e); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(H, cpu->h); \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(L, cpu->l);
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDHL_Bus, \
|
||||
cpu->index = LR35902ReadHL(cpu); \
|
||||
cpu->executionState = LR35902_CORE_MEMORY_MOVE_INDEX_STORE; \
|
||||
cpu->instruction = _LR35902InstructionNOP;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDHL, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLDHL_Bus;)
|
||||
|
||||
#define DEFINE_ALU_INSTRUCTION_LR35902(NAME) \
|
||||
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Bus, cpu->bus); \
|
||||
DEFINE_INSTRUCTION_LR35902(NAME ## HL, \
|
||||
cpu->executionState = LR35902_CORE_MEMORY_MOVE_INDEX_LOAD; \
|
||||
cpu->index = LR35902ReadHL(cpu); \
|
||||
cpu->instruction = _LR35902Instruction ## NAME ## Bus;) \
|
||||
DEFINE_INSTRUCTION_LR35902(NAME, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902Instruction ## NAME ## Bus;) \
|
||||
DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME)
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(AND);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(XOR);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(OR);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(CP);
|
||||
|
||||
static void _LR35902InstructionLDB_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDC_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDD_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDE_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDH_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDL_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDHL_Bus(struct LR35902Core*);
|
||||
static void _LR35902InstructionLDA_Bus(struct LR35902Core*);
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDB_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDC_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDD_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDE_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDH_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDL_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902_NOHL(LDHL_);
|
||||
DEFINE_ALU_INSTRUCTION_LR35902(LDA_);
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDIAFinish, \
|
||||
cpu->index |= cpu->bus << 8;
|
||||
cpu->bus = cpu->a; \
|
||||
cpu->executionState = LR35902_CORE_MEMORY_MOVE_INDEX_STORE; \
|
||||
cpu->instruction = _LR35902InstructionNOP;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDIADelay, \
|
||||
cpu->index = cpu->bus;
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLDIAFinish;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDIA, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLDIADelay;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDAIFinish, \
|
||||
cpu->index |= cpu->bus << 8;
|
||||
cpu->executionState = LR35902_CORE_MEMORY_MOVE_INDEX_LOAD; \
|
||||
cpu->instruction = _LR35902InstructionLDA_Bus;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDAIDelay, \
|
||||
cpu->index = cpu->bus;
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLDAIFinish;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(LDAI, \
|
||||
cpu->executionState = LR35902_CORE_READ_PC; \
|
||||
cpu->instruction = _LR35902InstructionLDAIDelay;)
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(DI, cpu->irqh.setInterrupts(cpu, false));
|
||||
DEFINE_INSTRUCTION_LR35902(EI, cpu->irqh.setInterrupts(cpu, true));
|
||||
|
||||
DEFINE_INSTRUCTION_LR35902(STUB, cpu->irqh.hitStub(cpu));
|
||||
|
||||
const LR35902Instruction _lr35902InstructionTable[0x100] = {
|
||||
DECLARE_LR35902_EMITTER_BLOCK(_LR35902Instruction)
|
||||
};
|
||||
|
||||
const LR35902Instruction _lr35902CBInstructionTable[0x100] = {
|
||||
DECLARE_LR35902_CB_EMITTER_BLOCK(_LR35902Instruction)
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef ISA_LR35902_H
|
||||
#define ISA_LR35902_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
struct LR35902Core;
|
||||
|
||||
typedef void (*LR35902Instruction)(struct LR35902Core*);
|
||||
const LR35902Instruction _lr35902InstructionTable[0x100];
|
||||
const LR35902Instruction _lr35902CBInstructionTable[0x100];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,116 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "lr35902.h"
|
||||
|
||||
#include "isa-lr35902.h"
|
||||
|
||||
void LR35902Init(struct LR35902Core* cpu) {
|
||||
cpu->master->init(cpu, cpu->master);
|
||||
size_t i;
|
||||
for (i = 0; i < cpu->numComponents; ++i) {
|
||||
if (cpu->components[i] && cpu->components[i]->init) {
|
||||
cpu->components[i]->init(cpu, cpu->components[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LR35902Deinit(struct LR35902Core* cpu) {
|
||||
if (cpu->master->deinit) {
|
||||
cpu->master->deinit(cpu->master);
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < cpu->numComponents; ++i) {
|
||||
if (cpu->components[i] && cpu->components[i]->deinit) {
|
||||
cpu->components[i]->deinit(cpu->components[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LR35902SetComponents(struct LR35902Core* cpu, struct LR35902Component* master, int extra, struct LR35902Component** extras) {
|
||||
cpu->master = master;
|
||||
cpu->numComponents = extra;
|
||||
cpu->components = extras;
|
||||
}
|
||||
|
||||
|
||||
void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot) {
|
||||
if (slot >= cpu->numComponents) {
|
||||
return;
|
||||
}
|
||||
cpu->components[slot]->init(cpu, cpu->components[slot]);
|
||||
}
|
||||
|
||||
void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot) {
|
||||
if (slot >= cpu->numComponents) {
|
||||
return;
|
||||
}
|
||||
cpu->components[slot]->deinit(cpu->components[slot]);
|
||||
}
|
||||
|
||||
void LR35902Reset(struct LR35902Core* cpu) {
|
||||
cpu->af = 0;
|
||||
cpu->bc = 0;
|
||||
cpu->de = 0;
|
||||
cpu->hl = 0;
|
||||
|
||||
cpu->sp = 0;
|
||||
cpu->pc = 0;
|
||||
|
||||
cpu->instruction = 0;
|
||||
|
||||
cpu->cycles = 0;
|
||||
cpu->nextEvent = 0;
|
||||
cpu->executionState = LR35902_CORE_FETCH;
|
||||
cpu->halted = 0;
|
||||
|
||||
cpu->irqh.reset(cpu);
|
||||
}
|
||||
|
||||
void LR35902RaiseIRQ(struct LR35902Core* cpu) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void LR35902Tick(struct LR35902Core* cpu) {
|
||||
++cpu->cycles;
|
||||
enum LR35902ExecutionState state = cpu->executionState;
|
||||
++cpu->executionState;
|
||||
cpu->executionState &= 3;
|
||||
switch (state) {
|
||||
case LR35902_CORE_FETCH:
|
||||
cpu->bus = cpu->memory.load8(cpu, cpu->pc);
|
||||
break;
|
||||
case LR35902_CORE_DECODE:
|
||||
cpu->instruction = _lr35902InstructionTable[cpu->bus];
|
||||
++cpu->pc;
|
||||
break;
|
||||
case LR35902_CORE_EXECUTE:
|
||||
cpu->instruction(cpu);
|
||||
break;
|
||||
case LR35902_CORE_MEMORY_LOAD:
|
||||
cpu->bus = cpu->memory.load8(cpu, cpu->index);
|
||||
break;
|
||||
case LR35902_CORE_MEMORY_STORE:
|
||||
cpu->memory.store8(cpu, cpu->index, cpu->bus);
|
||||
break;
|
||||
case LR35902_CORE_READ_PC:
|
||||
cpu->bus = cpu->memory.load8(cpu, cpu->pc);
|
||||
++cpu->pc;
|
||||
cpu->executionState = LR35902_CORE_READ_PC_STALL;
|
||||
break;
|
||||
case LR35902_CORE_MEMORY_MOVE_INDEX_LOAD:
|
||||
cpu->executionState = LR35902_CORE_MEMORY_LOAD;
|
||||
break;
|
||||
case LR35902_CORE_MEMORY_MOVE_INDEX_STORE:
|
||||
cpu->executionState = LR35902_CORE_MEMORY_STORE;
|
||||
break;
|
||||
case LR35902_CORE_READ_PC_STALL:
|
||||
case LR35902_CORE_STALL:
|
||||
break;
|
||||
}
|
||||
if (cpu->cycles >= cpu->nextEvent) {
|
||||
cpu->irqh.processEvents(cpu);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef LR35902_H
|
||||
#define LR35902_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "lr35902/isa-lr35902.h"
|
||||
|
||||
struct LR35902Core;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
union FlagRegister {
|
||||
struct {
|
||||
#if defined(__POWERPC__) || defined(__PPC__)
|
||||
unsigned z : 1;
|
||||
unsigned n : 1;
|
||||
unsigned h : 1;
|
||||
unsigned c : 1;
|
||||
unsigned : 4;
|
||||
#else
|
||||
unsigned : 4;
|
||||
unsigned c : 1;
|
||||
unsigned h : 1;
|
||||
unsigned n : 1;
|
||||
unsigned z : 1;
|
||||
#endif
|
||||
};
|
||||
|
||||
uint8_t packed;
|
||||
};
|
||||
#pragma pack(pop, 1)
|
||||
|
||||
enum LR35902ExecutionState {
|
||||
LR35902_CORE_FETCH = 0,
|
||||
LR35902_CORE_DECODE,
|
||||
LR35902_CORE_STALL,
|
||||
LR35902_CORE_EXECUTE,
|
||||
|
||||
LR35902_CORE_MEMORY_LOAD = 5,
|
||||
LR35902_CORE_MEMORY_STORE = 9,
|
||||
LR35902_CORE_MEMORY_MOVE_INDEX_LOAD,
|
||||
LR35902_CORE_MEMORY_MOVE_INDEX_STORE,
|
||||
LR35902_CORE_READ_PC,
|
||||
LR35902_CORE_READ_PC_STALL,
|
||||
};
|
||||
|
||||
struct LR35902Memory {
|
||||
uint16_t (*load16)(struct LR35902Core*, uint16_t address);
|
||||
uint8_t (*load8)(struct LR35902Core*, uint16_t address);
|
||||
|
||||
void (*store16)(struct LR35902Core*, uint16_t address, int16_t value);
|
||||
void (*store8)(struct LR35902Core*, uint16_t address, int8_t value);
|
||||
|
||||
uint8_t* activeRegion;
|
||||
uint16_t activeMask;
|
||||
void (*setActiveRegion)(struct LR35902Core*, uint16_t address);
|
||||
};
|
||||
|
||||
struct LR35902InterruptHandler {
|
||||
void (*reset)(struct LR35902Core* cpu);
|
||||
void (*processEvents)(struct LR35902Core* cpu);
|
||||
void (*setInterrupts)(struct LR35902Core* cpu, bool enable);
|
||||
|
||||
void (*hitStub)(struct LR35902Core* cpu);
|
||||
};
|
||||
|
||||
// TODO: Merge with ARMComponent?
|
||||
struct LR35902Component {
|
||||
uint32_t id;
|
||||
void (*init)(struct LR35902Core* cpu, struct LR35902Component* component);
|
||||
void (*deinit)(struct LR35902Component* component);
|
||||
};
|
||||
|
||||
struct LR35902Core {
|
||||
#pragma pack(push, 1)
|
||||
union {
|
||||
struct {
|
||||
union FlagRegister f;
|
||||
uint8_t a;
|
||||
};
|
||||
uint16_t af;
|
||||
};
|
||||
#pragma pack(pop, 1)
|
||||
union {
|
||||
struct {
|
||||
uint8_t c;
|
||||
uint8_t b;
|
||||
};
|
||||
uint16_t bc;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint8_t e;
|
||||
uint8_t d;
|
||||
};
|
||||
uint16_t de;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint8_t l;
|
||||
uint8_t h;
|
||||
};
|
||||
uint16_t hl;
|
||||
};
|
||||
uint16_t sp;
|
||||
uint16_t pc;
|
||||
|
||||
uint16_t index;
|
||||
|
||||
int32_t cycles;
|
||||
int32_t nextEvent;
|
||||
enum LR35902ExecutionState executionState;
|
||||
int halted;
|
||||
|
||||
uint8_t bus;
|
||||
bool condition;
|
||||
LR35902Instruction instruction;
|
||||
|
||||
struct LR35902Memory memory;
|
||||
struct LR35902InterruptHandler irqh;
|
||||
|
||||
struct LR35902Component* master;
|
||||
|
||||
size_t numComponents;
|
||||
struct LR35902Component** components;
|
||||
};
|
||||
|
||||
static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) {
|
||||
uint16_t hl;
|
||||
LOAD_16LE(hl, 0, &cpu->hl);
|
||||
return hl;
|
||||
}
|
||||
|
||||
void LR35902Init(struct LR35902Core* cpu);
|
||||
void LR35902Deinit(struct LR35902Core* cpu);
|
||||
void LR35902SetComponents(struct LR35902Core* cpu, struct LR35902Component* master, int extra, struct LR35902Component** extras);
|
||||
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*);
|
||||
|
||||
void LR35902Tick(struct LR35902Core* cpu);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "lr35902/lr35902.h"
|
||||
#include "gb/gb.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
struct LR35902Core cpu;
|
||||
struct GB gb;
|
||||
|
||||
GBCreate(&gb);
|
||||
LR35902SetComponents(&cpu, &gb.d, 0, 0);
|
||||
LR35902Init(&cpu);
|
||||
struct VFile* vf = VFileOpen(argv[1], O_RDONLY);
|
||||
GBLoadROM(&gb, vf, 0, argv[1]);
|
||||
|
||||
LR35902Reset(&cpu);
|
||||
while (true) {
|
||||
LR35902Tick(&cpu);
|
||||
}
|
||||
vf->close(vf);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue