Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustKarlstedt committed Apr 15, 2020
1 parent 49b4a76 commit 7a3ea48
Show file tree
Hide file tree
Showing 16 changed files with 1,718 additions and 0 deletions.
38 changes: 38 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.14)

### Require out-of-source builds
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH)
if(EXISTS "${LOC_PATH}")
message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.")
endif()

project(gameboyemu
VERSION 0.01
DESCRIPTION "gameboy emulator"
LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)

include(FetchContent)

FetchContent_Declare(
fmtlib
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 6.1.2
)
FetchContent_MakeAvailable(fmtlib)

set(BUILD_SHARED_LIBS FALSE)
set(SFML_BUILD_NETWORK FALSE)
FetchContent_Declare(
SFML
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 2.5.1
)
FetchContent_MakeAvailable(SFML)

configure_file("${PROJECT_SOURCE_DIR}/include/gameboyemu/BuildSettings.h.in" "${PROJECT_BINARY_DIR}/include/gameboyemu/BuildSettings.h")

add_subdirectory(src)
add_subdirectory(app)
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Instruction set: https://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
First ROM to implement: https://gbdev.gg8.se/wiki/articles/Gameboy_Bootstrap_ROM#Contents_of_the_ROM
Test roms: https://github.com/retrio/gb-test-roms

GameBoy CPU manual: http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
Good info on Z80: http://z80-heaven.wikidot.com/flags-and-bit-level-instructions


==Scratchpad==

0x80 = 1000 0000
0xF3 = 1111 0011
0x77 = 0111 0111

LD HL,$ff26 ; $000c Setup Audio HL = 0xFF26 sound on/off register.
LD C,$11 ; $000f C = 0x11
LD A,$80 ; $0011 A = 0x80
LD (HL-),A ; $0013 memory[0xFF26] = 0x80; HL = 0xFF25; set all sound on
LD ($FF00+C),A ; $0014 memory[0xFF00+0x11] = 0x80 sound mode 1 register: length/wave pattern duty
INC C ; $0015 C = 0x12
LD A,$f3 ; $0016 A = 0xF3
LD ($FF00+C),A ; $0018 memory[0xFF00+0x12] = 0xF3 sound mode 1 register: envelope
LD (HL-),A ; $0019 memory[0xFF25] = 0xF3; HL = 0xFF24 set sound output terminal: output [4,3,2,1] to SO2 and output [2,1] to SO1
LD A,$77 ; $001a A = 0x77
LD (HL),A ; $001c memory[0xFF24] = 0x77 set SO2 off, but max volume. set SO1 off, but max volume


0x83 = 1000 0011
0x87 = 1000 0111

play sound #1...
LD C,$13 ; $0070 C = 0x13
LD E,$83 ; $0074 E = 0x83
LD A,E ; $0080 play sound A = 0x83
LD ($FF00+C),A ; $0081 memory[0xFF00+0x13] = 0x83 sound mode 1 register: frequency lo
INC C ; $0082 C = 0x14
LD A,$87 ; $0083 A = 0x87
LD ($FF00+C),A ; $0085 memory[0xFF00+0x14] = 0x87 sound mode 1 register: frequency hi + enable consecutive

Binary file added ROMs/DMG_ROM.bin
Binary file not shown.
Binary file added ROMs/Tetris (World) (Rev A).gb
Binary file not shown.
14 changes: 14 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
file(GLOB HEADER_LIST CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/include/gameboyemu/*.h")

add_executable(emulator emulator.cpp ${HEADER_LIST})

target_compile_definitions(emulator PRIVATE SFML_STATIC)
target_include_directories(emulator PRIVATE "${SFML_SOURCE_DIR}/include")
target_link_directories(emulator PRIVATE "${SFML_BINARY_DIR}/lib/")

target_link_libraries(emulator emulib sfml-graphics sfml-window sfml-audio fmt::fmt)

target_include_directories(emulator PRIVATE "${PROJECT_SOURCE_DIR}/include")
target_include_directories(emulator PRIVATE "${PROJECT_BINARY_DIR}/include")

source_group(TREE "${PROJECT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADER_LIST})
273 changes: 273 additions & 0 deletions app/decompiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
#include <iomanip>
#include <iostream>
#include <fstream>
#include <limits>
#include <map>

#define MAX_FILE_SIZE 0x800000 // 8MB in bytes

int main()
{
uint8_t* romStorage = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * MAX_FILE_SIZE));

std::cout << "READING ROM\n";
std::ifstream file;
file.open("DMG_ROM.bin", std::ifstream::in);
//file.open("Tetris (World) (Rev A).gb", std::ifstream::in);
//file.open("Densha de Go! 2 (Japan).gbc", std::ifstream::in);
uint32_t byte = 0;
while (file.good())
{
if (byte > MAX_FILE_SIZE)
{
std::cout << "File too large.\n";
return -1;
}

romStorage[byte] = file.get();
++byte;
}
byte -= 1;
file.close();
std::cout << "READING ROM COMPLETE (" << byte << " bytes)\n";

uint8_t* stack = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * 0x10000));

std::map<std::string, uint16_t> registers;
registers["A"] = 0; //
registers["B"] = 0;
registers["C"] = 0; //
registers["D"] = 0;
registers["E"] = 0;
registers["F"] = 0;
registers["H"] = 0; //
registers["L"] = 0; //
registers["I"] = 0;
registers["R"] = 0;

registers["AF"] = 0;
registers["BC"] = 0;
registers["DE"] = 0;
registers["HL"] = 0; //

registers["PC"] = 0;
registers["SP"] = 0; //

registers["IX"] = 0;
registers["IY"] = 0;

registers["IXH"] = 0;
registers["IXL"] = 0;
registers["IYH"] = 0;
registers["IYL"] = 0;

std::cout << "PARSING ROM\n";
for (int i = 0; i < byte; ++i)
{
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(6) << i << ": ";

if (i >= 0xA8 && i < 0xD8)
{
std::cout << "NINTENDO LOGO DATA\n";
continue;
}

if (i >= 0xD8 && i < 0xE0)
{
std::cout << "REGISTERED TRADEMARK SYMBOL DATA\n";
continue;
}

switch (romStorage[i])
{
case 0x31:
std::cout << "LD SP,$" << std::hex << +romStorage[i + 2] << +romStorage[i + 1] << "\n";
registers["SP"] = (romStorage[i + 2] << 8) + romStorage[i + 1];
i += 2;
break;
case 0xAF:
std::cout << "XOR A" << "\n";
registers["A"] = registers["A"] ^ registers["A"];
break;
case 0x21:
std::cout << "LD HL,$" << std::hex << std::setfill('0') << std::setw(2) << +romStorage[i + 2] << std::setw(2) << +romStorage[i + 1] << "\n";
i += 2;
break;
case 0x32:
std::cout << "LD (HL-),A\n";
break;
case 0xCB:
switch (romStorage[i + 1])
{
case 0x7C:
std::cout << "BIT 7,H\n";
break;
case 0x11:
std::cout << "RL C\n";
break;
default:
std::cout << "UNKNOWN WITH CB PREFIX: " << std::hex << +romStorage[i + 1] << "\n";
break;
}
i += 1;
break;
case 0x20:
if (romStorage[i + 1] >= 0xFE)
{
std::cout << "JR NZ,$" << +romStorage[i + 1] << "\n";
}
else
{
std::cout << "JR NZ, Addr_" << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<char>(i) + 2 + romStorage[i + 1] << std::nouppercase << "\n";
}
i += 1;
break;
case 0x0E:
std::cout << "LD C,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x3E:
std::cout << "LD A,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0xE2:
std::cout << "LD ($FF00+C),A" << "\n";
break;
case 0x0C:
std::cout << "INC C" << "\n";
break;
case 0x77:
std::cout << "LD (HL),A\n";
break;
case 0xE0:
std::cout << "LD ($FF00+$" << +romStorage[i + 1] << "),A" << "\n";
i += 1;
break;
case 0x11:
std::cout << "LD DE,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 2] << std::setw(2) << +romStorage[i + 1] << "\n";
i += 2;
break;
case 0x1A:
std::cout << "LD A,(DE)\n";
break;
case 0xCD:
std::cout << "CALL $" << std::setfill('0') << std::setw(2) << +romStorage[i + 2] << std::setw(2) << +romStorage[i + 1] << "\n";
i += 2;
break;
case 0x13:
std::cout << "INC DE\n";
break;
case 0x7B:
std::cout << "LD A,E\n";
break;
case 0xFE:
std::cout << "CP $" << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x06:
std::cout << "LD B,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x22:
std::cout << "LD (HL+),A\n";
break;
case 0x23:
std::cout << "INC HL\n";
break;
case 0x05:
std::cout << "DEC B\n";
break;
case 0xEA:
std::cout << "LD ($" << +romStorage[i + 2] << +romStorage[i + 1] << ",A\n";
i += 2;
break;
case 0x3D:
std::cout << "DEC A\n";
break;
case 0x28:
std::cout << "JR Z, Addr_" << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x0D:
std::cout << "DEC C\n";
break;
case 0x2E:
std::cout << "LD L,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x18:
std::cout << "JR Addr_" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x67:
std::cout << "LD H,A\n";
break;
case 0x57:
std::cout << "LD D,A\n";
break;
case 0x04:
std::cout << "INC B\n";
break;
case 0x1E:
std::cout << "LD E,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0xF0:
std::cout << "LD A,($FF00+$" << +romStorage[i + 1] << ")\n";
i += 1;
break;
case 0x1D:
std::cout << "DEC E\n";
break;
case 0x24:
std::cout << "INC H\n";
break;
case 0x7C:
std::cout << "LD A,H\n";
break;
case 0x90:
std::cout << "SUB B\n";
break;
case 0x15:
std::cout << "DEC D\n";
break;
case 0x16:
std::cout << "LD D,$" << std::setfill('0') << std::setw(2) << +romStorage[i + 1] << "\n";
i += 1;
break;
case 0x4F:
std::cout << "LD C,A\n";
break;
case 0xC5:
std::cout << "PUSH BC\n";
break;
case 0x17:
std::cout << "RLA\n";
break;
case 0xC1:
std::cout << "POP BC\n";
break;
case 0xC9:
std::cout << "RET\n";
break;
case 0xBE:
std::cout << "CP (HL)\n";
break;
case 0x7D:
std::cout << "LD A,L\n";
break;
case 0x78:
std::cout << "LD A,B\n";
break;
case 0x86:
std::cout << "ADD (HL)\n";
break;
default:
std::cout << "UNKNOWN: " << std::hex << +romStorage[i] << "\n";
break;
}
}
std::cout << "PARSING ROM COMPLETE\n";

return 0;
}
Loading

0 comments on commit 7a3ea48

Please sign in to comment.