diff --git a/Machines/Amiga/Blitter.cpp b/Machines/Amiga/Blitter.cpp index e6e788c51..bc7b34220 100644 --- a/Machines/Amiga/Blitter.cpp +++ b/Machines/Amiga/Blitter.cpp @@ -76,13 +76,6 @@ void Blitter::set_horizontal_size([[maybe_unused]] uint16_t value) { LOG("Set horizontal size " << PADHEX(4) << value); } -void Blitter::set_modulo(int channel, uint16_t value) { - LOG("Set modulo size " << channel << " to " << PADHEX(4) << value); - - // Convert by sign extension. - modulos_[channel] = uint32_t(int16_t(value) >> 1); -} - void Blitter::set_data(int channel, uint16_t value) { LOG("Set data " << channel << " to " << PADHEX(4) << value); diff --git a/Machines/Amiga/Blitter.hpp b/Machines/Amiga/Blitter.hpp index 3d4b17a2e..2ece312db 100644 --- a/Machines/Amiga/Blitter.hpp +++ b/Machines/Amiga/Blitter.hpp @@ -17,7 +17,7 @@ namespace Amiga { -class Blitter: public DMADevice<4> { +class Blitter: public DMADevice<4, 4> { public: using DMADevice::DMADevice; @@ -33,7 +33,6 @@ class Blitter: public DMADevice<4> { void set_minterms(uint16_t value); void set_vertical_size(uint16_t value); void set_horizontal_size(uint16_t value); - void set_modulo(int channel, uint16_t value); void set_data(int channel, uint16_t value); uint16_t get_status(); @@ -60,7 +59,6 @@ class Blitter: public DMADevice<4> { uint8_t minterms_ = 0; uint32_t a32_ = 0, b32_ = 0; uint16_t a_data_ = 0, b_data_ = 0, c_data_ = 0; - uint32_t modulos_[4]{}; bool not_zero_flag_ = false; }; diff --git a/Machines/Amiga/Chipset.cpp b/Machines/Amiga/Chipset.cpp index 7d2c1f63a..8fef0a2f3 100644 --- a/Machines/Amiga/Chipset.cpp +++ b/Machines/Amiga/Chipset.cpp @@ -96,6 +96,7 @@ Chipset::Changes Chipset::run_until_cpu_slot() { void Chipset::set_cia_interrupts(bool cia_a_interrupt, bool cia_b_interrupt) { // TODO: are these really latched, or are they active live? + // If latched, is it only on a leading edge? // interrupt_requests_ &= ~InterruptMask::value; interrupt_requests_ |= (cia_a_interrupt ? InterruptMask::value : 0) | @@ -462,8 +463,6 @@ template Chipset::Changes Chipset::run(HalfCycles length) { // } if(did_fetch_) { - // TODO: find out when modulos are actually applied, since - // they're dynamically programmable. bitplanes_.do_end_of_line(); previous_bitplanes_.clear(); } @@ -762,8 +761,10 @@ void Chipset::perform(const CPU::MC68000::Microcycle &cycle) { break; case Write(0x108): + bitplanes_.set_modulo<0>(cycle.value16()); + break; case Write(0x10a): - LOG("TODO: Bitplane modulo; " << PADHEX(4) << cycle.value16() << " to " << *cycle.address); + bitplanes_.set_modulo<1>(cycle.value16()); break; case Write(0x110): @@ -804,10 +805,10 @@ void Chipset::perform(const CPU::MC68000::Microcycle &cycle) { case Write(0x05c): blitter_.set_vertical_size(cycle.value16()); break; case Write(0x05e): blitter_.set_horizontal_size(cycle.value16()); break; - case Write(0x060): blitter_.set_modulo(2, cycle.value16()); break; - case Write(0x062): blitter_.set_modulo(1, cycle.value16()); break; - case Write(0x064): blitter_.set_modulo(0, cycle.value16()); break; - case Write(0x066): blitter_.set_modulo(3, cycle.value16()); break; + case Write(0x060): blitter_.set_modulo<2>(cycle.value16()); break; + case Write(0x062): blitter_.set_modulo<1>(cycle.value16()); break; + case Write(0x064): blitter_.set_modulo<0>(cycle.value16()); break; + case Write(0x066): blitter_.set_modulo<3>(cycle.value16()); break; case Write(0x070): blitter_.set_data(2, cycle.value16()); break; case Write(0x072): blitter_.set_data(1, cycle.value16()); break; @@ -955,7 +956,14 @@ bool Chipset::Bitplanes::advance(int cycle) { } void Chipset::Bitplanes::do_end_of_line() { - // TODO: apply modulos. + // Apply modulos here. Posssibly correct? + pointer_[0] += modulos_[1]; + pointer_[2] += modulos_[1]; + pointer_[4] += modulos_[1]; + + pointer_[1] += modulos_[0]; + pointer_[3] += modulos_[0]; + pointer_[5] += modulos_[0]; } void Chipset::Bitplanes::set_control(uint16_t control) { diff --git a/Machines/Amiga/Chipset.hpp b/Machines/Amiga/Chipset.hpp index 32e2327d3..637dabd83 100644 --- a/Machines/Amiga/Chipset.hpp +++ b/Machines/Amiga/Chipset.hpp @@ -228,7 +228,7 @@ class Chipset: private ClockingHint::Observer { } }; - class Bitplanes: public DMADevice<6> { + class Bitplanes: public DMADevice<6, 2> { public: using DMADevice::DMADevice; diff --git a/Machines/Amiga/DMADevice.hpp b/Machines/Amiga/DMADevice.hpp index 6aa7fef82..99d0c7377 100644 --- a/Machines/Amiga/DMADevice.hpp +++ b/Machines/Amiga/DMADevice.hpp @@ -32,7 +32,7 @@ class DMADeviceBase { const uint32_t ram_mask_ = 0; }; -template class DMADevice: public DMADeviceBase { +template class DMADevice: public DMADeviceBase { public: using DMADeviceBase::DMADeviceBase; @@ -40,10 +40,19 @@ template class DMADevice: public DMADeviceBase { template void set_pointer(uint16_t value) { static_assert(id < num_addresses); static_assert(shift == 0 || shift == 16); + byte_pointer_[id] = (byte_pointer_[id] & (0xffff'0000 >> shift)) | uint32_t(value << shift); pointer_[id] = byte_pointer_[id] >> 1; } + /// Writes the word @c value to the modulo register @c id, shifting it by @c shift (0 or 16) first. + template void set_modulo(uint16_t value) { + static_assert(id < num_modulos); + + // Convert by sign extension. + modulos_[id] = uint32_t(int16_t(value) >> 1); + } + template uint16_t get_pointer() { // Restore the original least-significant bit. const uint32_t source = (pointer_[id] << 1) | (byte_pointer_[id] & 1); @@ -54,6 +63,7 @@ template class DMADevice: public DMADeviceBase { // These are shifted right one to provide word-indexing pointers; // subclasses should use e.g. ram_[pointer_[0] & ram_mask_] directly. std::array pointer_{}; + std::array modulos_{}; private: std::array byte_pointer_{}; diff --git a/OSBindings/Mac/Clock SignalTests/AmigaBlitterTests.mm b/OSBindings/Mac/Clock SignalTests/AmigaBlitterTests.mm index d30c6159a..22d887591 100644 --- a/OSBindings/Mac/Clock SignalTests/AmigaBlitterTests.mm +++ b/OSBindings/Mac/Clock SignalTests/AmigaBlitterTests.mm @@ -142,19 +142,19 @@ using WriteVector = std::vector>; } if([type isEqualToString:@"bltamod"]) { - blitter.set_modulo(0, param1); + blitter.set_modulo<0>(param1); continue; } if([type isEqualToString:@"bltbmod"]) { - blitter.set_modulo(1, param1); + blitter.set_modulo<1>(param1); continue; } if([type isEqualToString:@"bltcmod"]) { - blitter.set_modulo(2, param1); + blitter.set_modulo<2>(param1); continue; } if([type isEqualToString:@"bltdmod"]) { - blitter.set_modulo(3, param1); + blitter.set_modulo<3>(param1); continue; }