From 3393df9a68df2322ee776d7cd3d14852e08a69ac Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 26 Nov 2025 22:24:29 -0500 Subject: [PATCH 1/3] Permit construction from any integral type. --- Numeric/SizedInt.hpp | 46 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Numeric/SizedInt.hpp b/Numeric/SizedInt.hpp index 1f03eba99..e3d725b6f 100644 --- a/Numeric/SizedInt.hpp +++ b/Numeric/SizedInt.hpp @@ -10,6 +10,8 @@ #include "Sizes.hpp" +#include + namespace Numeric { /*! @@ -21,42 +23,44 @@ struct SizedInt { using IntT = MinIntForValue<1 << bits>::type; inline static constexpr IntT Mask = (1 << bits) - 1; - constexpr SizedInt(const IntT start_value) noexcept : counter_(start_value & Mask) {} + template + constexpr SizedInt(const ConstructionT start_value) noexcept : value_(IntT(start_value & Mask)) {} + SizedInt() = default; template IntT get() const { - return counter_ >> begin; + return value_ >> begin; } - SizedInt operator +(const SizedInt offset) const { return SizedInt(counter_ + offset.counter_); } - SizedInt operator -(const SizedInt offset) const { return SizedInt(counter_ - offset.counter_); } - SizedInt operator &(const SizedInt offset) const { return SizedInt(counter_ & offset.counter_); } - SizedInt operator |(const SizedInt offset) const { return SizedInt(counter_ | offset.counter_); } - SizedInt operator ^(const SizedInt offset) const { return SizedInt(counter_ ^ offset.counter_); } - SizedInt operator >>(const int shift) const { return SizedInt(counter_ >> shift); } - SizedInt operator <<(const int shift) const { return SizedInt(counter_ << shift); } + SizedInt operator +(const SizedInt offset) const { return SizedInt(value_ + offset.value_); } + SizedInt operator -(const SizedInt offset) const { return SizedInt(value_ - offset.value_); } + SizedInt operator &(const SizedInt offset) const { return SizedInt(value_ & offset.value_); } + SizedInt operator |(const SizedInt offset) const { return SizedInt(value_ | offset.value_); } + SizedInt operator ^(const SizedInt offset) const { return SizedInt(value_ ^ offset.value_); } + SizedInt operator >>(const int shift) const { return SizedInt(value_ >> shift); } + SizedInt operator <<(const int shift) const { return SizedInt(value_ << shift); } SizedInt &operator &=(const SizedInt offset) { - counter_ &= offset.counter_; + value_ &= offset.value_; return *this; } SizedInt &operator |=(const SizedInt offset) { - counter_ |= offset.counter_; + value_ |= offset.value_; return *this; } SizedInt &operator ^=(const SizedInt offset) { - counter_ ^= offset.counter_; + value_ ^= offset.value_; return *this; } SizedInt &operator <<=(const int shift) { - counter_ = (counter_ << shift) & Mask; + value_ = (value_ << shift) & Mask; return *this; } SizedInt &operator >>=(const int shift) { - counter_ >>= shift; + value_ >>= shift; return *this; } @@ -66,17 +70,17 @@ struct SizedInt { } SizedInt &operator ++() { - counter_ = (counter_ + 1) & Mask; + value_ = (value_ + 1) & Mask; return *this; } SizedInt &operator +=(const IntT rhs) { - counter_ = (counter_ + rhs) & Mask; + value_ = (value_ + rhs) & Mask; return *this; } bool operator!() const { - return !counter_; + return !value_; } auto operator <=>(const SizedInt &) const = default; @@ -85,8 +89,8 @@ struct SizedInt { template void load(const MinIntForValue<1 << (end - begin)>::type value) { const auto mask = (1 << end) - (1 << begin); - counter_ &= ~mask; - counter_ |= IntT((value << begin) & mask); + value_ &= ~mask; + value_ |= IntT((value << begin) & mask); } template @@ -97,11 +101,11 @@ struct SizedInt { template requires (index < bits) bool bit() const { - return counter_ & (1 << index); + return value_ & (1 << index); } private: - IntT counter_{}; + IntT value_{}; }; } From 906a16a6c1cac1945daeb9fe403f8c5c6c453a68 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 26 Nov 2025 22:36:08 -0500 Subject: [PATCH 2/3] Size RAM pool only as required. --- Machines/Enterprise/Enterprise.cpp | 70 ++++++++++++++++++------------ 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index 0d43cf5a3..f7c0e620c 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -28,6 +28,15 @@ namespace { using Logger = Log::Logger; + +static constexpr size_t ram_size(const Analyser::Static::Enterprise::Target::Model model) { + switch(model) { + case Analyser::Static::Enterprise::Target::Model::Enterprise64: return 64 * 1024; + default: + case Analyser::Static::Enterprise::Target::Model::Enterprise128: return 128 * 1024; + case Analyser::Static::Enterprise::Target::Model::Enterprise256: return 256 * 1024; + } +} } namespace Enterprise { @@ -71,7 +80,11 @@ namespace Enterprise { */ -template class ConcreteMachine: +template < + Analyser::Static::Enterprise::Target::Model model, + bool has_disk_controller, + bool is_6mhz +> class ConcreteMachine: public Activity::Source, public Configurable::Device, public CPU::Z80::BusHandler, @@ -84,17 +97,6 @@ template class ConcreteMachine: public MachineTypes::TimedMachine, public Utility::TypeRecipient { private: - constexpr uint8_t min_ram_slot(const Analyser::Static::Enterprise::Target &target) { - const auto ram_size = [&] { - switch(target.model) { - case Analyser::Static::Enterprise::Target::Model::Enterprise64: return 64*1024; - default: - case Analyser::Static::Enterprise::Target::Model::Enterprise128: return 128*1024; - case Analyser::Static::Enterprise::Target::Model::Enterprise256: return 256*1024; - } - }(); - return uint8_t(0x100 - ram_size / 0x4000); - } static constexpr double clock_rate = is_6mhz ? 6'000'000.0 : 4'000'000.0; using NickType = @@ -104,7 +106,6 @@ private: public: ConcreteMachine(const Analyser::Static::Enterprise::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : - min_ram_slot_(min_ram_slot(target)), z80_(*this), nick_(ram_.end() - 65536), dave_audio_(audio_queue_), @@ -616,21 +617,18 @@ public: private: // MARK: - Memory layout - std::array ram_{}; + std::array ram_{}; std::array exos_; std::array basic_; std::array exdos_rom_; std::array epdos_rom_; std::array host_fs_rom_; - const uint8_t min_ram_slot_; + static constexpr auto MinRAMSlot = uint8_t(0x100 - (ram_size(model) >> 14)); /// @returns A pointer to the start of the RAM segment representing @c page if any; otherwise @c nullptr. uint8_t *ram_segment(const uint8_t page) { - if(page < min_ram_slot_) return nullptr; - const auto ram_floor = (0x100 << 14) - ram_.size(); - // Each segment is 2^14 bytes long and there are 256 of them. So the Enterprise has a 22-bit address space. - // RAM is at the end of that range; `ram_floor` is the 22-bit address at which RAM starts. - return &ram_[size_t((page << 14)) - ram_floor]; + if(page < MinRAMSlot) return nullptr; + return &ram_[(page - MinRAMSlot) << 14]; } struct ROMPage { @@ -698,13 +696,9 @@ private: return; } - // Of whatever size of RAM I've declared above, use only the final portion. - // This correlated with Nick always having been handed the final 64kb and, - // at least while the RAM is the first thing declared above, does a little - // to benefit data locality. Albeit not in a useful sense. - if(offset >= min_ram_slot_) { + auto pointer = ram_segment(offset); + if(pointer) { is_video_[slot] = offset >= 0xfc; // TODO: this hard-codes a 64kb video assumption. - auto pointer = ram_segment(offset); apply(pointer, pointer); return; } @@ -950,15 +944,35 @@ using namespace Enterprise; namespace { +template +std::unique_ptr machine( + const Analyser::Static::Enterprise::Target &target, + const ROMMachine::ROMFetcher &rom_fetcher +) { + switch(target.model) { + using enum Analyser::Static::Enterprise::Target::Model; + + case Enterprise64: + return std::make_unique> + (target, rom_fetcher); + case Enterprise128: + return std::make_unique> + (target, rom_fetcher); + case Enterprise256: + return std::make_unique> + (target, rom_fetcher); + } +} + template std::unique_ptr machine( const Analyser::Static::Enterprise::Target &target, const ROMMachine::ROMFetcher &rom_fetcher ) { if(target.speed == Analyser::Static::Enterprise::Target::Speed::SixMHz) { - return std::make_unique>(target, rom_fetcher); + return machine(target, rom_fetcher); } else { - return std::make_unique>(target, rom_fetcher); + return machine(target, rom_fetcher); } } From 95ccdeb0e98e1c2e8f3e87f2e4f2c2ba3fec05ff Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 26 Nov 2025 22:46:42 -0500 Subject: [PATCH 3/3] Attempt to resolve GCC's control flow concern. --- Machines/Enterprise/Enterprise.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index f7c0e620c..7a29df7f0 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -952,6 +952,8 @@ std::unique_ptr machine( switch(target.model) { using enum Analyser::Static::Enterprise::Target::Model; + default: __builtin_unreachable(); + case Enterprise64: return std::make_unique> (target, rom_fetcher);