summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--app/mac/CMakeLists.txt4
-rw-r--r--flake.lock61
-rw-r--r--flake.nix29
-rw-r--r--lib/nes/app/application.cc50
-rw-r--r--lib/nes/app/application.hh8
-rw-r--r--lib/nes/sys/ppu.cc16
-rw-r--r--lib/nes/sys/ppu.hh10
-rw-r--r--tools/generate-tiles/CMakeLists.txt4
-rw-r--r--tools/generate-tiles/main.cc34
10 files changed, 165 insertions, 55 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 22f1ee8..9b8525e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.30)
project(
nes
- LANGUAGES CXX OBJCXX OBJC
+ LANGUAGES CXX
VERSION 1.0)
option(NES_ENABLE_SANITIZER_ADDRESS "Enable address sanitizer." OFF)
@@ -47,4 +47,4 @@ endif()
add_subdirectory(tools)
add_subdirectory(lib)
-add_subdirectory(app) \ No newline at end of file
+add_subdirectory(app)
diff --git a/app/mac/CMakeLists.txt b/app/mac/CMakeLists.txt
index e7471d1..041ae29 100644
--- a/app/mac/CMakeLists.txt
+++ b/app/mac/CMakeLists.txt
@@ -1,3 +1,5 @@
+enable_language(OBJC OBJCXX)
+
add_executable(nes_app_mac)
find_library(FRAMEWORK_Cocoa Cocoa REQUIRED)
@@ -23,4 +25,4 @@ target_sources(
view-controller.hh
view-controller.mm)
-add_subdirectory(impl) \ No newline at end of file
+add_subdirectory(impl)
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..a49d83e
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,61 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1738797219,
+ "narHash": "sha256-KRwX9Z1XavpgeSDVM/THdFd6uH8rNm/6R+7kIbGa+2s=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "1da52dd49a127ad74486b135898da2cef8c62665",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..bf0f856
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,29 @@
+{
+ description = "NES Emulator";
+
+ inputs = {
+ nixpkgs = {
+ url = "github:nixos/nixpkgs/nixpkgs-unstable";
+ };
+
+ flake-utils = {
+ url = "github:numtide/flake-utils";
+ };
+ };
+
+ outputs = { self, nixpkgs, flake-utils, ... }@inputs:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs { inherit system; };
+ shell = pkgs.mkShell {
+ packages = with pkgs; [ cmake gcc binutils gdb gnumake valgrind clang-tools ];
+ hardeningDisable = [ "fortify" ];
+ };
+ in
+ {
+ devShells = {
+ default = shell;
+ };
+ });
+}
+
diff --git a/lib/nes/app/application.cc b/lib/nes/app/application.cc
index bb2f1e4..ca04999 100644
--- a/lib/nes/app/application.cc
+++ b/lib/nes/app/application.cc
@@ -16,19 +16,19 @@ namespace nes::app
buffer_back_[y * display::width + x] = value;
base.set(x, y, value);
}
-
+
auto application::display_proxy::switch_buffers() -> void
{
auto r = renderer{ base };
- if (screen)
+ if (visible_screen)
{
- screen->render(r);
+ visible_screen->render(r);
}
- if (popup)
+ if (visible_popup)
{
- popup->render(r);
+ visible_popup->render(r);
}
if (preferences_.get_fps_counter())
@@ -37,7 +37,7 @@ namespace nes::app
auto const attrs = text_attributes{}
.set_max_width(2)
.set_alignment(text_alignment::right);
- r.render_text_format(32, 29, color::fixed_white, attrs, "{}", fps_counter.get_fps());
+ r.render_text_format(32, 29, color::fixed_white, attrs, "{}", fps.get_fps());
}
swap(buffer_front_, buffer_back_);
@@ -54,25 +54,25 @@ namespace nes::app
, screen_error_{ keyboard }
, screen_confirm_quit_{ keyboard }
{
- display_.screen = &screen_title_;
+ display_.visible_screen = &screen_title_;
}
auto application::frame(u32 const elapsed_time_us) -> void
{
- display_.fps_counter.frame(elapsed_time_us);
+ display_.fps.frame(elapsed_time_us);
- if (display_.popup)
+ if (display_.visible_popup)
{
- auto const a = display_.popup->process_events();
+ auto const a = display_.visible_popup->process_events();
handle_action(a);
}
- else if (display_.screen)
+ else if (display_.visible_screen)
{
- auto const a = display_.screen->process_events();
+ auto const a = display_.visible_screen->process_events();
handle_action(a);
}
- if (display_.screen)
+ if (display_.visible_screen)
{
// Directly let the scene render itself without rendering any gameplay (the scene is responsible for
// clearing the buffer).
@@ -87,8 +87,8 @@ namespace nes::app
{
screen_freeze_.freeze(display_.get_front());
screen_confirm_quit_.set_confirm(false);
- display_.screen = &screen_freeze_;
- display_.popup = &screen_confirm_quit_;
+ display_.visible_screen = &screen_freeze_;
+ display_.visible_popup = &screen_confirm_quit_;
display_.switch_buffers();
return;
}
@@ -105,7 +105,7 @@ namespace nes::app
if (console_->get_status() != status::success)
{
screen_freeze_.freeze(display_.get_front());
- display_.screen = &screen_freeze_;
+ display_.visible_screen = &screen_freeze_;
show_error("Runtime error", console_->get_status(), action::go_to_browser());
console_.clear();
}
@@ -143,13 +143,13 @@ namespace nes::app
}
case action::type::close_popup:
{
- display_.popup = nullptr;
+ display_.visible_popup = nullptr;
break;
}
case action::type::cancel_quit:
{
- display_.popup = nullptr;
- display_.screen = nullptr;
+ display_.visible_popup = nullptr;
+ display_.visible_screen = nullptr;
break;
}
case action::type::launch_game:
@@ -170,8 +170,8 @@ namespace nes::app
break;
}
- display_.screen = nullptr;
- display_.popup = nullptr;
+ display_.visible_screen = nullptr;
+ display_.visible_popup = nullptr;
break;
}
case action::type::show_error:
@@ -187,13 +187,13 @@ namespace nes::app
screen_error_.set_message(message);
screen_error_.set_error(error);
screen_error_.set_action(action);
- display_.popup = &screen_error_;
+ display_.visible_popup = &screen_error_;
}
auto application::go_to_screen(screen* screen) -> void
{
console_.clear();
- display_.screen = screen;
- display_.popup = nullptr;
+ display_.visible_screen = screen;
+ display_.visible_popup = nullptr;
}
-} // namespace nes::app \ No newline at end of file
+} // namespace nes::app
diff --git a/lib/nes/app/application.hh b/lib/nes/app/application.hh
index d0973e8..960b022 100644
--- a/lib/nes/app/application.hh
+++ b/lib/nes/app/application.hh
@@ -36,10 +36,10 @@ namespace nes::app
span<rgb, display::width * display::height> buffer_back_ = buffers_[1];
public:
- fps_counter fps_counter;
+ fps_counter fps;
display& base;
- screen* popup{ nullptr };
- screen* screen{ nullptr };
+ screen* visible_popup{ nullptr };
+ screen* visible_screen{ nullptr };
explicit display_proxy(preferences& preferences, display& base)
: preferences_{ preferences }
@@ -84,4 +84,4 @@ namespace nes::app
auto show_error(string_view message, status error, action const& action = action::close_popup()) -> void;
auto go_to_screen(screen*) -> void;
};
-} // namespace nes::app \ No newline at end of file
+} // namespace nes::app
diff --git a/lib/nes/sys/ppu.cc b/lib/nes/sys/ppu.cc
index 5b9f5db..56e99a8 100644
--- a/lib/nes/sys/ppu.cc
+++ b/lib/nes/sys/ppu.cc
@@ -74,7 +74,7 @@ namespace nes::sys
case 1:
{
// Load the tile pattern for the background from the name table.
- fetch_cycle_.tile = tile{ read8(address{ 0x2000 } + internal_.v.get_tile_address()) };
+ fetch_cycle_.background_tile = tile{ read8(address{ 0x2000 } + internal_.v.get_tile_address()) };
break;
}
case 3:
@@ -88,15 +88,15 @@ namespace nes::sys
auto const shift =
((internal_.v.get_coarse_y() & 0b00010u) << 1) |
((internal_.v.get_coarse_x() & 0b00010u) << 0);
- fetch_cycle_.palette = static_cast<palette>((read8(addr) >> shift) & 0b11);
+ fetch_cycle_.background_palette = static_cast<palette>((read8(addr) >> shift) & 0b11);
break;
}
case 5:
{
// Load bitplane 0 for the background tile's pattern.
- fetch_cycle_.bitplane_0 = get_tile_bitplane(
+ fetch_cycle_.pattern_bitplane_0 = get_tile_bitplane(
control_.get_background_pattern_table(),
- fetch_cycle_.tile,
+ fetch_cycle_.background_tile,
internal_.v.get_fine_y(),
bitplane::_0);
break;
@@ -104,9 +104,9 @@ namespace nes::sys
case 7:
{
// Load bitplane 1 for the background tile's pattern.
- fetch_cycle_.bitplane_1 = get_tile_bitplane(
+ fetch_cycle_.pattern_bitplane_1 = get_tile_bitplane(
control_.get_background_pattern_table(),
- fetch_cycle_.tile,
+ fetch_cycle_.background_tile,
internal_.v.get_fine_y(),
bitplane::_1);
break;
@@ -116,7 +116,7 @@ namespace nes::sys
// Fetch cycle done -> build the tile row for the background.
current_background_ = next_background_;
next_background_ = get_tile_row(
- fetch_cycle_.palette, fetch_cycle_.bitplane_0, fetch_cycle_.bitplane_1);
+ fetch_cycle_.background_palette, fetch_cycle_.pattern_bitplane_0, fetch_cycle_.pattern_bitplane_1);
break;
}
default:
@@ -697,4 +697,4 @@ namespace nes::sys
default: return rgb::from_hex(0x000000);
}
}
-} // namespace nes::sys \ No newline at end of file
+} // namespace nes::sys
diff --git a/lib/nes/sys/ppu.hh b/lib/nes/sys/ppu.hh
index 898ddd3..d82056e 100644
--- a/lib/nes/sys/ppu.hh
+++ b/lib/nes/sys/ppu.hh
@@ -217,10 +217,10 @@ namespace nes::sys
tile_row next_background_{};
struct
{
- tile tile{ 0 };
- palette palette{ 0 };
- u8 bitplane_0{ 0 };
- u8 bitplane_1{ 0 };
+ tile background_tile{ 0 };
+ palette background_palette{ 0 };
+ u8 pattern_bitplane_0{ 0 };
+ u8 pattern_bitplane_1{ 0 };
} fetch_cycle_{}; // Data populated during the fetch cycle.
evaluated_sprite sprites_[8]{}; // Evaluated sprites.
u32 sprite_count_{ 0 }; // Number of evaluated sprites in sprites_.
@@ -284,4 +284,4 @@ namespace nes::sys
auto ref_color(color_index) -> color&;
auto resolve_color(color) const -> rgb;
};
-} // namespace nes::sys \ No newline at end of file
+} // namespace nes::sys
diff --git a/tools/generate-tiles/CMakeLists.txt b/tools/generate-tiles/CMakeLists.txt
index fc7d7f0..40d19a0 100644
--- a/tools/generate-tiles/CMakeLists.txt
+++ b/tools/generate-tiles/CMakeLists.txt
@@ -20,7 +20,7 @@ function(nes_generate_tiles TARGET_NAME NAME)
set(CODEGEN_DIR "${CODEGEN_BASE}/nes/app/graphics/tiles")
set(CODEGEN_SOURCE "${CODEGEN_DIR}/${NAME}.cc")
set(CODEGEN_HEADER "${CODEGEN_DIR}/${NAME}.hh")
- file(MAKE_DIRECTORY "${RESOURCES_INCLUDE_DIR}")
+ file(MAKE_DIRECTORY "${CODEGEN_DIR}")
add_custom_command(
OUTPUT "${CODEGEN_SOURCE}" "${CODEGEN_HEADER}"
@@ -40,4 +40,4 @@ function(nes_generate_tiles TARGET_NAME NAME)
set_source_files_properties("${CODEGEN_SOURCE}" PROPERTIES GENERATED TRUE)
set_source_files_properties("${CODEGEN_HEADER}" PROPERTIES GENERATED TRUE)
add_dependencies(${TARGET_NAME} ${CODEGEN_TARGET})
-endfunction() \ No newline at end of file
+endfunction()
diff --git a/tools/generate-tiles/main.cc b/tools/generate-tiles/main.cc
index dbee3fa..4ec4906 100644
--- a/tools/generate-tiles/main.cc
+++ b/tools/generate-tiles/main.cc
@@ -6,6 +6,8 @@
#include <cassert>
#include <cstdlib>
#include <cstdint>
+#include <unistd.h>
+#include <fcntl.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
@@ -215,6 +217,27 @@ namespace
return status::ok;
}
+
+ auto write_file(std::string_view const filename, std::string_view const content) -> status
+ {
+ auto const filename_str = std::string{ filename };
+
+ auto const fd = open(filename_str.c_str(), O_TRUNC | O_WRONLY | O_CREAT, 0644);
+ if (fd == -1)
+ {
+ perror("open");
+ return status::invalid;
+ }
+
+ if (write(fd, content.data(), content.length()) == -1)
+ {
+ perror("write");
+ return status::invalid;
+ }
+
+ close(fd);
+ return status::ok;
+ }
} // namespace
int main(int const argc, char** const argv)
@@ -285,13 +308,8 @@ int main(int const argc, char** const argv)
source << "} // namespace nes::app::tiles\n";
- auto header_file = std::ofstream{ std::string{ output_header } };
- header_file << header.str();
- header_file.flush();
-
- auto source_file = std::ofstream{ std::string{ output_source } };
- source_file << source.str();
- source_file.flush();
+ if (write_file(output_header, header.str()) != status::ok) { return EXIT_FAILURE; }
+ if (write_file(output_source, source.str()) != status::ok) { return EXIT_FAILURE; }
return EXIT_SUCCESS;
-} \ No newline at end of file
+}