diff --git a/Machines/AtariST/AtariST.cpp b/Machines/AtariST/AtariST.cpp index eff85308c..750ad2972 100644 --- a/Machines/AtariST/AtariST.cpp +++ b/Machines/AtariST/AtariST.cpp @@ -15,6 +15,9 @@ #include "Video.hpp" #include "../../ClockReceiver/JustInTime.hpp" +#include "../Utility/MemoryPacker.hpp" +#include "../Utility/MemoryFuzzer.hpp" + namespace Atari { namespace ST { @@ -31,7 +34,8 @@ class ConcreteMachine: mc68000_(*this) { set_clock_rate(CLOCK_RATE); - ram_.resize(512 * 1024); + ram_.resize(512 * 512); + Memory::Fuzz(ram_); std::vector rom_descriptions = { {"AtariST", "the TOS ROM", "tos100.img", 192*1024, 0x1a586c64} @@ -40,7 +44,7 @@ class ConcreteMachine: if(!roms[0]) { throw ROMMachine::Error::MissingROMs; } - rom_ = *roms[0]; + Memory::PackBigEndian16(*roms[0], rom_); } // MARK: CRTMachine::Machine @@ -57,7 +61,54 @@ class ConcreteMachine: } // MARK: MC68000::BusHandler + using Microcycle = CPU::MC68000::Microcycle; HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { + // Advance time. + video_ += cycle.length; + + // A null cycle leaves nothing else to do. + if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0); + + auto address = cycle.word_address(); + uint16_t *memory; + if(address < 4) { + memory = rom_.data(); + } else if(address < 0x700000) { + memory = ram_.data(); + address &= ram_.size() - 1; + // TODO: align with the next access window. + } else if(address < 0x780000) { // TOS 2.0+ address + memory = rom_.data(); + address &= rom_.size() - 1; + } else if(address >= 0x7e0000 && address < 0x7f8000) { // TOS 1.0 address + memory = rom_.data(); + address &= rom_.size() - 1; + } else { + assert(false); + } + + // If control has fallen through to here, the access is either a read from ROM, or a read or write to RAM. + switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { + default: + break; + + case Microcycle::SelectWord | Microcycle::Read: + cycle.value->full = memory[address]; + break; + case Microcycle::SelectByte | Microcycle::Read: + cycle.value->halves.low = uint8_t(memory[address] >> cycle.byte_shift()); + break; + case Microcycle::SelectWord: + memory[address] = cycle.value->full; + break; + case Microcycle::SelectByte: + memory[address] = uint16_t( + (cycle.value->halves.low << cycle.byte_shift()) | + (memory[address] & cycle.untouched_byte_mask()) + ); + break; + } + return HalfCycles(0); } @@ -65,8 +116,8 @@ class ConcreteMachine: CPU::MC68000::Processor mc68000_; JustInTimeActor video_; - std::vector ram_; - std::vector rom_; + std::vector ram_; + std::vector rom_; }; diff --git a/Machines/Utility/MemoryPacker.cpp b/Machines/Utility/MemoryPacker.cpp index 9630af259..101a68b5c 100644 --- a/Machines/Utility/MemoryPacker.cpp +++ b/Machines/Utility/MemoryPacker.cpp @@ -13,3 +13,8 @@ void Memory::PackBigEndian16(const std::vector &source, uint16_t *targe target[c >> 1] = uint16_t(source[c] << 8) | uint16_t(source[c+1]); } } + +void Memory::PackBigEndian16(const std::vector &source, std::vector &target) { + target.resize(source.size() >> 1); + PackBigEndian16(source, target.data()); +} diff --git a/Machines/Utility/MemoryPacker.hpp b/Machines/Utility/MemoryPacker.hpp index 145191829..dbfd624a0 100644 --- a/Machines/Utility/MemoryPacker.hpp +++ b/Machines/Utility/MemoryPacker.hpp @@ -20,5 +20,12 @@ namespace Memory { */ void PackBigEndian16(const std::vector &source, uint16_t *target); +/*! + Copies the bytes from @c source into @c target, interpreting them + as big-endian 16-bit data. @c target will be resized to the proper size + exactly to contain the contents of @c source. +*/ +void PackBigEndian16(const std::vector &source, std::vector &target); + } #endif /* MemoryPacker_hpp */