// // Copper.cpp // Clock Signal // // Created by Thomas Harte on 16/09/2021. // Copyright © 2021 Thomas Harte. All rights reserved. // #include #define NDEBUG #define LOG_PREFIX "[Copper] " #include "../../Outputs/Log.hpp" #include "Chipset.hpp" #include "Copper.hpp" using namespace Amiga; bool Copper::advance(uint16_t position) { switch(state_) { default: return false; case State::Waiting: // TODO: blitter-finished bit. if((position & position_mask_) >= instruction_[0]) { state_ = State::FetchFirstWord; } return false; case State::FetchFirstWord: instruction_[0] = ram_[address_ & ram_mask_]; ++address_; state_ = State::FetchSecondWord; break; case State::FetchSecondWord: { const bool should_skip_move = skip_next_; skip_next_ = false; instruction_[1] = ram_[address_ & ram_mask_]; ++address_; if(!(instruction_[0] & 1)) { // A MOVE. if(!should_skip_move) { // Stop if this move would be a privilege violation. instruction_[0] &= 0x1fe; if((instruction_[0] < 0x10) || (instruction_[0] < 0x20 && !(control_&1))) { LOG("Invalid MOVE to " << PADHEX(4) << instruction_[0] << "; stopping"); state_ = State::Stopped; break; } // Construct a 68000-esque Microcycle in order to be able to perform the access. CPU::MC68000::Microcycle cycle; cycle.operation = CPU::MC68000::Microcycle::SelectWord; uint32_t full_address = instruction_[0]; CPU::RegisterPair16 data = instruction_[1]; cycle.address = &full_address; cycle.value = &data; chipset_.perform(cycle); } // Roll onto the next command. state_ = State::FetchFirstWord; break; } // Prepare for a position comparison. position_mask_ = 0x8001 | (instruction_[1] & 0x7ffe); instruction_[0] &= position_mask_; if(!(instruction_[1] & 1)) { // A WAIT. Just note that this is now waiting; the proper test // will be applied from the next potential `advance` onwards. state_ = State::Waiting; break; } // Neither a WAIT nor a MOVE => a SKIP. // TODO: blitter-finished bit. skip_next_ = (position & position_mask_) >= instruction_[0]; state_ = State::FetchFirstWord; } break; } return true; }