diff --git a/Machines/MSX/DiskROM.cpp b/Machines/MSX/DiskROM.cpp index 97d7a57aa..1311d99f0 100644 --- a/Machines/MSX/DiskROM.cpp +++ b/Machines/MSX/DiskROM.cpp @@ -10,7 +10,7 @@ using namespace MSX; -DiskROM::DiskROM(const MSX::MemorySlot &slot) : +DiskROM::DiskROM(MSX::MemorySlot &slot) : WD1770(P1793), rom_(slot.source()) { emplace_drives(2, 8000000, 300, 2); diff --git a/Machines/MSX/DiskROM.hpp b/Machines/MSX/DiskROM.hpp index 931668eb4..7d776b83f 100644 --- a/Machines/MSX/DiskROM.hpp +++ b/Machines/MSX/DiskROM.hpp @@ -23,7 +23,7 @@ namespace MSX { class DiskROM: public MemorySlotHandler, public WD::WD1770 { public: - DiskROM(const MSX::MemorySlot &slot); + DiskROM(MSX::MemorySlot &slot); void write(uint16_t address, uint8_t value, bool pc_is_outside_bios) final; uint8_t read(uint16_t address) final; diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 7f71610be..aeeb2b517 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -143,6 +143,11 @@ class ConcreteMachine: public Configurable::Device, public ClockingHint::Observer, public Activity::Source { + private: + static constexpr int RAMMemorySlot = 3; + static constexpr int RAMMemorySubSlot = 0; + + public: ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher): z80_(*this), @@ -156,7 +161,6 @@ class ConcreteMachine: i8255_port_handler_(*this, audio_toggle_, tape_player_), ay_port_handler_(tape_player_) { set_clock_rate(3579545); - std::memset(unpopulated_, 0xff, sizeof(unpopulated_)); clear_all_keys(); ay_.set_port_handler(&ay_port_handler_); @@ -234,11 +238,17 @@ class ConcreteMachine: // Figure out which BIOS to use, either a specific one or the generic // one appropriately patched. - const auto regional_bios = roms.find(regional_bios_name); - if(regional_bios != roms.end()) { - regional_bios->second.resize(32768); - memory_slots_[0].set_source(regional_bios->second); - } else { + bool has_bios = false; + if constexpr (model == Target::Model::MSX1) { + const auto regional_bios = roms.find(regional_bios_name); + if(regional_bios != roms.end()) { + regional_bios->second.resize(32768); + memory_slots_[0].set_source(regional_bios->second); + has_bios = true; + } + } + + if(!has_bios) { std::vector &bios = roms.find(bios_name)->second; bios.resize(32768); @@ -255,7 +265,9 @@ class ConcreteMachine: } memory_slots_[0].map(0, 0, 0, 32768); - memory_slots_[3].template map(0, 0, 0, 65536); + + memory_slots_[RAMMemorySlot].resize_source(65536); + memory_slots_[RAMMemorySlot].template map(RAMMemorySubSlot, 0, 0, 65536); // Add a disk cartridge if any disks were supplied. if(target.has_disk_drive) { @@ -447,8 +459,8 @@ class ConcreteMachine: using Parser = Storage::Tape::MSX::Parser; std::unique_ptr new_speed = Parser::find_header(tape_player_); if(new_speed) { - ram_[0xfca4] = new_speed->minimum_start_bit_duration; - ram_[0xfca5] = new_speed->low_high_disrimination_duration; + ram()[0xfca4] = new_speed->minimum_start_bit_duration; + ram()[0xfca5] = new_speed->low_high_disrimination_duration; z80_.set_value_of_register(CPU::Z80::Register::Flags, 0); } else { z80_.set_value_of_register(CPU::Z80::Register::Flags, 1); @@ -465,8 +477,8 @@ class ConcreteMachine: // Grab the current values of LOWLIM and WINWID. using Parser = Storage::Tape::MSX::Parser; Parser::FileSpeed tape_speed; - tape_speed.minimum_start_bit_duration = ram_[0xfca4]; - tape_speed.low_high_disrimination_duration = ram_[0xfca5]; + tape_speed.minimum_start_bit_duration = ram()[0xfca4]; + tape_speed.low_high_disrimination_duration = ram()[0xfca5]; // Ask the tape parser to grab a byte. int next_byte = Parser::get_byte(tape_speed, tape_player_); @@ -489,9 +501,12 @@ class ConcreteMachine: if(!address) { pc_zero_accesses_++; } - if(read_pointers_[address >> 13] == unpopulated_) { - performed_unmapped_access_ = true; - } + + // TODO: below relates to confidence measurements. Reinstate, somehow. +// if(is_unpopulated_[address >> 13] == unpopulated_) { +// performed_unmapped_access_ = true; +// } + pc_address_ = address; // This is retained so as to be able to name the source of an access to cartridge handlers. [[fallthrough]]; @@ -587,8 +602,8 @@ class ConcreteMachine: const int buffer_size = 40; // Also from the Red Book: GETPNT is at F3FAH and PUTPNT is at F3F8H. - int read_address = ram_[0xf3fa] | (ram_[0xf3fb] << 8); - int write_address = ram_[0xf3f8] | (ram_[0xf3f9] << 8); + int read_address = ram()[0xf3fa] | (ram()[0xf3fb] << 8); + int write_address = ram()[0xf3f8] | (ram()[0xf3f9] << 8); // Write until either the string is exhausted or the write_pointer is immediately // behind the read pointer; temporarily map write_address and read_address into @@ -599,7 +614,7 @@ class ConcreteMachine: while(characters_written < input_text_.size()) { const int next_write_address = (write_address + 1) % buffer_size; if(next_write_address == read_address) break; - ram_[write_address + buffer_start] = uint8_t(input_text_[characters_written]); + ram()[write_address + buffer_start] = uint8_t(input_text_[characters_written]); ++characters_written; write_address = next_write_address; } @@ -607,8 +622,8 @@ class ConcreteMachine: // Map the write address back into absolute terms and write it out again as PUTPNT. write_address += buffer_start; - ram_[0xf3f8] = uint8_t(write_address); - ram_[0xf3f9] = uint8_t(write_address >> 8); + ram()[0xf3f8] = uint8_t(write_address); + ram()[0xf3f9] = uint8_t(write_address >> 8); } break; @@ -690,6 +705,9 @@ class ConcreteMachine: } private: + uint8_t *ram() { + return memory_slots_[RAMMemorySlot].source().data(); + } DiskROM *get_disk_rom() { return dynamic_cast(memory_slots_[2].handler.get()); } @@ -795,15 +813,6 @@ class ConcreteMachine: MemorySlot memory_slots_[4]; MemorySlot *final_slot_ = nullptr; - /// Base RAM. - uint8_t ram_[65536]; - - /// A never-read area that writes for unmapped regions can be diverted to. - uint8_t scratch_[8192]; - - /// A never-written area that reads for unmapped regions can be sourced from. - uint8_t unpopulated_[8192]; - HalfCycles time_since_ay_update_; uint8_t key_states_[16]; diff --git a/Machines/MSX/MemorySlotHandler.cpp b/Machines/MSX/MemorySlotHandler.cpp index 5c039c8f1..28f160af1 100644 --- a/Machines/MSX/MemorySlotHandler.cpp +++ b/Machines/MSX/MemorySlotHandler.cpp @@ -39,16 +39,18 @@ uint8_t *MemorySlot::write_pointer(int segment) const { return write_pointers_[subslot][segment]; } -void MemorySlot::apply_mapping(uint8_t port, uint8_t value) { - // TODO. - (void)port; - (void)value; -} - void MemorySlot::set_source(const std::vector &source) { source_ = source; } +void MemorySlot::resize_source(std::size_t size) { + source_.resize(size); +} + +std::vector &MemorySlot::source() { + return source_; +} + const std::vector &MemorySlot::source() const { return source_; } @@ -71,7 +73,6 @@ void MemorySlot::map(int subslot, std::size_t source_address, uint16_t destinati source_address += 8192; } - // TODO: allow write_pointers_ to be set. // TODO: need to indicate that mapping changed. } diff --git a/Machines/MSX/MemorySlotHandler.hpp b/Machines/MSX/MemorySlotHandler.hpp index 3a1eefa8f..d20cba8a9 100644 --- a/Machines/MSX/MemorySlotHandler.hpp +++ b/Machines/MSX/MemorySlotHandler.hpp @@ -50,14 +50,14 @@ class MemorySlot { /// @returns A pointer to the area of memory currently underneath @c address. uint8_t *write_pointer(int segment) const; - /// Sets the value most-recently written to one of the standard - /// memory mapping ports, FC–FF. - void apply_mapping(uint8_t port, uint8_t value); - /// Copies an underlying source buffer. void set_source(const std::vector &source); + /// Sets the size of the underlying source buffer. + void resize_source(std::size_t); + /// Provides a reference to the internal source storage. + std::vector &source(); const std::vector &source() const; enum AccessType { @@ -107,6 +107,10 @@ class MemorySlotHandler { /*! Seeks the result of a read at @c address; this is used only if the area is unmapped. */ virtual uint8_t read([[maybe_unused]] uint16_t address) { return 0xff; } + /// Sets the value most-recently written to one of the standard + /// memory mapping ports, FC–FF. + virtual void apply_mapping([[maybe_unused]] uint8_t port, [[maybe_unused]] uint8_t value) {} + /*! @returns The probability that this handler is correct for the data it owns. */ float get_confidence() { return confidence_counter_.get_confidence();