diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/nes/app/application.cc | 6 | ||||
| -rw-r--r-- | lib/nes/app/file-browser.hh | 3 | ||||
| -rw-r--r-- | lib/nes/common/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | lib/nes/common/path-builder.cc | 19 | ||||
| -rw-r--r-- | lib/nes/common/path-builder.hh | 12 | ||||
| -rw-r--r-- | lib/nes/common/span.hh | 82 | ||||
| -rw-r--r-- | lib/nes/common/string-builder.cc | 9 | ||||
| -rw-r--r-- | lib/nes/common/string-builder.hh | 12 | ||||
| -rw-r--r-- | lib/nes/sys/cartridge.cc | 16 | ||||
| -rw-r--r-- | lib/nes/sys/cartridge.hh | 18 | ||||
| -rw-r--r-- | lib/nes/sys/mapper.cc | 18 | ||||
| -rw-r--r-- | lib/nes/sys/mapper.hh | 5 | ||||
| -rw-r--r-- | lib/nes/sys/nes.cc | 6 | ||||
| -rw-r--r-- | lib/nes/sys/nes.hh | 4 | ||||
| -rw-r--r-- | lib/nes/sys/ppu.cc | 2 | ||||
| -rw-r--r-- | lib/nes/sys/ppu.hh | 3 |
16 files changed, 148 insertions, 70 deletions
diff --git a/lib/nes/app/application.cc b/lib/nes/app/application.cc index 5471984..b528e61 100644 --- a/lib/nes/app/application.cc +++ b/lib/nes/app/application.cc @@ -92,10 +92,10 @@ namespace nes::app } case action::type::launch_game: { - nes::u8 buffer[sys::cartridge::max_file_size]; - auto const length = file_browser_.load(a.get_file_name(), buffer, sizeof(buffer)); + u8 buffer[sys::cartridge::max_file_size]; + auto const length = file_browser_.load(a.get_file_name(), buffer); - console_.emplace(display_, buffer, length); + console_.emplace(display_, span<u8 const>{ buffer, length }); if (console_->get_status() != sys::status::success) { std::cerr << "Unable to load cartridge: " << to_string(console_->get_status()) << std::endl; diff --git a/lib/nes/app/file-browser.hh b/lib/nes/app/file-browser.hh index 67be794..6ce55aa 100644 --- a/lib/nes/app/file-browser.hh +++ b/lib/nes/app/file-browser.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/common/types.hh" +#include "nes/common/span.hh" namespace nes { @@ -50,7 +51,7 @@ namespace nes::app virtual auto read_next(item* out_item) -> bool = 0; virtual auto navigate_up() -> void = 0; virtual auto navigate(std::string_view) -> void = 0; - virtual auto load(std::string_view, u8* buffer, u32 buffer_size) -> u32 = 0; + virtual auto load(std::string_view, span<u8>) -> u32 = 0; protected: explicit file_browser() = default; diff --git a/lib/nes/common/CMakeLists.txt b/lib/nes/common/CMakeLists.txt index f0ee288..a7c1d76 100644 --- a/lib/nes/common/CMakeLists.txt +++ b/lib/nes/common/CMakeLists.txt @@ -12,4 +12,5 @@ target_sources( path-view.hh path-view.cc path-builder.hh - path-builder.cc)
\ No newline at end of file + path-builder.cc + span.hh)
\ No newline at end of file diff --git a/lib/nes/common/path-builder.cc b/lib/nes/common/path-builder.cc index 67190dc..794d565 100644 --- a/lib/nes/common/path-builder.cc +++ b/lib/nes/common/path-builder.cc @@ -2,12 +2,11 @@ namespace nes { - path_builder::path_builder(char* buffer, u32 const buffer_length) + path_builder::path_builder(span<char> const buffer) : buffer_{ buffer } - , buffer_length_{ buffer_length } { // Initialize the path to "/" if possible. - if (buffer_length > 0) { buffer_[actual_length_++] = '/'; } + if (buffer_.get_length() > 0) { buffer_[length_++] = '/'; } } auto path_builder::push(std::string_view component) -> bool @@ -18,30 +17,30 @@ namespace nes if (component.empty() || std::find(component.begin(), component.end(), '/') != component.end()) { return false; } // Check if there is enough remaining capacity for "/<component>" - auto const add_leading_slash = actual_length_ == 0 || buffer_[actual_length_ - 1] != '/'; + auto const add_leading_slash = length_ == 0 || buffer_[length_ - 1] != '/'; auto const length = component.length() + (add_leading_slash ? 1 : 0); - if (actual_length_ + length > buffer_length_) { return false; } + if (length_ + length > buffer_.get_length()) { return false; } // Append "/<component>" - if (add_leading_slash) { buffer_[actual_length_++] = '/'; } - for (auto i = u32{ 0 }; i < component.length(); ++i) { buffer_[actual_length_++] = component[i]; } + if (add_leading_slash) { buffer_[length_++] = '/'; } + for (auto i = u32{ 0 }; i < component.length(); ++i) { buffer_[length_++] = component[i]; } return true; } auto path_builder::pop() -> bool { - if (actual_length_ == 0 || buffer_[actual_length_ - 1] == '/') { return false; } + if (length_ == 0 || buffer_[length_ - 1] == '/') { return false; } // Find the start of the last component. - auto last_start = actual_length_ - 1; + auto last_start = length_ - 1; while (last_start > 0 && buffer_[last_start] != '/') { last_start -= 1; } // Drop the slash if we are not at the root. if (last_start == 0) { last_start += 1; } // Drop everything including the trailing slash. - actual_length_ = last_start; + length_ = last_start; return true; } } // namespace nes
\ No newline at end of file diff --git a/lib/nes/common/path-builder.hh b/lib/nes/common/path-builder.hh index 727d18c..b64fb28 100644 --- a/lib/nes/common/path-builder.hh +++ b/lib/nes/common/path-builder.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/common/types.hh" +#include "nes/common/span.hh" #include "nes/common/path-view.hh" #include <string_view> @@ -9,15 +10,14 @@ namespace nes /// A mutable path with a fixed-length buffer. class path_builder { - char* buffer_{ nullptr }; - u32 buffer_length_{ 0 }; - u32 actual_length_{ 0 }; + span<char> buffer_; + u32 length_{ 0 }; public: - explicit path_builder(char* buffer, u32 buffer_length); + explicit path_builder(span<char>); auto get_components() const -> path_view { return path_view{ get_path() }; } - auto get_path() const -> std::string_view { return std::string_view{ buffer_, actual_length_ }; } + auto get_path() const -> std::string_view { return std::string_view{ buffer_.get_data(), length_ }; } auto push(std::string_view) -> bool; auto pop() -> bool; @@ -31,7 +31,7 @@ namespace nes public: explicit path_buffer() - : path_builder{ buffer_, Capacity } + : path_builder{ buffer_ } { } }; diff --git a/lib/nes/common/span.hh b/lib/nes/common/span.hh new file mode 100644 index 0000000..16eb129 --- /dev/null +++ b/lib/nes/common/span.hh @@ -0,0 +1,82 @@ +#pragma once + +#include "nes/common/types.hh" + +namespace nes +{ + namespace detail + { + struct span_unchecked{}; + + inline constexpr auto span_dynamic_length = u32{ 0xFFFF }; + + template<typename T> + struct remove_const + { + using type = T; + }; + + template<typename T> + struct remove_const<T const> + { + using type = T; + }; + } // namespace detail + + /// Implementation of a container similar to std::span in C++20. + template<typename T, u32 Length = detail::span_dynamic_length> + class span + { + template<typename U, u32 OtherLength> + friend class span; + + T* data_{ nullptr }; + u32 length_{ 0 }; + + public: + using iterator = T*; + + explicit span() + { + static_assert(Length == 0 || Length == detail::span_dynamic_length); + } + + explicit span(T* data, u32 const length) + : span{ data, length, {} } + { + static_assert(Length == detail::span_dynamic_length); + } + + template<u32 ActualLength> + span(T (&data)[ActualLength]) + : span{ data, ActualLength, {} } + { + static_assert(Length == ActualLength || Length == detail::span_dynamic_length); + } + + span(span<typename detail::remove_const<T>::type, Length> const other) + : span{ other.data_, other.length_, {} } + { + } + + auto get_data() const -> T* { return data_; } + auto get_length() const -> u32 { return length_; } + + auto begin() const -> iterator { return data_; } + auto end() const -> iterator { return data_ + length_; } + + auto subspan(u32 const first, u32 const length) const -> span<T> { return span{ data_ + first, length }; } + auto subspan(u32 const first) const -> span<T> { return subspan(length_ - first); } + template<u32 OtherLength> + auto subspan(u32 const first) const -> span<T, OtherLength> { return span<T, OtherLength>{ data_ + first, OtherLength, {} }; } + + auto operator[](u32 const index) const -> T& { return data_[index]; } + + private: + explicit span(T* data, u32 const length, detail::span_unchecked) + : data_{ data } + , length_{ length } + { + } + }; +} // namespace nes
\ No newline at end of file diff --git a/lib/nes/common/string-builder.cc b/lib/nes/common/string-builder.cc index efc1326..087f0d4 100644 --- a/lib/nes/common/string-builder.cc +++ b/lib/nes/common/string-builder.cc @@ -2,22 +2,21 @@ namespace nes { - string_builder::string_builder(char* buffer, u32 buffer_length) + string_builder::string_builder(span<char> const buffer) : buffer_{ buffer } - , buffer_length_{ buffer_length } { } auto string_builder::append_char(char const value) -> string_builder& { - if (actual_length_ == buffer_length_) + if (length_ == buffer_.get_length()) { is_good_ = false; return *this; } - buffer_[actual_length_] = value; - actual_length_ += 1; + buffer_[length_] = value; + length_ += 1; return *this; } diff --git a/lib/nes/common/string-builder.hh b/lib/nes/common/string-builder.hh index e0bc673..256c267 100644 --- a/lib/nes/common/string-builder.hh +++ b/lib/nes/common/string-builder.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/common/types.hh" +#include "nes/common/span.hh" #include <string_view> namespace nes @@ -16,9 +17,8 @@ namespace nes /// Builds a string into a fixed-length buffer. class string_builder { - char* buffer_{ nullptr }; - u32 buffer_length_{ 0 }; - u32 actual_length_{ 0 }; + span<char> buffer_; + u32 length_{ 0 }; bool is_good_{ true }; enum class format_arg_type @@ -60,10 +60,10 @@ namespace nes }; public: - explicit string_builder(char* buffer, u32 buffer_length); + explicit string_builder(span<char>); /// Get the resulting string. - auto get_result() const -> std::string_view { return std::string_view{ buffer_, actual_length_ }; } + auto get_result() const -> std::string_view { return std::string_view{ buffer_.get_data(), length_ }; } /// Returns false after an invalid format string or buffer overflow. auto is_good() const -> bool { return is_good_; } @@ -104,7 +104,7 @@ namespace nes public: explicit string_buffer() - : string_builder{ buffer_, Capacity } + : string_builder{ buffer_ } { } }; diff --git a/lib/nes/sys/cartridge.cc b/lib/nes/sys/cartridge.cc index fcb7e84..14fff3d 100644 --- a/lib/nes/sys/cartridge.cc +++ b/lib/nes/sys/cartridge.cc @@ -5,15 +5,13 @@ namespace nes::sys { - cartridge::cartridge(u8 const* data, u32 const length) + cartridge::cartridge(span<u8 const> const data) { // See: https://www.nesdev.org/wiki/INES - auto const bytes = static_cast<u8 const*>(data); - // Parse header. - if (length < header_length) { return; } - auto const h = header{ bytes }; + if (data.get_length() < header_length) { return; } + auto const h = header{ data.subspan<header_length>(0) }; if (h.get_magic_0() != 'N' || h.get_magic_1() != 'E' || h.get_magic_2() != 'S' || h.get_magic_3() != 0x1A) { return; @@ -28,16 +26,16 @@ namespace nes::sys if (h.get_has_trainer()) { offset += 512; } prg_rom_size_ = h.get_prg_rom_banks() * prg_rom_bank_size; - if (length < offset + prg_rom_size_) { return; } + if (data.get_length() < offset + prg_rom_size_) { return; } if (prg_rom_size_ > max_prg_rom_size) { return; } - std::copy_n(&bytes[offset], prg_rom_size_, prg_rom_); + std::copy_n(&data[offset], prg_rom_size_, prg_rom_); offset += prg_rom_size_; chr_rom_size_ = h.get_chr_rom_banks() * chr_rom_bank_size; - if (length < offset + chr_rom_size_) { return; } + if (data.get_length() < offset + chr_rom_size_) { return; } if (chr_rom_size_ > max_chr_rom_size) { return; } - std::copy_n(&bytes[offset], chr_rom_size_, chr_rom_); + std::copy_n(&data[offset], chr_rom_size_, chr_rom_); ram_size_ = std::max(h.get_ram_banks(), 1u) * ram_bank_size; if (ram_size_ > max_ram_size) { return; } diff --git a/lib/nes/sys/cartridge.hh b/lib/nes/sys/cartridge.hh index 1934b8d..5383b56 100644 --- a/lib/nes/sys/cartridge.hh +++ b/lib/nes/sys/cartridge.hh @@ -3,8 +3,7 @@ #include "nes/sys/types/status.hh" #include "nes/sys/mapper.hh" #include "nes/common/types.hh" -#include <vector> -#include <string_view> +#include "nes/common/span.hh" namespace nes::sys { @@ -42,7 +41,7 @@ namespace nes::sys u8 value[header_length]{}; - explicit header(u8 const* v) + explicit header(span<u8 const, header_length> const v) { for (auto i = u32{ 0 }; i < header_length; ++i) { @@ -64,16 +63,13 @@ namespace nes::sys public: static constexpr auto max_file_size = u32{ max_prg_rom_size + max_chr_rom_size + 512 + header_length }; - explicit cartridge(u8 const* data, u32 length); + explicit cartridge(span<u8 const>); auto get_status() const -> status { return status_; } - auto get_prg_rom() const -> u8 const* { return prg_rom_; } - auto get_prg_rom_length() const -> u32 { return prg_rom_size_; } - auto get_chr_rom() const -> u8 const* { return chr_rom_; } - auto get_chr_rom_length() const -> u32 { return chr_rom_size_; } - auto get_ram() const -> u8 const* { return ram_; } - auto get_ram_mut() -> u8* { return ram_; } - auto get_ram_length() const -> u32 { return ram_size_; } + auto get_prg_rom() const -> span<u8 const> { return span{ prg_rom_, prg_rom_size_ }; } + auto get_chr_rom() const -> span<u8 const> { return span{ chr_rom_, chr_rom_size_ }; } + auto get_ram() const -> span<u8 const> { return span{ ram_, ram_size_ }; } + auto ref_ram() -> span<u8> { return span{ ram_, ram_size_ }; } auto get_mapper() const -> mapper& { return *mapper_; } auto get_name_table_arrangement() const -> name_table_arrangement { return name_table_arrangement_; } }; diff --git a/lib/nes/sys/mapper.cc b/lib/nes/sys/mapper.cc index d779076..e5c9a2b 100644 --- a/lib/nes/sys/mapper.cc +++ b/lib/nes/sys/mapper.cc @@ -16,17 +16,17 @@ namespace nes::sys auto validate(cartridge& cartridge) -> status override { - if (cartridge.get_ram_length() != 0x2000) + if (cartridge.get_ram().get_length() != 0x2000) { return status::error_invalid_ines_data; } - if (cartridge.get_prg_rom_length() != 0x4000 && cartridge.get_prg_rom_length() != 0x8000) + if (cartridge.get_prg_rom().get_length() != 0x4000 && cartridge.get_prg_rom().get_length() != 0x8000) { return status::error_invalid_ines_data; } - if (cartridge.get_chr_rom_length() != 0x2000) + if (cartridge.get_chr_rom().get_length() != 0x2000) { return status::error_invalid_ines_data; } @@ -52,7 +52,7 @@ namespace nes::sys if (addr <= address{ 0xFFFF }) { auto rel = addr.get_absolute() - 0xC000u; - if (cartridge.get_prg_rom_length() > 0x4000) { rel += 0x4000; } + if (cartridge.get_prg_rom().get_length() > 0x4000) { rel += 0x4000; } return cartridge.get_prg_rom()[rel]; } @@ -67,12 +67,12 @@ namespace nes::sys } if (addr <= address{ 0x7FFF }) { - cartridge.get_ram_mut()[addr.get_absolute() - 0x6000] = value; + cartridge.ref_ram()[addr.get_absolute() - 0x6000] = value; return; } } - auto read_ppu(address const addr, cartridge& cartridge, u8 const* vram) -> u8 override + auto read_ppu(address const addr, cartridge& cartridge, span<u8 const> const vram) -> u8 override { if (addr <= address{ 0x1FFF }) { @@ -87,7 +87,7 @@ namespace nes::sys return 0x0; } - auto write_ppu(address const addr, u8 const value, cartridge& cartridge, u8* vram) -> void override + auto write_ppu(address const addr, u8 const value, cartridge& cartridge, span<u8> const vram) -> void override { if (addr <= address{ 0x1FFF }) { @@ -139,8 +139,8 @@ namespace nes::sys auto validate(cartridge&) -> status override { return status::error_unsupported_mapper; } auto read_cpu(address, cartridge&) -> u8 override { return 0; } auto write_cpu(address, u8, cartridge&) -> void override {} - auto read_ppu(address, cartridge&, u8 const*) -> u8 override { return 0; } - auto write_ppu(address, u8, cartridge&, u8*) -> void override {} + auto read_ppu(address, cartridge&, span<u8 const>) -> u8 override { return 0; } + auto write_ppu(address, u8, cartridge&, span<u8>) -> void override {} }; } // namespace diff --git a/lib/nes/sys/mapper.hh b/lib/nes/sys/mapper.hh index c7c9784..9ad88e2 100644 --- a/lib/nes/sys/mapper.hh +++ b/lib/nes/sys/mapper.hh @@ -3,6 +3,7 @@ #include "nes/sys/types/address.hh" #include "nes/sys/types/status.hh" #include "nes/common/types.hh" +#include "nes/common/span.hh" namespace nes::sys { @@ -24,8 +25,8 @@ namespace nes::sys virtual auto validate(cartridge&) -> status = 0; virtual auto read_cpu(address, cartridge&) -> u8 = 0; virtual auto write_cpu(address, u8, cartridge&) -> void = 0; - virtual auto read_ppu(address, cartridge&, u8 const* vram) -> u8 = 0; - virtual auto write_ppu(address, u8, cartridge&, u8* vram) -> void = 0; + virtual auto read_ppu(address, cartridge&, span<u8 const> vram) -> u8 = 0; + virtual auto write_ppu(address, u8, cartridge&, span<u8> vram) -> void = 0; protected: explicit mapper() = default; diff --git a/lib/nes/sys/nes.cc b/lib/nes/sys/nes.cc index 3195826..5cc47a4 100644 --- a/lib/nes/sys/nes.cc +++ b/lib/nes/sys/nes.cc @@ -3,8 +3,8 @@ namespace nes::sys { - nes::nes(display& display, u8 const* rom_data, u32 rom_length) - : cartridge_{ rom_data, rom_length } + nes::nes(display& display, span<u8 const> const rom_data) + : cartridge_{ rom_data } , display_{ display } , ppu_{ cpu_, cartridge_, display_ } , cpu_{ ppu_, cartridge_, controller_1_, controller_2_ } @@ -52,7 +52,7 @@ namespace nes::sys auto nes::get_snapshot() -> snapshot { auto res = snapshot{}; - res.sram = std::vector(cartridge_.get_ram(), cartridge_.get_ram() + cartridge_.get_ram_length()); + res.sram = std::vector(cartridge_.get_ram().begin(), cartridge_.get_ram().end()); cpu_.build_snapshot(res); ppu_.build_snapshot(res); return res; diff --git a/lib/nes/sys/nes.hh b/lib/nes/sys/nes.hh index 5e081b3..187b940 100644 --- a/lib/nes/sys/nes.hh +++ b/lib/nes/sys/nes.hh @@ -5,7 +5,7 @@ #include "nes/sys/controller.hh" #include "nes/sys/cpu.hh" #include "nes/sys/ppu.hh" -#include <string_view> +#include "nes/common/span.hh" namespace nes { @@ -29,7 +29,7 @@ namespace nes::sys status status_{ status::error_invalid_ines_data }; public: - explicit nes(display&, u8 const* rom_data, u32 rom_length); + explicit nes(display&, span<u8 const> rom_data); nes(nes const&) = delete; nes(nes&&) = delete; diff --git a/lib/nes/sys/ppu.cc b/lib/nes/sys/ppu.cc index c9e6f11..2419030 100644 --- a/lib/nes/sys/ppu.cc +++ b/lib/nes/sys/ppu.cc @@ -239,7 +239,7 @@ namespace nes::sys sprite_count_ = 0; for (auto i = u32{ 0 }; i < sprite_max_count; ++i) { - auto const s = sprite{ &oam_[i * 4] }; + auto const s = sprite{ span{ oam_ }.subspan<4>(i * 4) }; auto const row = static_cast<int>(scanline_) - static_cast<int>(s.get_y()); if (row < 0 || static_cast<u32>(row) >= height) { continue; } diff --git a/lib/nes/sys/ppu.hh b/lib/nes/sys/ppu.hh index 013546a..7774669 100644 --- a/lib/nes/sys/ppu.hh +++ b/lib/nes/sys/ppu.hh @@ -2,6 +2,7 @@ #include "nes/sys/types/cycle-count.hh" #include "nes/common/types.hh" +#include "nes/common/span.hh" namespace nes { @@ -96,7 +97,7 @@ namespace nes::sys explicit sprite() = default; - explicit sprite(u8 const* data) + explicit sprite(span<u8 const, 4> const data) : value{ data[0], data[1], data[2], data[3] } { } |
