mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Adds support for the Blitter-busy flag to WAIT and SKIP.
This commit is contained in:
parent
33bfa1b81c
commit
dac40630fd
@ -434,7 +434,7 @@ template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
|
|||||||
//
|
//
|
||||||
// The Blitter and CPU are dealt with outside of the odd/even test.
|
// The Blitter and CPU are dealt with outside of the odd/even test.
|
||||||
if((dma_control_ & CopperFlag) == CopperFlag) {
|
if((dma_control_ & CopperFlag) == CopperFlag) {
|
||||||
if(copper_.advance_dma(uint16_t(((y_ & 0xff) << 8) | (cycle & 0xfe)))) {
|
if(copper_.advance_dma(uint16_t(((y_ & 0xff) << 8) | (cycle & 0xfe)), blitter_.get_status())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,13 +18,69 @@
|
|||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
bool Copper::advance_dma(uint16_t position) {
|
namespace {
|
||||||
|
|
||||||
|
bool satisfies_raster(uint16_t position, uint16_t blitter_status, uint16_t *instruction) {
|
||||||
|
const uint16_t mask = 0x8000 | (instruction[1] & 0x7ffe);
|
||||||
|
return
|
||||||
|
(position & mask) >= (instruction[0] & mask)
|
||||||
|
&& (!(blitter_status & 0x4000) || (instruction[1] & 0x8000));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Quick notes on the Copper:
|
||||||
|
//
|
||||||
|
// There are three instructions: move, wait and skip.
|
||||||
|
//
|
||||||
|
// Move writes a value to one of the Chipset registers; it is encoded as:
|
||||||
|
//
|
||||||
|
// First word:
|
||||||
|
// b0: 0
|
||||||
|
// b1–b8: register address
|
||||||
|
// b9+: unused ("should be set to 0")
|
||||||
|
//
|
||||||
|
// Second word:
|
||||||
|
// b0–b15: value to move.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Wait waits until the raster gets to at least a certain position, and
|
||||||
|
// optionally until the Blitter has finished. It is encoded as:
|
||||||
|
//
|
||||||
|
// First word:
|
||||||
|
// b0: 1
|
||||||
|
// b1–b7: horizontal beam position
|
||||||
|
// b8+: vertical beam position
|
||||||
|
//
|
||||||
|
// Second word:
|
||||||
|
// b0: 0
|
||||||
|
// b1–b7: horizontal beam comparison mask
|
||||||
|
// b8–b14: vertical beam comparison mask
|
||||||
|
// b15: 1 => don't also wait for the Blitter to be finished; 0 => wait.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Skip skips the next instruction if the raster has already reached a certain
|
||||||
|
// position, and optionally only if the Blitter has finished, and only if the
|
||||||
|
// next instruction is a move.
|
||||||
|
//
|
||||||
|
// First word:
|
||||||
|
// b0: 1
|
||||||
|
// b1–b7: horizontal beam position
|
||||||
|
// b8+: vertical beam position
|
||||||
|
//
|
||||||
|
// Second word:
|
||||||
|
// b0: 1
|
||||||
|
// b1–b7: horizontal beam comparison mask
|
||||||
|
// b8–b14: vertical beam comparison mask
|
||||||
|
// b15: 1 => don't also wait for the Blitter to be finished; 0 => wait.
|
||||||
|
//
|
||||||
|
bool Copper::advance_dma(uint16_t position, uint16_t blitter_status) {
|
||||||
switch(state_) {
|
switch(state_) {
|
||||||
default: return false;
|
default: return false;
|
||||||
|
|
||||||
case State::Waiting:
|
case State::Waiting:
|
||||||
// TODO: blitter-finished bit.
|
if(satisfies_raster(position, blitter_status, instruction_)) {
|
||||||
if((position & position_mask_) >= instruction_[0]) {
|
|
||||||
LOG("Unblocked waiting for " << PADHEX(4) << instruction_[0] << " at " << position);
|
LOG("Unblocked waiting for " << PADHEX(4) << instruction_[0] << " at " << position);
|
||||||
state_ = State::FetchFirstWord;
|
state_ = State::FetchFirstWord;
|
||||||
}
|
}
|
||||||
@ -37,15 +93,16 @@ bool Copper::advance_dma(uint16_t position) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case State::FetchSecondWord: {
|
case State::FetchSecondWord: {
|
||||||
|
// Get and reset the should-skip-next flag.
|
||||||
const bool should_skip_move = skip_next_;
|
const bool should_skip_move = skip_next_;
|
||||||
skip_next_ = false;
|
skip_next_ = false;
|
||||||
|
|
||||||
|
// Read in the second instruction word.
|
||||||
instruction_[1] = ram_[address_ & ram_mask_];
|
instruction_[1] = ram_[address_ & ram_mask_];
|
||||||
++address_;
|
++address_;
|
||||||
|
|
||||||
|
// Check for a MOVE.
|
||||||
if(!(instruction_[0] & 1)) {
|
if(!(instruction_[0] & 1)) {
|
||||||
// A MOVE.
|
|
||||||
|
|
||||||
if(!should_skip_move) {
|
if(!should_skip_move) {
|
||||||
// Stop if this move would be a privilege violation.
|
// Stop if this move would be a privilege violation.
|
||||||
instruction_[0] &= 0x1fe;
|
instruction_[0] &= 0x1fe;
|
||||||
@ -70,21 +127,18 @@ bool Copper::advance_dma(uint16_t position) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for a position comparison.
|
// Got to here => this is a WAIT or a SKIP.
|
||||||
position_mask_ = 0x8001 | (instruction_[1] & 0x7ffe);
|
|
||||||
instruction_[0] &= position_mask_;
|
|
||||||
|
|
||||||
if(!(instruction_[1] & 1)) {
|
if(!(instruction_[1] & 1)) {
|
||||||
// A WAIT. Just note that this is now waiting; the proper test
|
// A WAIT. Just note that this is now waiting; the proper test
|
||||||
// will be applied from the next potential `advance` onwards.
|
// will be applied from the next potential `advance_dma` onwards.
|
||||||
state_ = State::Waiting;
|
state_ = State::Waiting;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neither a WAIT nor a MOVE => a SKIP.
|
// Neither a WAIT nor a MOVE => a SKIP.
|
||||||
|
|
||||||
// TODO: blitter-finished bit.
|
skip_next_ = satisfies_raster(position, blitter_status, instruction_);
|
||||||
skip_next_ = (position & position_mask_) >= instruction_[0];
|
|
||||||
state_ = State::FetchFirstWord;
|
state_ = State::FetchFirstWord;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ class Copper: public DMADevice<2> {
|
|||||||
public:
|
public:
|
||||||
using DMADevice<2>::DMADevice;
|
using DMADevice<2>::DMADevice;
|
||||||
|
|
||||||
/// Offers a DMA slot to the Copper, specifying the current beam position.
|
/// Offers a DMA slot to the Copper, specifying the current beam position and Blitter status.
|
||||||
///
|
///
|
||||||
/// @returns @c true if the slot was used; @c false otherwise.
|
/// @returns @c true if the slot was used; @c false otherwise.
|
||||||
bool advance_dma(uint16_t position);
|
bool advance_dma(uint16_t position, uint16_t blitter_status);
|
||||||
|
|
||||||
/// Forces a reload of address @c id (i.e. 0 or 1) and restarts the Copper.
|
/// Forces a reload of address @c id (i.e. 0 or 1) and restarts the Copper.
|
||||||
template <int id> void reload() {
|
template <int id> void reload() {
|
||||||
@ -47,7 +47,6 @@ class Copper: public DMADevice<2> {
|
|||||||
} state_ = State::Stopped;
|
} state_ = State::Stopped;
|
||||||
bool skip_next_ = false;
|
bool skip_next_ = false;
|
||||||
uint16_t instruction_[2]{};
|
uint16_t instruction_[2]{};
|
||||||
uint16_t position_mask_ = 0xffff;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user