diff --git a/Analyser/Static/Amiga/Target.hpp b/Analyser/Static/Amiga/Target.hpp index 5987e290d..a41d37dd9 100644 --- a/Analyser/Static/Amiga/Target.hpp +++ b/Analyser/Static/Amiga/Target.hpp @@ -17,7 +17,28 @@ namespace Static { namespace Amiga { struct Target: public Analyser::Static::Target, public Reflection::StructImpl { - Target() : Analyser::Static::Target(Machine::Amiga) {} + ReflectableEnum(ChipRAM, + FiveHundredAndTwelveKilobytes, + OneMegabyte, + TwoMegabytes); + ReflectableEnum(FastRAM, + None, + OneMegabyte, + TwoMegabytes, + FourMegabytes, + EightMegabytes); + + ChipRAM chip_ram = ChipRAM::FiveHundredAndTwelveKilobytes; + FastRAM fast_ram = FastRAM::EightMegabytes; + + Target() : Analyser::Static::Target(Machine::Amiga) { + if(needs_declare()) { + DeclareField(fast_ram); + DeclareField(chip_ram); + AnnounceEnum(FastRAM); + AnnounceEnum(ChipRAM); + } + } }; } diff --git a/Machines/Amiga/Amiga.cpp b/Machines/Amiga/Amiga.cpp index e41c4a11d..1d60034cf 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.chip_ram, 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..9e6c8fdf1 100644 --- a/Machines/Amiga/MemoryMap.hpp +++ b/Machines/Amiga/MemoryMap.hpp @@ -9,6 +9,12 @@ #ifndef MemoryMap_hpp #define MemoryMap_hpp +#include "../../Analyser/Static/Amiga/Target.hpp" + +#include +#include +#include + namespace Amiga { class MemoryMap { @@ -18,16 +24,17 @@ class MemoryMap { static constexpr auto PermitReadWrite = PermitRead | PermitWrite; public: - // TODO: decide what of the below I want to be dynamic. - std::array chip_ram{}; std::array kickstart{0xff}; + std::vector 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; + using ChipRAM = Analyser::Static::Amiga::Target::ChipRAM; + MemoryMap(ChipRAM chip_ram_size, FastRAM fast_ram_size) { // Address spaces that matter: // // 00'0000 – 08'0000: chip RAM. [or overlayed KickStart] @@ -45,6 +52,42 @@ 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(chip_ram_size) { + default: + case ChipRAM::FiveHundredAndTwelveKilobytes: + chip_ram.resize(512 * 1024); + break; + case ChipRAM::OneMegabyte: + chip_ram.resize(1 * 1024 * 1024); + break; + case ChipRAM::TwoMegabytes: + chip_ram.resize(2 * 1024 * 1024); + break; + } + + 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 +107,75 @@ 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; + 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) { diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h index 3faae40c7..970dbf641 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h @@ -124,7 +124,7 @@ typedef int Kilobytes; - (nullable instancetype)initWithFileAtURL:(NSURL *)url; -- (instancetype)initWithAmigaModel:(CSMachineAmigaModel)model; +- (instancetype)initWithAmigaModel:(CSMachineAmigaModel)model chipMemorySize:(Kilobytes)chipMemorySize fastMemorySize:(Kilobytes)fastMemorySize; - (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model; - (instancetype)initWithAppleIIModel:(CSMachineAppleIIModel)model diskController:(CSMachineAppleIIDiskController)diskController; - (instancetype)initWithAppleIIgsModel:(CSMachineAppleIIgsModel)model memorySize:(Kilobytes)memorySize; diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm index 8d6d27e00..5da15a508 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm @@ -50,11 +50,28 @@ // MARK: - Machine-based Initialisers -- (instancetype)initWithAmigaModel:(CSMachineAmigaModel)model { +- (instancetype)initWithAmigaModel:(CSMachineAmigaModel)model chipMemorySize:(Kilobytes)chipMemorySize fastMemorySize:(Kilobytes)fastMemorySize { self = [super init]; if(self) { using Target = Analyser::Static::Amiga::Target; auto target = std::make_unique(); + + switch(chipMemorySize) { + default: return nil; + case 512: target->chip_ram = Target::ChipRAM::FiveHundredAndTwelveKilobytes; break; + case 1024: target->chip_ram = Target::ChipRAM::OneMegabyte; break; + case 2048: target->chip_ram = Target::ChipRAM::TwoMegabytes; break; + } + + switch(fastMemorySize) { + default: return nil; + case 0: target->fast_ram = Target::FastRAM::None; break; + case 1024: target->fast_ram = Target::FastRAM::OneMegabyte; break; + case 2048: target->fast_ram = Target::FastRAM::TwoMegabytes; break; + case 4096: target->fast_ram = Target::FastRAM::FourMegabytes; break; + case 8192: target->fast_ram = Target::FastRAM::EightMegabytes; break; + } + _targets.push_back(std::move(target)); } return self; diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib index 135fb94df..51d26aa1c 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib +++ b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib @@ -1,8 +1,8 @@ - + - + @@ -67,29 +67,75 @@ Gw - - - - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + - + - + @@ -103,7 +149,7 @@ Gw - + @@ -627,11 +673,11 @@ Gw - + - + @@ -647,7 +693,7 @@ Gw - + @@ -661,7 +707,7 @@ Gw - + @@ -669,7 +715,7 @@ Gw - + @@ -677,7 +723,7 @@ Gw