1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00
CLK/Machines/Amiga/Copper.cpp
Thomas Harte 47f36f08fb Switches to a synchronous audio state machine; renames advance -> advance_dma.
I can worry about how to just-in-time things once I better understand the hardware in general.
2021-11-13 15:53:41 -05:00

93 lines
2.2 KiB
C++

//
// Copper.cpp
// Clock Signal
//
// Created by Thomas Harte on 16/09/2021.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#ifndef NDEBUG
#define NDEBUG
#endif
#define LOG_PREFIX "[Copper] "
#include "../../Outputs/Log.hpp"
#include "Chipset.hpp"
#include "Copper.hpp"
using namespace Amiga;
bool Copper::advance_dma(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;
}