mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-12 15:31:09 +00:00
Starts on a two-at-a-time sprite shifter.
This commit is contained in:
parent
9f3efb7f05
commit
cb24457b4a
@ -31,6 +31,26 @@ template <typename EnumT, EnumT F, EnumT... T> struct Mask<EnumT, F, T...> {
|
||||
template <InterruptFlag... Flags> struct InterruptMask: Mask<InterruptFlag, Flags...> {};
|
||||
template <DMAFlag... Flags> struct DMAMask: Mask<DMAFlag, Flags...> {};
|
||||
|
||||
/// 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);
|
||||
|
||||
constexpr uint64_t expand_sprite_word(uint16_t source) {
|
||||
return 0; // TODO.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define DMA_CONSTRUCT *this, reinterpret_cast<uint16_t *>(map.chip_ram.data()), map.chip_ram.size() >> 1
|
||||
@ -179,7 +199,7 @@ template <int cycle> void Chipset::output() {
|
||||
|
||||
if(pixels_) {
|
||||
// TODO: this doesn't support dual playfields; use an alternative
|
||||
// palette table for that.
|
||||
// palette table for that?
|
||||
const uint32_t source = bitplane_pixels_.get(is_high_res_);
|
||||
|
||||
pixels_[0] = palette_[source >> 24];
|
||||
@ -230,8 +250,11 @@ template <int cycle> void Chipset::output() {
|
||||
}
|
||||
|
||||
// Update all active pixel shifters.
|
||||
// TODO: including sprites.
|
||||
bitplane_pixels_.shift(is_high_res_);
|
||||
sprite_shifters_[0].shift();
|
||||
sprite_shifters_[1].shift();
|
||||
sprite_shifters_[2].shift();
|
||||
sprite_shifters_[3].shift();
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,27 +504,7 @@ void Chipset::post_bitplanes(const BitplaneData &data) {
|
||||
fetch_horizontal_ &= !horizontal_is_last_;
|
||||
}
|
||||
|
||||
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_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_byte(0xff) == 0x01'01'01'01'01'01'01'01);
|
||||
static_assert(expand_byte(0x55) == 0x00'01'00'01'00'01'00'01);
|
||||
static_assert(expand_byte(0xaa) == 0x01'00'01'00'01'00'01'00);
|
||||
static_assert(expand_byte(0x00) == 0x00'00'00'00'00'00'00'00);
|
||||
|
||||
}
|
||||
|
||||
void Chipset::SixteenPixels::set(const BitplaneData &previous, const BitplaneData &next, int odd_delay, int even_delay) {
|
||||
void Chipset::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),
|
||||
@ -511,21 +514,21 @@ void Chipset::SixteenPixels::set(const BitplaneData &previous, const BitplaneDat
|
||||
uint16_t(((previous[5] << 16) | next[5]) >> odd_delay),
|
||||
};
|
||||
|
||||
(*this)[0] =
|
||||
(expand_byte(uint8_t(planes[0])) << 0) |
|
||||
(expand_byte(uint8_t(planes[1])) << 1) |
|
||||
(expand_byte(uint8_t(planes[2])) << 2) |
|
||||
(expand_byte(uint8_t(planes[3])) << 3) |
|
||||
(expand_byte(uint8_t(planes[4])) << 4) |
|
||||
(expand_byte(uint8_t(planes[5])) << 5);
|
||||
data_[0] =
|
||||
(expand_bitplane_byte(uint8_t(planes[0])) << 0) |
|
||||
(expand_bitplane_byte(uint8_t(planes[1])) << 1) |
|
||||
(expand_bitplane_byte(uint8_t(planes[2])) << 2) |
|
||||
(expand_bitplane_byte(uint8_t(planes[3])) << 3) |
|
||||
(expand_bitplane_byte(uint8_t(planes[4])) << 4) |
|
||||
(expand_bitplane_byte(uint8_t(planes[5])) << 5);
|
||||
|
||||
(*this)[1] =
|
||||
(expand_byte(uint8_t(planes[0] >> 8)) << 0) |
|
||||
(expand_byte(uint8_t(planes[1] >> 8)) << 1) |
|
||||
(expand_byte(uint8_t(planes[2] >> 8)) << 2) |
|
||||
(expand_byte(uint8_t(planes[3] >> 8)) << 3) |
|
||||
(expand_byte(uint8_t(planes[4] >> 8)) << 4) |
|
||||
(expand_byte(uint8_t(planes[5] >> 8)) << 5);
|
||||
data_[1] =
|
||||
(expand_bitplane_byte(uint8_t(planes[0] >> 8)) << 0) |
|
||||
(expand_bitplane_byte(uint8_t(planes[1] >> 8)) << 1) |
|
||||
(expand_bitplane_byte(uint8_t(planes[2] >> 8)) << 2) |
|
||||
(expand_bitplane_byte(uint8_t(planes[3] >> 8)) << 3) |
|
||||
(expand_bitplane_byte(uint8_t(planes[4] >> 8)) << 4) |
|
||||
(expand_bitplane_byte(uint8_t(planes[5] >> 8)) << 5);
|
||||
}
|
||||
|
||||
void Chipset::update_interrupts() {
|
||||
@ -1023,6 +1026,24 @@ void Chipset::Sprite::reset_dma() {
|
||||
dma_state_ = DMAState::FetchStart;
|
||||
}
|
||||
|
||||
template <int sprite> void Chipset::TwoSpriteShifter::load(
|
||||
uint16_t lsb,
|
||||
uint16_t msb,
|
||||
int delay) {
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
overflow_ |= new_data >> (64 - delay_shift);
|
||||
}
|
||||
|
||||
// MARK: - Disk.
|
||||
|
||||
void Chipset::DiskDMA::enqueue(uint16_t value, bool matches_sync) {
|
||||
|
@ -157,6 +157,36 @@ class Chipset: private ClockingHint::Observer {
|
||||
} dma_state_ = DMAState::FetchStart;
|
||||
} sprites_[8];
|
||||
|
||||
class TwoSpriteShifter {
|
||||
public:
|
||||
/// Installs new pixel data for @c sprite (either 0 or 1),
|
||||
/// with @c delay being either 0 or 1 to indicate whether
|
||||
/// output should begin now or in one pixel's time.
|
||||
template <int sprite> void load(
|
||||
uint16_t lsb,
|
||||
uint16_t msb,
|
||||
int delay);
|
||||
|
||||
/// Shifts two pixels.
|
||||
void shift() {
|
||||
data_ <<= 8;
|
||||
data_ |= overflow_;
|
||||
overflow_ = 0;
|
||||
}
|
||||
|
||||
/// @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);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t data_;
|
||||
uint8_t overflow_;
|
||||
} sprite_shifters_[4];
|
||||
|
||||
// MARK: - Raster position and state.
|
||||
|
||||
// Definitions related to PAL/NTSC.
|
||||
@ -219,30 +249,40 @@ class Chipset: private ClockingHint::Observer {
|
||||
void post_bitplanes(const BitplaneData &data);
|
||||
BitplaneData previous_bitplanes_;
|
||||
|
||||
struct SixteenPixels: public std::array<uint64_t, 2> {
|
||||
void set(
|
||||
const BitplaneData &previous,
|
||||
const BitplaneData &next,
|
||||
int odd_delay,
|
||||
int even_delay);
|
||||
class BitplaneShifter {
|
||||
public:
|
||||
/// Installs a new set of output pixels.
|
||||
void set(
|
||||
const BitplaneData &previous,
|
||||
const BitplaneData &next,
|
||||
int odd_delay,
|
||||
int even_delay);
|
||||
|
||||
void shift(bool high_res) {
|
||||
constexpr int shifts[] = {16, 32};
|
||||
/// Shifts either two pixels (in low-res mode) and four pixels (in high-res).
|
||||
void shift(bool high_res) {
|
||||
constexpr int shifts[] = {16, 32};
|
||||
|
||||
(*this)[1] = ((*this)[1] << shifts[high_res]) | ((*this)[0] >> (64 - shifts[high_res]));
|
||||
(*this)[0] <<= shifts[high_res];
|
||||
}
|
||||
|
||||
uint32_t get(bool high_res) {
|
||||
if(high_res) {
|
||||
return uint32_t((*this)[1] >> 32);
|
||||
} else {
|
||||
uint32_t result = uint16_t((*this)[1] >> 48);
|
||||
result = ((result & 0xff00) << 8) | (result & 0x00ff);
|
||||
result |= result << 8;
|
||||
return result;
|
||||
data_[1] = (data_[1] << shifts[high_res]) | (data_[0] >> (64 - shifts[high_res]));
|
||||
data_[0] <<= shifts[high_res];
|
||||
}
|
||||
}
|
||||
|
||||
/// @returns The next four pixels to output; in low-resolution mode only two
|
||||
/// of them will be unique. The value is arranges so that MSB = first pixel to output,
|
||||
/// LSB = last. Each byte is formed as 00[bitplane 5][bitplane 4]...[bitplane 0].
|
||||
uint32_t get(bool high_res) {
|
||||
if(high_res) {
|
||||
return uint32_t(data_[1] >> 32);
|
||||
} else {
|
||||
uint32_t result = uint16_t(data_[1] >> 48);
|
||||
result = ((result & 0xff00) << 8) | (result & 0x00ff);
|
||||
result |= result << 8;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint64_t, 2> data_{};
|
||||
|
||||
} bitplane_pixels_;
|
||||
|
||||
int odd_delay_ = 0, even_delay_ = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user