LR35902, GB: Start work on GB core

This commit is contained in:
Jeffrey Pfau 2016-01-13 23:02:50 -08:00
parent 811d654893
commit 64676529ba
10 changed files with 960 additions and 0 deletions

View File

@ -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

136
src/gb/gb.c Normal file
View File

@ -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);
}

69
src/gb/gb.h Normal file
View File

@ -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

133
src/gb/memory.c Normal file
View File

@ -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);

77
src/gb/memory.h Normal file
View File

@ -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

227
src/lr35902/isa-lr35902.c Normal file
View File

@ -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)
};

17
src/lr35902/isa-lr35902.h Normal file
View File

@ -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

116
src/lr35902/lr35902.c Normal file
View File

@ -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);
}
}

149
src/lr35902/lr35902.h Normal file
View File

@ -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

View File

@ -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;
}