summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/nes/app/application.cc6
-rw-r--r--lib/nes/app/file-browser.hh3
-rw-r--r--lib/nes/common/CMakeLists.txt3
-rw-r--r--lib/nes/common/path-builder.cc19
-rw-r--r--lib/nes/common/path-builder.hh12
-rw-r--r--lib/nes/common/span.hh82
-rw-r--r--lib/nes/common/string-builder.cc9
-rw-r--r--lib/nes/common/string-builder.hh12
-rw-r--r--lib/nes/sys/cartridge.cc16
-rw-r--r--lib/nes/sys/cartridge.hh18
-rw-r--r--lib/nes/sys/mapper.cc18
-rw-r--r--lib/nes/sys/mapper.hh5
-rw-r--r--lib/nes/sys/nes.cc6
-rw-r--r--lib/nes/sys/nes.hh4
-rw-r--r--lib/nes/sys/ppu.cc2
-rw-r--r--lib/nes/sys/ppu.hh3
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] }
{
}