1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-08-16 00:29:01 +00:00
CLK/Machines/AtariST/AtariST.cpp

134 lines
3.4 KiB
C++
Raw Normal View History

//
// AtariST.cpp
// Clock Signal
//
// Created by Thomas Harte on 03/10/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#include "AtariST.hpp"
#include "../CRTMachine.hpp"
#include "../../Processors/68000/68000.hpp"
#include "Video.hpp"
#include "../../ClockReceiver/JustInTime.hpp"
2019-10-05 02:38:46 +00:00
#include "../Utility/MemoryPacker.hpp"
#include "../Utility/MemoryFuzzer.hpp"
namespace Atari {
namespace ST {
const int CLOCK_RATE = 8000000;
using Target = Analyser::Static::Target;
class ConcreteMachine:
public Atari::ST::Machine,
public CPU::MC68000::BusHandler,
public CRTMachine::Machine {
public:
ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
mc68000_(*this) {
set_clock_rate(CLOCK_RATE);
2019-10-05 02:38:46 +00:00
ram_.resize(512 * 512);
Memory::Fuzz(ram_);
std::vector<ROMMachine::ROM> rom_descriptions = {
{"AtariST", "the TOS ROM", "tos100.img", 192*1024, 0x1a586c64}
};
const auto roms = rom_fetcher(rom_descriptions);
if(!roms[0]) {
throw ROMMachine::Error::MissingROMs;
}
2019-10-05 02:38:46 +00:00
Memory::PackBigEndian16(*roms[0], rom_);
}
// MARK: CRTMachine::Machine
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final {
video_->set_scan_target(scan_target);
}
Outputs::Speaker::Speaker *get_speaker() final {
return nullptr;
}
void run_for(const Cycles cycles) final {
mc68000_.run_for(cycles);
}
// MARK: MC68000::BusHandler
2019-10-05 02:38:46 +00:00
using Microcycle = CPU::MC68000::Microcycle;
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
2019-10-05 02:38:46 +00:00
// 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);
}
private:
CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
JustInTimeActor<Video, HalfCycles> video_;
2019-10-05 02:38:46 +00:00
std::vector<uint16_t> ram_;
std::vector<uint16_t> rom_;
};
}
}
using namespace Atari::ST;
Machine *Machine::AtariST(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
return new ConcreteMachine(*target, rom_fetcher);
}
Machine::~Machine() {}