diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..45cdf095 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,61 @@ +name: build +on: push +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y build-essential libsdl2-dev libfmt-dev qt5-default git + - name: Build natsukashii + run: | + cmake -B build -DCMAKE_BUILD_TYPE=Release + cd build + make -j$(nproc) + - name: Collect artifacts + run: | + mkdir upload + cp build/bin/qt/natsukashii-qt upload + cp build/bin/sdl/natsukashii-sdl upload + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: natsukashii-linux + path: upload + if-no-files-found: error + build-windows: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: msys2/setup-msys2@v2 + with: + install: make git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-SDL2 mingw-w64-x86_64-qt5-static mingw-w64-x86_64-fmt + - name: Build natsukashii + run: | + cmake \ + -G"Unix Makefiles" \ + -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-s" + cd build + make -j$(nproc) + - name: Collect artifacts + run: | + mkdir upload + cp build/bin/qt/natsukashii-qt upload + cp build/bin/sdl/natsukashii-sdl upload + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: natsukashii-windows + path: upload + if-no-files-found: error \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index af6715dc..968e1bec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,15 @@ project(natsukashii CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +add_subdirectory(src/core) -add_subdirectory(src) -add_executable(natsukashii src/main.cpp) -target_include_directories(natsukashii PUBLIC src/frontend/) -target_link_libraries(natsukashii cores frontend) +option(BUILD_SDL "Build the SDL frontend" ON) +option(BUILD_QT "Build the QT frontend" ON) + +if(${BUILD_QT}) + add_subdirectory(src/frontend/qt ${CMAKE_CURRENT_BINARY_DIR}/bin/qt/) +endif() + +if(${BUILD_SDL}) + add_subdirectory(src/frontend/sdl ${CMAKE_CURRENT_BINARY_DIR}/bin/sdl/) +endif() diff --git a/README.md b/README.md index 60bf6adf..9f09d63c 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,6 @@ ### _"Joyful nostalgia"_ [![CodeFactor](https://www.codefactor.io/repository/github/cocosimone/natsukashii/badge/master)](https://www.codefactor.io/repository/github/cocosimone/natsukashii/overview/master) +[![build](https://github.com/CocoSimone/natsukashii/actions/workflows/build.yml/badge.svg)](https://github.com/CocoSimone/natsukashii/actions/workflows/build.yml) Multi-system emulator in its infancy \ No newline at end of file diff --git a/external/portable_endian_bswap.h b/external/portable_endian_bswap.h index e2087165..66aaab49 100644 --- a/external/portable_endian_bswap.h +++ b/external/portable_endian_bswap.h @@ -5,6 +5,7 @@ // an example on how to get the endian conversion functions on different platforms. #pragma once +#include #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) @@ -114,64 +115,17 @@ #endif -// Adapted from Google's CityHash source code: -// -// https://github.com/google/cityhash/blob/8af9b8c2b889d80c22d6bc26ba0df1afb79a30db/src/city.cc#L50 - -#if defined(_MSC_VER) - -#include -#define bswap_16(x) _byteswap_ushort(x) -#define bswap_32(x) _byteswap_ulong(x) -#define bswap_64(x) _byteswap_uint64(x) - -#elif defined(__APPLE__) - -// Mac OS X / Darwin features -#include -#define bswap_16(x) OSSwapInt16(x) -#define bswap_32(x) OSSwapInt32(x) -#define bswap_64(x) OSSwapInt64(x) - -#elif defined(__sun) || defined(sun) - -#include -#define bswap_16(x) BSWAP_16(x) -#define bswap_32(x) BSWAP_32(x) -#define bswap_64(x) BSWAP_64(x) - -#elif defined(__FreeBSD__) - -#include -#define bswap_16(x) bswap16(x) -#define bswap_32(x) bswap32(x) -#define bswap_64(x) bswap64(x) - -#elif defined(__OpenBSD__) - -#include -#define bswap_16(x) swap16(x) -#define bswap_32(x) swap32(x) -#define bswap_64(x) swap64(x) - -#elif defined(__NetBSD__) - -#include -#include -#if defined(__BSWAP_RENAME) && !defined(__bswap_32) -#define bswap_16(x) bswap16(x) -#define bswap_32(x) bswap32(x) -#define bswap_64(x) bswap64(x) -#endif - -#elif __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) - -#define bswap_16(x) __builtin_bswap16(x) -#define bswap_32(x) __builtin_bswap32(x) -#define bswap_64(x) __builtin_bswap64(x) - -#else - -#include - -#endif \ No newline at end of file +#define bswap_16(x) (((x) & 0xFF00u) >> 8) | \ + (((x) & 0x00FFu) << 8) +#define bswap_32(x) (((x) & 0xFF000000u) >> 24u) | \ + (((x) & 0x00FF0000u) >> 8u) | \ + (((x) & 0x0000FF00u) << 8u) | \ + (((x) & 0x000000FFu) << 24u) +#define bswap_64(x) (((x) & 0xFF00000000000000u) >> 56u) | \ + (((x) & 0x00FF000000000000u) >> 40u) | \ + (((x) & 0x0000FF0000000000u) >> 24u) | \ + (((x) & 0x000000FF00000000u) >> 8u) | \ + (((x) & 0x00000000FF000000u) << 8u) | \ + (((x) & 0x0000000000FF0000u) << 24u) | \ + (((x) & 0x000000000000FF00u) << 40u) | \ + (((x) & 0x00000000000000FFu) << 56u) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 535e89cb..00000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -add_subdirectory(core) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(FRONTEND "sdl" CACHE INTERNAL "") - -if(${FRONTEND} MATCHES "qt") - add_subdirectory(frontend/qt) -elseif(${FRONTEND} MATCHES "sdl") - add_subdirectory(frontend/sdl) -else() - message("Invalid frontend specified, falling back to Qt.") - add_subdirectory(frontend/qt) -endif() diff --git a/src/core/BaseCore.cpp b/src/core/BaseCore.cpp new file mode 100644 index 00000000..9bf637e0 --- /dev/null +++ b/src/core/BaseCore.cpp @@ -0,0 +1,5 @@ +#include + +namespace natsukashii::core { +void BaseCore::Run() {} +} \ No newline at end of file diff --git a/src/core/BaseCore.hpp b/src/core/BaseCore.hpp index a41e37e9..1062c3ec 100644 --- a/src/core/BaseCore.hpp +++ b/src/core/BaseCore.hpp @@ -2,6 +2,7 @@ namespace natsukashii::core { struct BaseCore { - virtual void Run() {} + virtual ~BaseCore() {} + virtual void Run(); }; } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7cbef9ee..3988d0ad 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(cores Scheduler.cpp Scheduler.hpp common.hpp - BaseCore.hpp) + util.hpp) target_include_directories(cores PRIVATE .) target_include_directories(cores PUBLIC ../../external) target_link_libraries(cores PUBLIC gb n64) diff --git a/src/core/gb/CMakeLists.txt b/src/core/gb/CMakeLists.txt index 4f291cf4..269bf181 100644 --- a/src/core/gb/CMakeLists.txt +++ b/src/core/gb/CMakeLists.txt @@ -3,10 +3,35 @@ project(gb CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -find_package(mio REQUIRED) -find_package(fmt REQUIRED) -find_package(toml11 REQUIRED) +include(FetchContent) +FetchContent_Declare( + mio + GIT_REPOSITORY https://github.com/CocoSimone/mio + GIT_TAG master +) +FetchContent_Declare( + toml11 + GIT_REPOSITORY https://github.com/ToruNiina/toml11 + GIT_TAG dcfe39a783a94e8d52c885e5883a6fbb21529019 +) -add_library(gb Core.hpp Core.cpp Cpu.hpp Cpu.cpp Ppu.hpp Ppu.cpp Mem.cpp Mem.hpp mbc.cpp mbc.hpp memory_regions.hpp) -target_include_directories(gb PRIVATE . ..) -target_link_libraries(gb PUBLIC toml11::toml11 mio::mio fmt::fmt) +FetchContent_MakeAvailable(mio toml11) +find_package(fmt REQUIRED) + +add_library(gb + Core.hpp + Core.cpp + Cpu.hpp + Cpu.cpp + Ppu.hpp + Ppu.cpp + Mem.cpp + Mem.hpp + mbc.cpp + mbc.hpp + memory_regions.hpp + ../BaseCore.cpp + ../BaseCore.hpp) +target_include_directories(gb PRIVATE . .. ../../../external) +target_include_directories(gb PUBLIC ${mio_SOURCE_DIR}/include ${toml11_SOURCE_DIR}/include) +target_link_libraries(gb PRIVATE toml11::toml11 mio::mio fmt::fmt) diff --git a/src/core/gb/Core.hpp b/src/core/gb/Core.hpp index 90763449..61395291 100644 --- a/src/core/gb/Core.hpp +++ b/src/core/gb/Core.hpp @@ -5,8 +5,10 @@ #include namespace natsukashii::gb::core { -struct Core : natsukashii::core::BaseCore { - Core(const std::string&); +using namespace natsukashii::core; +struct Core : BaseCore { + ~Core() override = default; + explicit Core(const std::string&); void Run() override; private: Mem mem; diff --git a/src/core/gb/Cpu.hpp b/src/core/gb/Cpu.hpp index 454abd22..9947462e 100644 --- a/src/core/gb/Cpu.hpp +++ b/src/core/gb/Cpu.hpp @@ -3,15 +3,15 @@ #include namespace natsukashii::gb::core { -#define REGIMPL(type1, reg1, type2, reg2) \ - struct reg##reg1##reg2 { \ - reg##reg1##reg2() {} \ - union { \ - type1 reg1; \ - type2 reg2; \ - }; \ - u16 raw = 0; \ - } reg1##reg2 +template +struct Reg { + Reg() : raw(0) {}; + union { + T1 hi; + T2 lo; + }; + u16 raw = 0; +}; struct RegF { RegF() : raw(0) {} @@ -71,20 +71,20 @@ private: }; struct Registers { - REGIMPL(u8, A, RegF, F); - REGIMPL(u8, B, u8, C); - REGIMPL(u8, D, u8, E); - REGIMPL(u8, H, u8, L); + Reg AF; + Reg BC; + Reg DE; + Reg HL; u16 pc = 0, sp = 0; - u8& a() { return AF.A; } - RegF& f() { return AF.F; } - u8& b() { return BC.B; } - u8& c() { return BC.C; } - u8& d() { return DE.D; } - u8& e() { return DE.E; } - u8& h() { return HL.H; } - u8& l() { return HL.L; } + u8& a() { return AF.hi; } + RegF& f() { return AF.lo; } + u8& b() { return BC.hi; } + u8& c() { return BC.lo; } + u8& d() { return DE.hi; } + u8& e() { return DE.lo; } + u8& h() { return HL.hi; } + u8& l() { return HL.lo; } u16& af() { return AF.raw; } u16& bc() { return BC.raw; } @@ -124,6 +124,7 @@ private: case 3: return regs.af(); } } + return 0; } template diff --git a/src/core/gb/Mem.hpp b/src/core/gb/Mem.hpp index e04a081a..d4b3309f 100644 --- a/src/core/gb/Mem.hpp +++ b/src/core/gb/Mem.hpp @@ -1,10 +1,10 @@ #pragma once #include #include -#include #include -#include "memory_regions.hpp" -#include "mbc.hpp" +#include +#include +#include namespace natsukashii::gb::core { struct IO { diff --git a/src/core/n64/CMakeLists.txt b/src/core/n64/CMakeLists.txt index 2319dc41..5bc85ba9 100644 --- a/src/core/n64/CMakeLists.txt +++ b/src/core/n64/CMakeLists.txt @@ -3,10 +3,31 @@ project(n64 CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -#find_package(mio REQUIRED) -find_package(fmt REQUIRED) -#find_package(toml11 REQUIRED) +include(FetchContent) +FetchContent_Declare( + mio + GIT_REPOSITORY https://github.com/CocoSimone/mio + GIT_TAG master +) +FetchContent_Declare( + toml11 + GIT_REPOSITORY https://github.com/ToruNiina/toml11 + GIT_TAG dcfe39a783a94e8d52c885e5883a6fbb21529019 +) -add_library(n64 Core.hpp Core.cpp Cpu.hpp Cpu.cpp Mem.cpp Mem.hpp memory_regions.hpp) -target_include_directories(n64 PRIVATE . ..) -target_link_libraries(n64 PUBLIC fmt::fmt) +FetchContent_MakeAvailable(mio toml11) +find_package(fmt REQUIRED) + +add_library(n64 + Core.hpp + Core.cpp + Cpu.hpp + Cpu.cpp + Mem.cpp + Mem.hpp + memory_regions.hpp + ../BaseCore.cpp + ../BaseCore.hpp) +target_include_directories(n64 PRIVATE . .. ../../../external) +target_include_directories(n64 PUBLIC ${mio_SOURCE_DIR}/include ${toml11_SOURCE_DIR}/include) +target_link_libraries(n64 PRIVATE mio::mio toml11::toml11 fmt::fmt) diff --git a/src/core/n64/Core.hpp b/src/core/n64/Core.hpp index 75f105c0..4a49bdb5 100644 --- a/src/core/n64/Core.hpp +++ b/src/core/n64/Core.hpp @@ -5,8 +5,10 @@ #include namespace natsukashii::n64::core { -struct Core : natsukashii::core::BaseCore { - Core(const std::string&); - virtual void Run() override; +using namespace natsukashii::core; +struct Core : BaseCore { + ~Core() override = default; + explicit Core(const std::string&); + void Run() override; }; } diff --git a/src/frontend/qt/CMakeLists.txt b/src/frontend/qt/CMakeLists.txt index d0e43b19..1aa6e645 100644 --- a/src/frontend/qt/CMakeLists.txt +++ b/src/frontend/qt/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) -project(frontend) +project(natsukashii-qt) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -9,8 +9,7 @@ set(CMAKE_AUTOUIC ON) find_package(Qt5 COMPONENTS Widgets REQUIRED) -add_library(frontend Frontend.hpp Frontend.cpp) +add_executable(natsukashii-qt Frontend.hpp Frontend.cpp main.cpp) -target_compile_definitions(frontend PUBLIC FRONTEND_QT) -target_include_directories(frontend PUBLIC .) -target_link_libraries(frontend PUBLIC Qt5::Widgets) +target_include_directories(natsukashii-qt PRIVATE . ../../core ../../core/gb ../../core/n64 ../../../external) +target_link_libraries(natsukashii-qt PRIVATE cores Qt5::Widgets) diff --git a/src/frontend/qt/main.cpp b/src/frontend/qt/main.cpp new file mode 100644 index 00000000..37e04d8c --- /dev/null +++ b/src/frontend/qt/main.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char* argv[]) { + natsukashii::frontend::App app; + app.Run(); + return 0; +} diff --git a/src/frontend/sdl/CMakeLists.txt b/src/frontend/sdl/CMakeLists.txt index 89a36a98..b93f1443 100644 --- a/src/frontend/sdl/CMakeLists.txt +++ b/src/frontend/sdl/CMakeLists.txt @@ -1,11 +1,19 @@ cmake_minimum_required(VERSION 3.20) -project(frontend) +project(natsukashii-sdl) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(SDL2 REQUIRED) -add_library(frontend Frontend.cpp Frontend.hpp) -target_compile_definitions(frontend PUBLIC FRONTEND_SDL) -target_include_directories(frontend PUBLIC . ../../core ../../core/gb ../../core/n64) -target_link_libraries(frontend PUBLIC SDL2) +add_executable(natsukashii-sdl Frontend.cpp Frontend.hpp main.cpp) + +include(FetchContent) +FetchContent_Declare( + argparse + GIT_REPOSITORY https://github.com/p-ranav/argparse + GIT_TAG 40a3888f151256bba95c45860af381b2b73752e8 +) +FetchContent_MakeAvailable(argparse) + +target_include_directories(natsukashii-sdl PRIVATE . ../../core ../../core/gb ../../core/n64 ../../../external) +target_link_libraries(natsukashii-sdl PRIVATE cores argparse::argparse SDL2) diff --git a/src/frontend/sdl/Frontend.cpp b/src/frontend/sdl/Frontend.cpp index 2637b4c4..5722af61 100644 --- a/src/frontend/sdl/Frontend.cpp +++ b/src/frontend/sdl/Frontend.cpp @@ -1,30 +1,28 @@ #include -#include -#include #include #include namespace natsukashii::frontend { +using namespace natsukashii; App::~App() { SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } -App::App(const std::string& rom) { +App::App(const std::string& rom, const std::string& selectedCore) { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); window = SDL_CreateWindow("natukashii", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); id = SDL_GetWindowID(window); - std::string ext{rom.begin() + rom.find_first_of('.') + 1, rom.end()}; - std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ - return std::tolower(c); - }); - - if(ext == "gb") core = std::make_unique(rom); - else if(ext == "n64") core = std::make_unique(rom); - else util::panic("Unimplemented core!"); + if(selectedCore == "gb") { + core = std::make_unique(rom); + } else if(selectedCore == "n64") { + core = std::make_unique(rom); + } else { + util::panic("Unimplemented core!"); + } } void App::Run() { diff --git a/src/frontend/sdl/Frontend.hpp b/src/frontend/sdl/Frontend.hpp index 25e23844..0379fb76 100644 --- a/src/frontend/sdl/Frontend.hpp +++ b/src/frontend/sdl/Frontend.hpp @@ -1,4 +1,5 @@ #pragma once +#define SDL_MAIN_HANDLED #include #include #include @@ -9,7 +10,7 @@ namespace natsukashii::frontend { using namespace natsukashii::core; struct App { ~App(); - App(const std::string&); + App(const std::string&, const std::string&); void Run(); private: SDL_Window *window = nullptr; diff --git a/src/frontend/sdl/main.cpp b/src/frontend/sdl/main.cpp new file mode 100644 index 00000000..20ff368f --- /dev/null +++ b/src/frontend/sdl/main.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +int main(int argc, char* argv[]) { + argparse::ArgumentParser program("natsukashii"); + program.add_argument("-c", "--core") + .required() + .help("Select the core"); + + program.add_argument("rom") + .required() + .help("ROM to load"); + + try { + program.parse_args(argc, argv); + } + catch (const std::runtime_error& err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + natsukashii::frontend::App app(program.get("rom"), program.get("--core")); + app.Run(); + + return 0; +} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index c6026fcd..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef FRONTEND_QT -#include -#elifdef FRONTEND_SDL -#include -#endif - -#include - -int main(int argc, char* argv[]) { -#ifdef FRONTEND_SDL - if(argc < 2) { - natsukashii::util::panic("Usage: natsukashii [rom]"); - } - natsukashii::frontend::App app(argv[1]); -#else - natsukashii::frontend::App app; -#endif - app.Run(); - return 0; -}