1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00
CLK/OSBindings/Mac/Clock SignalTests/TestRunner68000.hpp
2024-01-16 23:34:46 -05:00

137 lines
3.5 KiB
C++

//
// TestRunner68000.hpp
// Clock Signal
//
// Created by Thomas Harte on 28/06/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#pragma once
#include <array>
#include <functional>
#include <vector>
#include "../../../Processors/68000/68000.hpp"
using namespace InstructionSet::M68k;
/*!
Provides a 68000 with 64kb of RAM in its low address space;
/RESET will put the supervisor stack pointer at 0xFFFF and
begin execution at 0x0400.
*/
class RAM68000: public CPU::MC68000::BusHandler {
public:
RAM68000() : m68000_(*this) {}
uint32_t initial_pc() const {
return 0x1000;
}
void set_program(
const std::vector<uint16_t> &program,
uint32_t stack_pointer = 0x206
) {
memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t));
// Ensure the condition codes start unset and set the initial program counter
// and supervisor stack pointer, as well as starting in supervisor mode.
auto registers = m68000_.get_state().registers;
registers.status = 0x2700;
registers.program_counter = initial_pc();
registers.supervisor_stack_pointer = stack_pointer;
m68000_.decode_from_state(registers);
}
void set_registers(std::function<void(InstructionSet::M68k::RegisterSet &)> func) {
auto state = m68000_.get_state();
func(state.registers);
m68000_.set_state(state);
}
void will_perform(uint32_t, uint16_t) {
--instructions_remaining_;
if(instructions_remaining_ < 0) {
throw StopException();
}
}
void run_for_instructions(int count) {
duration_ = HalfCycles(0);
instructions_remaining_ = count;
if(!instructions_remaining_) return;
try {
while(true) {
run_for(HalfCycles(2000));
}
} catch (const StopException &) {}
}
void run_for(HalfCycles cycles) {
m68000_.run_for(cycles);
}
uint16_t *ram_at(uint32_t address) {
return &ram_[(address >> 1) % ram_.size()];
}
template <typename Microcycle> HalfCycles perform_bus_operation(const Microcycle &cycle, int) {
const uint32_t word_address = cycle.word_address();
duration_ += cycle.length;
if(cycle.data_select_active()) {
if(cycle.operation & CPU::MC68000::Operation::InterruptAcknowledge) {
cycle.value->b = 10;
} else {
switch(cycle.operation & (CPU::MC68000::Operation::SelectWord | CPU::MC68000::Operation::SelectByte | CPU::MC68000::Operation::Read)) {
default: break;
case CPU::MC68000::Operation::SelectWord | CPU::MC68000::Operation::Read:
cycle.value->w = ram_[word_address % ram_.size()];
break;
case CPU::MC68000::Operation::SelectByte | CPU::MC68000::Operation::Read:
cycle.value->b = ram_[word_address % ram_.size()] >> cycle.byte_shift();
break;
case CPU::MC68000::Operation::SelectWord:
ram_[word_address % ram_.size()] = cycle.value->w;
break;
case CPU::MC68000::Operation::SelectByte:
ram_[word_address % ram_.size()] = uint16_t(
(cycle.value->b << cycle.byte_shift()) |
(ram_[word_address % ram_.size()] & cycle.untouched_byte_mask())
);
break;
}
}
}
return HalfCycles(0);
}
CPU::MC68000::State get_processor_state() {
return m68000_.get_state();
}
auto &processor() {
return m68000_;
}
int get_cycle_count() {
return int(duration_.as_integral()) >> 1;
}
void reset_cycle_count() {
duration_ = HalfCycles(0);
}
private:
struct StopException {};
CPU::MC68000::Processor<RAM68000, true, true, true> m68000_;
std::array<uint16_t, 256*1024> ram_{};
int instructions_remaining_;
HalfCycles duration_;
};