1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-30 19:30:17 +00:00

Merge pull request #752 from TomHarte/MacintoshBus

Reduces 8-bit memory access costs for the Macintosh.
This commit is contained in:
Thomas Harte 2020-02-13 23:03:07 -05:00 committed by GitHub
commit cfc44cf778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -123,10 +123,10 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
rom_descriptions.emplace_back(machine_name, "the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s); rom_descriptions.emplace_back(machine_name, "the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s);
} break; } break;
} }
ram_mask_ = (ram_size >> 1) - 1; ram_mask_ = ram_size - 1;
rom_mask_ = (rom_size >> 1) - 1; rom_mask_ = rom_size - 1;
ram_.resize(ram_size >> 1); ram_.resize(ram_size);
video_.set_ram(ram_.data(), ram_mask_); video_.set_ram(reinterpret_cast<uint16_t *>(ram_.data()), ram_mask_ >> 1);
// Grab a copy of the ROM and convert it into big-endian data. // Grab a copy of the ROM and convert it into big-endian data.
const auto roms = rom_fetcher(rom_descriptions); const auto roms = rom_fetcher(rom_descriptions);
@ -196,11 +196,11 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
// A null cycle leaves nothing else to do. // A null cycle leaves nothing else to do.
if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0); if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0);
// Grab the value on the address bus, at word precision. // Grab the address.
uint32_t word_address = cycle.active_operation_word_address(); auto address = cycle.host_endian_byte_address();
// Everything above E0 0000 is signalled as being on the peripheral bus. // Everything above E0 0000 is signalled as being on the peripheral bus.
mc68000_.set_is_peripheral_address(word_address >= 0x700000); mc68000_.set_is_peripheral_address(address >= 0xe0'0000);
// All code below deals only with reads and writes — cycles in which a // All code below deals only with reads and writes — cycles in which a
// data select is active. So quit now if this is not the active part of // data select is active. So quit now if this is not the active part of
@ -213,9 +213,9 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
if(!cycle.data_select_active() || (cycle.operation & Microcycle::InterruptAcknowledge)) return HalfCycles(0); if(!cycle.data_select_active() || (cycle.operation & Microcycle::InterruptAcknowledge)) return HalfCycles(0);
// Grab the word-precision address being accessed. // Grab the word-precision address being accessed.
uint16_t *memory_base = nullptr; uint8_t *memory_base = nullptr;
HalfCycles delay; HalfCycles delay;
switch(memory_map_[word_address >> 16]) { switch(memory_map_[address >> 17]) {
default: assert(false); default: assert(false);
case BusDevice::Unassigned: case BusDevice::Unassigned:
@ -226,7 +226,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
if(*cycle.address & 1) { if(*cycle.address & 1) {
fill_unmapped(cycle); fill_unmapped(cycle);
} else { } else {
const int register_address = word_address >> 8; const int register_address = address >> 9;
// VIA accesses are via address 0xefe1fe + register*512, // VIA accesses are via address 0xefe1fe + register*512,
// which at word precision is 0x77f0ff + register*256. // which at word precision is 0x77f0ff + register*256.
@ -250,7 +250,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
case BusDevice::IWM: { case BusDevice::IWM: {
if(*cycle.address & 1) { if(*cycle.address & 1) {
const int register_address = word_address >> 8; const int register_address = address >> 9;
// The IWM; this is a purely polled device, so can be run on demand. // The IWM; this is a purely polled device, so can be run on demand.
if(cycle.operation & Microcycle::Read) { if(cycle.operation & Microcycle::Read) {
@ -266,8 +266,8 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
} return delay; } return delay;
case BusDevice::SCSI: { case BusDevice::SCSI: {
const int register_address = word_address >> 3; const int register_address = address >> 4;
const bool dma_acknowledge = word_address & 0x100; const bool dma_acknowledge = address & 0x200;
// Even accesses = read; odd = write. // Even accesses = read; odd = write.
if(*cycle.address & 1) { if(*cycle.address & 1) {
@ -308,7 +308,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
cycle.value->halves.low = 0xff; cycle.value->halves.low = 0xff;
} }
} else { } else {
const auto read = scc_.read(int(word_address)); const auto read = scc_.read(int(address >> 1));
if(cycle.operation & Microcycle::Read) { if(cycle.operation & Microcycle::Read) {
cycle.value->halves.low = read; cycle.value->halves.low = read;
} }
@ -323,10 +323,10 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
} else { } else {
if(*cycle.address & 1) { if(*cycle.address & 1) {
if(cycle.operation & Microcycle::Read) { if(cycle.operation & Microcycle::Read) {
scc_.write(int(word_address), 0xff); scc_.write(int(address >> 1), 0xff);
cycle.value->halves.low = 0xff; cycle.value->halves.low = 0xff;
} else { } else {
scc_.write(int(word_address), cycle.value->halves.low); scc_.write(int(address >> 1), cycle.value->halves.low);
} }
} else { } else {
fill_unmapped(cycle); fill_unmapped(cycle);
@ -338,13 +338,13 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
// This is coupled with the Macintosh implementation of video; the magic // This is coupled with the Macintosh implementation of video; the magic
// constant should probably be factored into the Video class. // constant should probably be factored into the Video class.
// It embodies knowledge of the fact that video (and audio) will always // It embodies knowledge of the fact that video (and audio) will always
// be fetched from the final $d900 bytes (i.e. $6c80 words) of memory. // be fetched from the final $d900 bytes of memory.
// (And that ram_mask_ = ram size - 1). // (And that ram_mask_ = ram size - 1).
if(word_address > ram_mask_ - 0x6c80) if(address > ram_mask_ - 0xd900)
update_video(); update_video();
memory_base = ram_.data(); memory_base = ram_.data();
word_address &= ram_mask_; address &= ram_mask_;
// Apply a delay due to video contention if applicable; scheme applied: // Apply a delay due to video contention if applicable; scheme applied:
// only every other access slot is available during the period of video // only every other access slot is available during the period of video
@ -359,7 +359,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
case BusDevice::ROM: { case BusDevice::ROM: {
if(!(cycle.operation & Microcycle::Read)) return delay; if(!(cycle.operation & Microcycle::Read)) return delay;
memory_base = rom_; memory_base = rom_;
word_address &= rom_mask_; address &= rom_mask_;
} break; } break;
} }
@ -369,19 +369,16 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
break; break;
case Microcycle::SelectWord | Microcycle::Read: case Microcycle::SelectWord | Microcycle::Read:
cycle.value->full = memory_base[word_address]; cycle.value->full = *reinterpret_cast<uint16_t *>(&memory_base[address]);
break; break;
case Microcycle::SelectByte | Microcycle::Read: case Microcycle::SelectByte | Microcycle::Read:
cycle.value->halves.low = uint8_t(memory_base[word_address] >> cycle.byte_shift()); cycle.value->halves.low = memory_base[address];
break; break;
case Microcycle::SelectWord: case Microcycle::SelectWord:
memory_base[word_address] = cycle.value->full; *reinterpret_cast<uint16_t *>(&memory_base[address]) = cycle.value->full;
break; break;
case Microcycle::SelectByte: case Microcycle::SelectByte:
memory_base[word_address] = uint16_t( memory_base[address] = cycle.value->halves.low;
(cycle.value->halves.low << cycle.byte_shift()) |
(memory_base[word_address] & cycle.untouched_byte_mask())
);
break; break;
} }
@ -473,7 +470,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
drives_[0].set_disk(media.disks[0]); drives_[0].set_disk(media.disks[0]);
} }
// TODO: allow this only at machine startup. // TODO: allow this only at machine startup?
if(!media.mass_storage_devices.empty()) { if(!media.mass_storage_devices.empty()) {
const auto volume = dynamic_cast<Storage::MassStorage::Encodings::Macintosh::Volume *>(media.mass_storage_devices.front().get()); const auto volume = dynamic_cast<Storage::MassStorage::Encodings::Macintosh::Volume *>(media.mass_storage_devices.front().get());
if(volume) { if(volume) {
@ -535,8 +532,10 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
if(quick_boot) { if(quick_boot) {
// Cf. Big Mess o' Wires' disassembly of the Mac Plus ROM, and the // Cf. Big Mess o' Wires' disassembly of the Mac Plus ROM, and the
// test at $E00. TODO: adapt as(/if?) necessary for other Macs. // test at $E00. TODO: adapt as(/if?) necessary for other Macs.
ram_[0x02ae >> 1] = 0x40; ram_[0x02ae] = 0x40;
ram_[0x02b0 >> 1] = 0x00; ram_[0x02af] = 0x00;
ram_[0x02b0] = 0x00;
ram_[0x02b1] = 0x00;
} }
} }
} }
@ -570,11 +569,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
forceinline void fill_unmapped(const Microcycle &cycle) { forceinline void fill_unmapped(const Microcycle &cycle) {
if(!(cycle.operation & Microcycle::Read)) return; if(!(cycle.operation & Microcycle::Read)) return;
if(cycle.operation & Microcycle::SelectWord) { cycle.set_value16(0xffff);
cycle.value->full = 0xffff;
} else {
cycle.value->halves.low = 0xff;
}
} }
/// Advances all non-CPU components by @c duration half cycles. /// Advances all non-CPU components by @c duration half cycles.
@ -857,8 +852,8 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
uint32_t ram_mask_ = 0; uint32_t ram_mask_ = 0;
uint32_t rom_mask_ = 0; uint32_t rom_mask_ = 0;
uint16_t rom_[64*1024]; // i.e. up to 128kb in size. uint8_t rom_[128*1024];
std::vector<uint16_t> ram_; std::vector<uint8_t> ram_;
}; };
} }