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:
commit
cfc44cf778
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user