diff --git a/Machines/Acorn/Archimedes/MemoryController.hpp b/Machines/Acorn/Archimedes/MemoryController.hpp index 0a7c83a7d..2e43da591 100644 --- a/Machines/Acorn/Archimedes/MemoryController.hpp +++ b/Machines/Acorn/Archimedes/MemoryController.hpp @@ -35,9 +35,9 @@ template struct MemoryController { MemoryController(InterruptObserverT &observer, ClockRateObserverT &clock_rate_observer) : ioc_(observer, clock_rate_observer, ram_.data()) { - read_zones_[0] = Zone::HighROM; // Temporarily put high ROM at address 0. - // TODO: could I just copy it in? Or, at least, - // could I detect at ROM loading time whether I can? + read_zones_[0] = ReadZone::HighROM; // Temporarily put high ROM at address 0. + // TODO: could I just copy it in? Or, at least, + // could I detect at ROM loading time whether I can? } int interrupt_mask() const { @@ -72,7 +72,20 @@ struct MemoryController { template bool write(uint32_t address, IntT source, InstructionSet::ARM::Mode, bool trans) { switch(write_zones_[(address >> 21) & 31]) { - case Zone::DMAAndMEMC: { + case WriteZone::LogicallyMappedRAM: { + const auto item = logical_ram(address, trans); + if(item < reinterpret_cast(ram_.data())) { + return false; + } + *item = source; + } break; + + case WriteZone::PhysicallyMappedRAM: + if(trans) return false; + physical_ram(address) = source; + break; + + case WriteZone::DMAAndMEMC: { if(trans) return false; const auto buffer_address = [](uint32_t source) -> uint32_t { @@ -133,40 +146,23 @@ struct MemoryController { } } break; - case Zone::LogicallyMappedRAM: { - const auto item = logical_ram(address, trans); - if(item < reinterpret_cast(ram_.data())) { - return false; - } - *item = source; - } break; - - case Zone::IOControllers: + case WriteZone::IOControllers: if(trans) return false; ioc_.template write(address, source); break; - case Zone::VideoController: + case WriteZone::VideoController: if(trans) return false; // TODO: handle byte writes correctly. ioc_.video().write(source); break; - case Zone::PhysicallyMappedRAM: - if(trans) return false; - physical_ram(address) = source; - break; - - case Zone::AddressTranslator: + case WriteZone::AddressTranslator: if(trans) return false; // printf("Translator write at %08x; replaces %08x\n", address, pages_[address & 0x7f]); pages_[address & 0x7f] = address; map_dirty_ = true; break; - - default: - printf("TODO: write of %08x to %08x [%lu]\n", source, address, sizeof(IntT)); - break; } return true; @@ -174,13 +170,8 @@ struct MemoryController { template bool read(uint32_t address, IntT &source, bool trans) { - switch (read_zones_[(address >> 21) & 31]) { - case Zone::PhysicallyMappedRAM: - if(trans) return false; - source = physical_ram(address); - break; - - case Zone::LogicallyMappedRAM: { + switch(read_zones_[(address >> 21) & 31]) { + case ReadZone::LogicallyMappedRAM: { const auto item = logical_ram(address, trans); if(item < reinterpret_cast(ram_.data())) { return false; @@ -188,25 +179,26 @@ struct MemoryController { source = *item; } break; - case Zone::LowROM: + case ReadZone::HighROM: + // Real test is: require A24=A25=0, then A25=1. + read_zones_[0] = ReadZone::LogicallyMappedRAM; + source = high_rom(address); + break; + + case ReadZone::PhysicallyMappedRAM: + if(trans) return false; + source = physical_ram(address); + break; + + case ReadZone::LowROM: // logger.error().append("TODO: Low ROM read from %08x", address); source = IntT(~0); break; - case Zone::HighROM: - // Real test is: require A24=A25=0, then A25=1. - read_zones_[0] = Zone::LogicallyMappedRAM; - source = high_rom(address); - break; - - case Zone::IOControllers: + case ReadZone::IOControllers: if(trans) return false; ioc_.template read(address, source); break; - - default: - logger.error().append("TODO: read from %08x", address); - break; } return true; @@ -244,32 +236,53 @@ struct MemoryController { private: Log::Logger logger; - enum class Zone { + enum class ReadZone { LogicallyMappedRAM, PhysicallyMappedRAM, IOControllers, LowROM, HighROM, + }; + enum class WriteZone { + LogicallyMappedRAM, + PhysicallyMappedRAM, + IOControllers, VideoController, DMAAndMEMC, AddressTranslator, }; - static std::array zones(bool is_read) { - std::array zones{}; + template + using Zone = std::conditional_t; + + template + static std::array, 0x20> zones() { + std::array, 0x20> zones{}; for(size_t c = 0; c < zones.size(); c++) { const auto address = c << 21; if(address < 0x200'0000) { - zones[c] = Zone::LogicallyMappedRAM; + zones[c] = Zone::LogicallyMappedRAM; } else if(address < 0x300'0000) { - zones[c] = Zone::PhysicallyMappedRAM; + zones[c] = Zone::PhysicallyMappedRAM; } else if(address < 0x340'0000) { - zones[c] = Zone::IOControllers; + zones[c] = Zone::IOControllers; } else if(address < 0x360'0000) { - zones[c] = is_read ? Zone::LowROM : Zone::VideoController; + if constexpr (is_read) { + zones[c] = Zone::LowROM; + } else { + zones[c] = Zone::VideoController; + } } else if(address < 0x380'0000) { - zones[c] = is_read ? Zone::LowROM : Zone::DMAAndMEMC; + if constexpr (is_read) { + zones[c] = Zone::LowROM; + } else { + zones[c] = Zone::DMAAndMEMC; + } } else { - zones[c] = is_read ? Zone::HighROM : Zone::AddressTranslator; + if constexpr (is_read) { + zones[c] = Zone::HighROM; + } else { + zones[c] = Zone::AddressTranslator; + } } } return zones; @@ -293,8 +306,8 @@ struct MemoryController { return *reinterpret_cast(&rom_[address & (rom_.size() - 1)]); } - std::array read_zones_ = zones(true); - const std::array write_zones_ = zones(false); + std::array read_zones_ = zones(); + const std::array write_zones_ = zones(); // Control register values. bool os_mode_ = false;