From 9796b308dc7030e27b130591618d39a7196427f6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Dec 2021 15:17:11 -0500 Subject: [PATCH] Add basic implementation of fast RAM. --- Analyser/Static/Amiga/Target.hpp | 16 +++++- Machines/Amiga/Amiga.cpp | 8 +++ Machines/Amiga/MemoryMap.hpp | 99 +++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/Analyser/Static/Amiga/Target.hpp b/Analyser/Static/Amiga/Target.hpp index 5987e290d..13dabf466 100644 --- a/Analyser/Static/Amiga/Target.hpp +++ b/Analyser/Static/Amiga/Target.hpp @@ -17,7 +17,21 @@ namespace Static { namespace Amiga { struct Target: public Analyser::Static::Target, public Reflection::StructImpl { - Target() : Analyser::Static::Target(Machine::Amiga) {} + ReflectableEnum(FastRAM, + None, + OneMegabyte, + TwoMegabytes, + FourMegabytes, + EightMegabytes); + + FastRAM fast_ram = FastRAM::TwoMegabytes; + + Target() : Analyser::Static::Target(Machine::Amiga) { + if(needs_declare()) { + DeclareField(fast_ram); + AnnounceEnum(FastRAM); + } + } }; } diff --git a/Machines/Amiga/Amiga.cpp b/Machines/Amiga/Amiga.cpp index e41c4a11d..ad92cf1a3 100644 --- a/Machines/Amiga/Amiga.cpp +++ b/Machines/Amiga/Amiga.cpp @@ -53,6 +53,7 @@ class ConcreteMachine: public: ConcreteMachine(const Analyser::Static::Amiga::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : mc68000_(*this), + memory_(target.fast_ram), chipset_(memory_, PALClockRate) { // Temporary: use a hard-coded Kickstart selection. @@ -146,6 +147,13 @@ class ConcreteMachine: // LOG("CIA " << (((address >> 12) & 3)^3) << " " << (cycle.operation & Microcycle::Read ? "read " : "write ") << std::dec << (reg & 0xf) << " of " << PADHEX(4) << +cycle.value16()); } else if(address >= 0xdf'f000 && address <= 0xdf'f1be) { chipset_.perform(cycle); + } else if(address >= 0xe8'0000 && address < 0xe9'0000) { + // This is the Autoconf space; right now the only + // Autoconf device this emulator implements is fast RAM, + // which if present is provided as part of the memory map. + // + // Relevant quote: "The Zorro II configuration space is the 64K memory block $00E8xxxx" + memory_.perform(cycle); } else { // This'll do for open bus, for now. if(cycle.operation & Microcycle::Read) { diff --git a/Machines/Amiga/MemoryMap.hpp b/Machines/Amiga/MemoryMap.hpp index a4532cd6d..de2b56264 100644 --- a/Machines/Amiga/MemoryMap.hpp +++ b/Machines/Amiga/MemoryMap.hpp @@ -9,6 +9,8 @@ #ifndef MemoryMap_hpp #define MemoryMap_hpp +#include "../../Analyser/Static/Amiga/Target.hpp" + namespace Amiga { class MemoryMap { @@ -19,15 +21,16 @@ class MemoryMap { public: // TODO: decide what of the below I want to be dynamic. - std::array chip_ram{}; std::array kickstart{0xff}; + std::array chip_ram{}; struct MemoryRegion { uint8_t *contents = nullptr; unsigned int read_write_mask = 0; } regions[64]; // i.e. top six bits are used as an index. - MemoryMap() { + using FastRAM = Analyser::Static::Amiga::Target::FastRAM; + MemoryMap(FastRAM fast_ram_size) { // Address spaces that matter: // // 00'0000 – 08'0000: chip RAM. [or overlayed KickStart] @@ -45,6 +48,29 @@ class MemoryMap { // f8'0000 — : 256kb Kickstart if 2.04 or higher. // fc'0000 – : 256kb Kickstart otherwise. set_region(0xfc'0000, 0x1'00'0000, kickstart.data(), PermitRead); + + switch(fast_ram_size) { + default: + fast_autoconf_visible_ = false; + break; + case FastRAM::OneMegabyte: + fast_ram_.resize(1 * 1024 * 1024); + fast_ram_size_ = 5; + break; + case FastRAM::TwoMegabytes: + fast_ram_.resize(2 * 1024 * 1024); + fast_ram_size_ = 6; + break; + case FastRAM::FourMegabytes: + fast_ram_.resize(4 * 1024 * 1024); + fast_ram_size_ = 7; + break; + case FastRAM::EightMegabytes: + fast_ram_.resize(8 * 1024 * 1024); + fast_ram_size_ = 0; + break; + } + reset(); } @@ -64,7 +90,76 @@ class MemoryMap { } } + /// Performs the provided microcycle, which the caller guarantees to be a memory access, + /// and in the Zorro register range. + bool perform(const CPU::MC68000::Microcycle &cycle) { + if(!fast_autoconf_visible_) return false; + + const uint32_t register_address = *cycle.address & 0xfe; + + using Microcycle = CPU::MC68000::Microcycle; + if(cycle.operation & Microcycle::Read) { + // Re: Autoconf: + // + // "All read registers physically return only the top 4 bits of data, on D31-D28"; + // (this is from Zorro III documentation; I'm assuming it to be D15–D11 for the + // 68000's 16-bit bus); + // + // "Every AUTOCONFIG register is logically considered to be 8 bits wide; the + // 8 bits actually being nybbles from two paired addresses." + + uint8_t value = 0xf; + switch(register_address) { + default: break; + + case 0x00: // er_Type (high) + value = + 0xc | // Zoro II-style PIC. + 0x2; // Memory will be linked into the free pool + break; + case 0x02: // er_Type (low) + value = fast_ram_size_; + break; + + // er_Manufacturer + // + // On the manufacturer number: this is supposed to be assigned + // by Commodore. TODO: find and crib a real fast RAM number, if it matters. + // + // (0xffff seems to be invalid, so _something_ needs to be supplied) + case 0x10: case 0x12: + value = 0xa; // Manufacturer's number, high byte. + break; + case 0x14: case 0x16: + value = 0xb; // Manufacturer's number, low byte. + break; + } + + // Shove the value into the top of the data bus. + cycle.set_value16(uint16_t(0x0fff | (value << 12))); + } else { + fast_autoconf_visible_ &= !(register_address >= 0x4c && register_address < 0x50); + + switch(register_address) { + default: break; + + case 0x48: { // ec_BaseAddress (A23–A16) + const auto address = uint32_t(cycle.value8_high()) << 16; + printf("Mapping fast RAM to %08x", address); + set_region(address, uint32_t(address + fast_ram_.size()), fast_ram_.data(), PermitRead | PermitWrite); + fast_autoconf_visible_ = false; + } break; + } + } + + return true; + } + private: + std::vector fast_ram_{}; + uint8_t fast_ram_size_ = 0; + + bool fast_autoconf_visible_ = true; bool overlay_ = false; void set_region(uint32_t start, uint32_t end, uint8_t *base, unsigned int read_write_mask) {