1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Switches to basic use of sprite shifters.

This commit is contained in:
Thomas Harte 2021-10-25 20:58:48 -07:00
parent cb24457b4a
commit 139d35c6f9
2 changed files with 67 additions and 44 deletions

View File

@ -41,15 +41,26 @@ constexpr uint64_t expand_bitplane_byte(uint8_t source) {
return result;
}
/// Expands @c source from b15 ... b0 to 000b15 ... 000b0.
constexpr uint64_t expand_sprite_word(uint16_t source) {
uint64_t result = source;
result = (result | (result << 24)) & 0x0000'00ff'0000'00ff;
result = (result | (result << 12)) & 0x000f'000f'000f'000f;
result = (result | (result << 6)) & 0x0303'0303'0303'0303;
result = (result | (result << 3)) & 0x1111'1111'1111'1111;
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);
constexpr uint64_t expand_sprite_word(uint16_t source) {
return 0; // TODO.
}
static_assert(expand_sprite_word(0xffff) == 0x11'11'11'11'11'11'11'11);
static_assert(expand_sprite_word(0x5555) == 0x01'01'01'01'01'01'01'01);
static_assert(expand_sprite_word(0xaaaa) == 0x10'10'10'10'10'10'10'10);
static_assert(expand_sprite_word(0x0000) == 0x00'00'00'00'00'00'00'00);
}
@ -127,6 +138,28 @@ template <int cycle> void Chipset::output() {
constexpr int blank3 = 7 + burst;
static_assert(blank3 == 43);
// Trigger any sprite loads encountered.
constexpr auto dcycle = cycle << 1;
for(int c = 0; c < 8; c += 2) {
if( sprites_[c].active &&
dcycle <= sprites_[c].h_start &&
dcycle+2 > sprites_[c].h_start) {
sprite_shifters_[c >> 1].load<0>(
sprites_[c].data[1],
sprites_[c].data[0],
sprites_[c].h_start & 1);
}
if( sprites_[c+1].active &&
dcycle <= sprites_[c + 1].h_start &&
dcycle+2 > sprites_[c + 1].h_start) {
sprite_shifters_[c >> 1].load<1>(
sprites_[c + 1].data[1],
sprites_[c + 1].data[0],
sprites_[c + 1].h_start & 1);
}
}
#define LINK(location, action, length) \
if(cycle == (location)) { \
crt_.action((length) * 4); \
@ -207,35 +240,25 @@ template <int cycle> void Chipset::output() {
pixels_[2] = palette_[(source >> 8) & 0xff];
pixels_[3] = palette_[source & 0xff];
// QUICK HACK: dump sprite pixels:
//
// (i) always on top, regardless of current priority;
// (ii) assuming four-colour sprites; and
// (iii) not using the proper triggering mechanism.
//
// (and assuming visible area is a subset of the fetch area, but elsewhere
// the two are currently equated, so...)
constexpr auto dcycle = cycle << 1;
for(int c = 7; c >= 0; --c) {
if(sprites_[c].active && sprites_[c].h_start_ <= (dcycle+1) && sprites_[c].h_start_+16 >= dcycle) {
const int shift = 16 + dcycle - sprites_[c].h_start_;
uint32_t pixels[] = {
uint32_t(sprites_[c].data[0] << shift),
uint32_t(sprites_[c].data[1] << shift),
};
for(int c = 3; c >= 0; --c) {
const auto data = sprite_shifters_[c].get();
if(!data) continue;
const int base = (c << 2) + 16;
const int colours[] = {
int((pixels[1] >> 31) | ((pixels[0] >> 30) & 2)),
int(((pixels[1] >> 30)&1) | ((pixels[0] >> 29) & 2))
};
const int base = ((c&~1) << 1) + 16;
if(colours[0]) {
pixels_[0] = pixels_[1] = palette_[base + colours[0]];
}
if(colours[1]) {
pixels_[2] = pixels_[3] = palette_[base + colours[1]];
}
// TODO: can do a better job of selection here —
// treat each 4-bit quantity as a single colour
// selection, much like dual playfield mode.
if(data >> 6) {
pixels_[0] = pixels_[1] = palette_[base + (data >> 6)];
}
if((data >> 4) & 3) {
pixels_[0] = pixels_[1] = palette_[base + ((data >> 4)&3)];
}
if((data >> 2) & 3) {
pixels_[2] = pixels_[3] = palette_[base + ((data >> 2)&3)];
}
if(data & 3) {
pixels_[2] = pixels_[3] = palette_[base + (data & 3)];
}
}
@ -958,12 +981,12 @@ void Chipset::Bitplanes::set_control(uint16_t control) {
void Chipset::Sprite::set_start_position(uint16_t value) {
v_start_ = (v_start_ & 0xff00) | (value >> 8);
h_start_ = uint16_t((h_start_ & 0x0001) | ((value & 0xff) << 1));
h_start = uint16_t((h_start & 0x0001) | ((value & 0xff) << 1));
active = false;
}
void Chipset::Sprite::set_stop_and_control(uint16_t value) {
h_start_ = uint16_t((h_start_ & 0x01fe) | (value & 0x01));
h_start = uint16_t((h_start & 0x01fe) | (value & 0x01));
v_stop_ = uint16_t((value >> 8) | ((value & 0x02) << 7));
v_start_ = uint16_t((v_start_ & 0x00ff) | ((value & 0x04) << 6));
attached = value & 0x80;
@ -1033,15 +1056,18 @@ template <int sprite> void Chipset::TwoSpriteShifter::load(
constexpr int sprite_shift = sprite << 1;
const int delay_shift = delay << 2;
// Clear out any current sprite pixels.
data_ &= (0x3333'3333'3333'3333 << sprite_shift) >> delay_shift;
// Clear out any current sprite pixels; this is a reload.
data_ &= 0xcccc'cccc'cccc'ccccull >> (sprite_shift + delay_shift);
// Map LSB and MSB up to 64-bits and load into the shifter.
const uint64_t new_data =
(expand_sprite_word(lsb) | (expand_sprite_word(msb) << 1)) << sprite_shift;
data_ |= new_data >> delay_shift;
(
expand_sprite_word(lsb) |
(expand_sprite_word(msb) << 1)
) << sprite_shift;
overflow_ |= new_data >> (64 - delay_shift);
data_ |= new_data >> delay_shift;
overflow_ |= uint8_t((new_data << 8) >> delay_shift);
}
// MARK: - Disk.

View File

@ -139,10 +139,7 @@ class Chipset: private ClockingHint::Observer {
uint16_t data[2]{};
bool attached = false;
bool active = false;
// TODO: unexpose this. It's public temporarily to allow
// an initial quick hack of sprite display.
uint16_t h_start_ = 0;
uint16_t h_start = 0;
private:
uint16_t v_start_ = 0, v_stop_ = 0;
@ -174,12 +171,12 @@ class Chipset: private ClockingHint::Observer {
overflow_ = 0;
}
/// @returns The next two pixels to output, formulated as:
/// @returns The next two pixels to output, formulated as
/// abcd efgh where ab and ef are two pixels of the first sprite
/// and cd and gh are two pixels of the second. In each case the
/// more significant two are output first.
uint8_t get() {
return uint8_t(data_ >> 24);
return uint8_t(data_ >> 56);
}
private: