1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-29 00:29:34 +00:00

Implements enough Copper to get a first store.

This commit is contained in:
Thomas Harte 2021-07-27 19:06:16 -04:00
parent 3544746934
commit 29cd8504ca
2 changed files with 125 additions and 17 deletions

View File

@ -39,6 +39,7 @@ enum InterruptFlag: uint16_t {
Chipset::Chipset(uint16_t *ram, size_t size) :
blitter_(ram, size),
copper_(*this, ram, size),
crt_(908, 4, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4) {
}
@ -50,12 +51,73 @@ Chipset::Changes Chipset::run_until_cpu_slot() {
return run<true>();
}
bool Chipset::Copper::advance(uint16_t position) {
(void)position;
switch(state_) {
default: return false;
case State::FetchFirstWord:
instruction[0] = ram_[address & ram_mask_];
++address;
state_ = State::FetchSecondWord;
break;
case State::FetchSecondWord:
instruction[1] = ram_[address & ram_mask_];
++address;
if(!(instruction[0] & 1)) {
// This is a move.
// At least for now, construct a 68000-esque Microcycle.
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);
state_ = State::FetchFirstWord;
} else {
// TODO: ... decode and handle WAITs and SKIPs.
state_ = State::Stopped;
}
break;
}
return true;
}
template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
// TODO: actual CPU scheduling.
if constexpr (stop_if_cpu) {
return true;
}
if constexpr (cycle & 1) {
// Odd slot priority is:
//
// 1. Copper, if interested.
// 2. Bitplane.
// 3. Blitter.
// 4. CPU.
if((dma_control_ & 0x280) == 0x280) {
if(copper_.advance(uint16_t(((y_ & 0xff) << 8) | cycle))) {
return false;
}
} else {
copper_.stop();
}
} else {
// Even slot use/priority:
//
// 1. Bitplane fetches.
// 2. Disk, then audio, then sprites depending on region.
// 3. Blitter.
// 4. CPU.
}
return false;
}
@ -80,9 +142,14 @@ template <bool stop_on_cpu> Chipset::Changes Chipset::run(HalfCycles length) {
if((line_cycle_ >> 2) == final_slot) {
// Not enough pixels left to fill any whole slots, just stop.
line_cycle_ += line_pixels;
break;
}
// TODO: advance to the next window boundary.
// line_pixels -= (line_pixels & 3);
// line_cycle_ += (4 - ((line_cycle_ & 3) + 1)) & 3;
#define C(x) \
case x: \
if constexpr(stop_on_cpu) { if(perform_cycle<x, stop_on_cpu>()) break; } else { perform_cycle<x, stop_on_cpu>(); } \
@ -205,7 +272,7 @@ template <bool stop_on_cpu> Chipset::Changes Chipset::run(HalfCycles length) {
y_ = 0;
// TODO: the manual is vague on when this happens. Try to find out.
copper_address_ = copper_addresses_[0];
copper_.reload(0);
}
}
}
@ -437,31 +504,32 @@ void Chipset::perform(const CPU::MC68000::Microcycle &cycle) {
// Copper.
case Write(0x02e):
LOG("TODO: coprocessor control " << PADHEX(4) << cycle.value16());
LOG("Coprocessor control " << PADHEX(4) << cycle.value16());
copper_.set_control(cycle.value16());
break;
case Write(0x080):
LOG("TODO: coprocessor first location register high " << PADHEX(4) << cycle.value16());
copper_addresses_[0] = (copper_addresses_[0] & 0x0000'ffff) | uint32_t(cycle.value16() << 16);
LOG("Coprocessor first location register high " << PADHEX(4) << cycle.value16());
copper_.set_address<0, 16>(cycle.value16());
break;
case Write(0x082):
LOG("TODO: coprocessor first location register low " << PADHEX(4) << cycle.value16());
copper_addresses_[0] = (copper_addresses_[0] & 0xffff'0000) | uint32_t(cycle.value16() << 0);
LOG("Coprocessor first location register low " << PADHEX(4) << cycle.value16());
copper_.set_address<0, 0>(cycle.value16());
break;
case Write(0x084):
LOG("TODO: coprocessor second location register high " << PADHEX(4) << cycle.value16());
copper_addresses_[1] = (copper_addresses_[1] & 0x0000'ffff) | uint32_t(cycle.value16() << 16);
LOG("Coprocessor second location register high " << PADHEX(4) << cycle.value16());
copper_.set_address<1, 16>(cycle.value16());
break;
case Write(0x086):
LOG("TODO: coprocessor second location register low " << PADHEX(4) << cycle.value16());
copper_addresses_[1] = (copper_addresses_[1] & 0xffff'0000) | uint32_t(cycle.value16() << 0);
LOG("Coprocessor second location register low " << PADHEX(4) << cycle.value16());
copper_.set_address<1, 0>(cycle.value16());
break;
case Write(0x088): case Read(0x088):
LOG("TODO: coprocessor restart at first location");
copper_address_ = copper_addresses_[0];
LOG("Coprocessor restart at first location");
copper_.reload(0);
break;
case Write(0x08a): case Read(0x08a):
LOG("TODO: coprocessor restart at second location");
copper_address_ = copper_addresses_[1];
LOG("Coprocessor restart at second location");
copper_.reload(1);
break;
case Write(0x08c):
LOG("TODO: coprocessor instruction fetch identity " << PADHEX(4) << cycle.value16());

View File

@ -48,7 +48,6 @@ class Chipset {
return interrupt_level_;
}
// The standard CRT set.
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
Outputs::Display::ScanStatus get_scaled_scan_status() const;
@ -96,8 +95,49 @@ class Chipset {
// MARK: - Copper.
uint32_t copper_address_ = 0;
uint32_t copper_addresses_[2]{};
class Copper {
public:
Copper(Chipset &chipset, uint16_t *ram, size_t size) : chipset_(chipset), ram_(ram), ram_mask_(uint32_t(size - 1)) {}
/// Offers a DMA slot to the Copper, specifying the current beam position.
///
/// @returns @c true if the slot was used; @c false otherwise.
bool advance(uint16_t position);
void reload(int id) {
address = addresses[id] >> 1;
state_ = State::FetchFirstWord;
}
template <int id, int shift> void set_address(uint16_t value) {
addresses[id] = (addresses[id] & (0xffff'0000 >> shift)) | uint32_t(value << shift);
}
void set_control(uint16_t c) {
control_ = c;
}
void stop() {
state_ = State::Stopped;
}
private:
Chipset &chipset_;
uint32_t address = 0;
uint32_t addresses[2]{};
uint16_t control_ = 0;
enum class State {
FetchFirstWord, FetchSecondWord, Waiting, Stopped,
} state_ = State::Stopped;
bool skip_next_ = false;
uint16_t instruction[2]{};
uint16_t *ram_ = nullptr;
uint32_t ram_mask_ = 0;
} copper_;
friend Copper;
// MARK: - Pixel output.