mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 18:31:53 +00:00
133 lines
4.1 KiB
C++
133 lines
4.1 KiB
C++
//
|
|
// Bitplanes.cpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 26/11/2021.
|
|
// Copyright © 2021 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#include "Bitplanes.hpp"
|
|
#include "Chipset.hpp"
|
|
|
|
using namespace Amiga;
|
|
|
|
namespace {
|
|
|
|
/// Expands @c source so that b7 is the least-significant bit of the most-significant byte of the result,
|
|
/// b6 is the least-significant bit of the next most significant byte, etc. b0 stays in place.
|
|
constexpr uint64_t expand_bitplane_byte(uint8_t source) {
|
|
uint64_t result = source; // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 abcd efgh
|
|
result = (result | (result << 28)) & 0x0000'000f'0000'000f; // 0000 0000 0000 0000 0000 0000 0000 abcd 0000 0000 0000 0000 0000 0000 0000 efgh
|
|
result = (result | (result << 14)) & 0x0003'0003'0003'0003; // 0000 0000 0000 00ab 0000 0000 0000 00cd 0000 0000 0000 00ef 0000 0000 0000 00gh
|
|
result = (result | (result << 7)) & 0x0101'0101'0101'0101; // 0000 000a 0000 000b 0000 000c 0000 000d 0000 000e 0000 000f 0000 000g 0000 000h
|
|
return result;
|
|
}
|
|
|
|
// A very small selection of test cases.
|
|
static_assert(expand_bitplane_byte(0xff) == 0x01'01'01'01'01'01'01'01);
|
|
static_assert(expand_bitplane_byte(0x55) == 0x00'01'00'01'00'01'00'01);
|
|
static_assert(expand_bitplane_byte(0xaa) == 0x01'00'01'00'01'00'01'00);
|
|
static_assert(expand_bitplane_byte(0x00) == 0x00'00'00'00'00'00'00'00);
|
|
|
|
}
|
|
|
|
// MARK: - BitplaneShifter.
|
|
|
|
void BitplaneShifter::set(const BitplaneData &previous, const BitplaneData &next, int odd_delay, int even_delay) {
|
|
const uint16_t planes[6] = {
|
|
uint16_t(((previous[0] << 16) | next[0]) >> even_delay),
|
|
uint16_t(((previous[1] << 16) | next[1]) >> odd_delay),
|
|
uint16_t(((previous[2] << 16) | next[2]) >> even_delay),
|
|
uint16_t(((previous[3] << 16) | next[3]) >> odd_delay),
|
|
uint16_t(((previous[4] << 16) | next[4]) >> even_delay),
|
|
uint16_t(((previous[5] << 16) | next[5]) >> odd_delay),
|
|
};
|
|
|
|
// Swizzle bits into the form:
|
|
//
|
|
// [b5 b3 b1 b4 b2 b0]
|
|
//
|
|
// ... and assume a suitably adjusted palette is in use elsewhere.
|
|
// This makes dual playfields very easy to separate.
|
|
data_[0] =
|
|
(expand_bitplane_byte(uint8_t(planes[0])) << 0) |
|
|
(expand_bitplane_byte(uint8_t(planes[2])) << 1) |
|
|
(expand_bitplane_byte(uint8_t(planes[4])) << 2) |
|
|
(expand_bitplane_byte(uint8_t(planes[1])) << 3) |
|
|
(expand_bitplane_byte(uint8_t(planes[3])) << 4) |
|
|
(expand_bitplane_byte(uint8_t(planes[5])) << 5);
|
|
|
|
data_[1] =
|
|
(expand_bitplane_byte(uint8_t(planes[0] >> 8)) << 0) |
|
|
(expand_bitplane_byte(uint8_t(planes[2] >> 8)) << 1) |
|
|
(expand_bitplane_byte(uint8_t(planes[4] >> 8)) << 2) |
|
|
(expand_bitplane_byte(uint8_t(planes[1] >> 8)) << 3) |
|
|
(expand_bitplane_byte(uint8_t(planes[3] >> 8)) << 4) |
|
|
(expand_bitplane_byte(uint8_t(planes[5] >> 8)) << 5);
|
|
}
|
|
|
|
// MARK: - Bitplanes.
|
|
|
|
bool Bitplanes::advance_dma(int cycle) {
|
|
#define BIND_CYCLE(offset, plane) \
|
|
case offset: \
|
|
if(plane_count_ > plane) { \
|
|
next[plane] = ram_[pointer_[plane] & ram_mask_]; \
|
|
++pointer_[plane]; \
|
|
if constexpr (!plane) { \
|
|
chipset_.post_bitplanes(next); \
|
|
} \
|
|
return true; \
|
|
} \
|
|
return false;
|
|
|
|
if(is_high_res_) {
|
|
switch(cycle&3) {
|
|
default: return false;
|
|
BIND_CYCLE(0, 3);
|
|
BIND_CYCLE(1, 1);
|
|
BIND_CYCLE(2, 2);
|
|
BIND_CYCLE(3, 0);
|
|
}
|
|
} else {
|
|
switch(cycle&7) {
|
|
default: return false;
|
|
/* Omitted: 0. */
|
|
BIND_CYCLE(1, 3);
|
|
BIND_CYCLE(2, 5);
|
|
BIND_CYCLE(3, 1);
|
|
/* Omitted: 4. */
|
|
BIND_CYCLE(5, 2);
|
|
BIND_CYCLE(6, 4);
|
|
BIND_CYCLE(7, 0);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
#undef BIND_CYCLE
|
|
}
|
|
|
|
void Bitplanes::do_end_of_line() {
|
|
// 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 Bitplanes::set_control(uint16_t control) {
|
|
is_high_res_ = control & 0x8000;
|
|
plane_count_ = (control >> 12) & 7;
|
|
|
|
// TODO: who really has responsibility for clearing the other
|
|
// bit plane fields?
|
|
std::fill(next.begin() + plane_count_, next.end(), 0);
|
|
if(plane_count_ == 7) {
|
|
plane_count_ = 4;
|
|
}
|
|
}
|