1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-17 06:29:28 +00:00

Ensure RAM is properly sized and available.

This commit is contained in:
Thomas Harte 2023-01-13 14:07:54 -05:00
parent befc81743a
commit 4190d25698
5 changed files with 55 additions and 41 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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<uint8_t> &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<MemorySlot::AccessType::ReadWrite>(0, 0, 0, 65536);
memory_slots_[RAMMemorySlot].resize_source(65536);
memory_slots_[RAMMemorySlot].template map<MemorySlot::AccessType::ReadWrite>(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<Parser::FileSpeed> 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<DiskROM *>(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];

View File

@ -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<uint8_t> &source) {
source_ = source;
}
void MemorySlot::resize_source(std::size_t size) {
source_.resize(size);
}
std::vector<uint8_t> &MemorySlot::source() {
return source_;
}
const std::vector<uint8_t> &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.
}

View File

@ -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, FCFF.
void apply_mapping(uint8_t port, uint8_t value);
/// Copies an underlying source buffer.
void set_source(const std::vector<uint8_t> &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<uint8_t> &source();
const std::vector<uint8_t> &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, FCFF.
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();