// // TestRunner68000.hpp // Clock Signal // // Created by Thomas Harte on 28/06/2019. // Copyright © 2019 Thomas Harte. All rights reserved. // #ifndef TestRunner68000_h #define TestRunner68000_h #include #include #include #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 &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 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()]; } HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int) { const uint32_t word_address = cycle.word_address(); duration_ += cycle.length; using Microcycle = CPU::MC68000::Microcycle; if(cycle.data_select_active()) { if(cycle.operation & Microcycle::InterruptAcknowledge) { cycle.value->b = 10; } else { switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { default: break; case Microcycle::SelectWord | Microcycle::Read: cycle.value->w = ram_[word_address % ram_.size()]; break; case Microcycle::SelectByte | Microcycle::Read: cycle.value->b = ram_[word_address % ram_.size()] >> cycle.byte_shift(); break; case Microcycle::SelectWord: ram_[word_address % ram_.size()] = cycle.value->w; break; case Microcycle::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 m68000_; std::array ram_{}; int instructions_remaining_; HalfCycles duration_; }; #endif /* TestRunner68000_h */