mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 16:31:42 +00:00
Move sprites into their own source file.
This commit is contained in:
parent
4b21549ff4
commit
1c0962e53c
@ -43,27 +43,12 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
#define DMA_CONSTRUCT *this, reinterpret_cast<uint16_t *>(map.chip_ram.data()), map.chip_ram.size() >> 1
|
||||
@ -1102,86 +1087,6 @@ void Chipset::Bitplanes::set_control(uint16_t control) {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sprites.
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void Chipset::Sprite::set_stop_and_control(uint16_t value) {
|
||||
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;
|
||||
|
||||
// Disarm the sprite, but expect graphics next from DMA.
|
||||
visible = false;
|
||||
dma_state_ = DMAState::FetchImage;
|
||||
}
|
||||
|
||||
void Chipset::Sprite::set_image_data(int slot, uint16_t value) {
|
||||
data[slot] = value;
|
||||
visible |= slot == 0;
|
||||
}
|
||||
|
||||
void Chipset::Sprite::advance_line(int y, bool is_end_of_blank) {
|
||||
if(dma_state_ == DMAState::FetchImage && y == v_start_) {
|
||||
visible = true;
|
||||
}
|
||||
if(is_end_of_blank || y == v_stop_) {
|
||||
dma_state_ = DMAState::FetchControl;
|
||||
}
|
||||
}
|
||||
|
||||
bool Chipset::Sprite::advance_dma(int offset) {
|
||||
if(!visible) return false;
|
||||
|
||||
// Fetch another word.
|
||||
const uint16_t next_word = ram_[pointer_[0] & ram_mask_];
|
||||
++pointer_[0];
|
||||
|
||||
// Put the fetched word somewhere appropriate and update the DMA state.
|
||||
switch(dma_state_) {
|
||||
// i.e. stopped.
|
||||
default: return false;
|
||||
|
||||
case DMAState::FetchControl:
|
||||
if(offset) {
|
||||
set_stop_and_control(next_word);
|
||||
} else {
|
||||
set_start_position(next_word);
|
||||
}
|
||||
return true;
|
||||
|
||||
case DMAState::FetchImage:
|
||||
set_image_data(1 - bool(offset), next_word);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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; 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;
|
||||
overflow_ |= uint8_t((new_data << 8) >> delay_shift);
|
||||
}
|
||||
|
||||
// MARK: - CRT connection.
|
||||
|
||||
void Chipset::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "Flags.hpp"
|
||||
#include "Keyboard.hpp"
|
||||
#include "MemoryMap.hpp"
|
||||
#include "Sprites.hpp"
|
||||
|
||||
namespace Amiga {
|
||||
|
||||
@ -142,60 +143,8 @@ class Chipset: private ClockingHint::Observer {
|
||||
|
||||
// MARK: - Sprites.
|
||||
|
||||
class Sprite: public DMADevice<1> {
|
||||
public:
|
||||
using DMADevice::DMADevice;
|
||||
|
||||
void set_start_position(uint16_t value);
|
||||
void set_stop_and_control(uint16_t value);
|
||||
void set_image_data(int slot, uint16_t value);
|
||||
|
||||
void advance_line(int y, bool is_end_of_blank);
|
||||
bool advance_dma(int offset);
|
||||
|
||||
uint16_t data[2]{};
|
||||
bool attached = false;
|
||||
bool visible = false;
|
||||
uint16_t h_start = 0;
|
||||
|
||||
private:
|
||||
uint16_t v_start_ = 0, v_stop_ = 0;
|
||||
|
||||
enum class DMAState {
|
||||
FetchControl,
|
||||
FetchImage
|
||||
} dma_state_ = DMAState::FetchControl;
|
||||
} 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_ >> 56);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t data_;
|
||||
uint8_t overflow_;
|
||||
} sprite_shifters_[4];
|
||||
Sprite sprites_[8];
|
||||
TwoSpriteShifter sprite_shifters_[4];
|
||||
|
||||
// MARK: - Raster position and state.
|
||||
|
||||
|
114
Machines/Amiga/Sprites.cpp
Normal file
114
Machines/Amiga/Sprites.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// Sprites.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 26/11/2021.
|
||||
// Copyright © 2021 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Sprites.hpp"
|
||||
|
||||
using namespace Amiga;
|
||||
|
||||
namespace {
|
||||
|
||||
/// 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_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);
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Sprites.
|
||||
|
||||
void Sprite::set_start_position(uint16_t value) {
|
||||
v_start_ = (v_start_ & 0xff00) | (value >> 8);
|
||||
h_start = uint16_t((h_start & 0x0001) | ((value & 0xff) << 1));
|
||||
}
|
||||
|
||||
void Sprite::set_stop_and_control(uint16_t value) {
|
||||
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;
|
||||
|
||||
// Disarm the sprite, but expect graphics next from DMA.
|
||||
visible = false;
|
||||
dma_state_ = DMAState::FetchImage;
|
||||
}
|
||||
|
||||
void Sprite::set_image_data(int slot, uint16_t value) {
|
||||
data[slot] = value;
|
||||
visible |= slot == 0;
|
||||
}
|
||||
|
||||
void Sprite::advance_line(int y, bool is_end_of_blank) {
|
||||
if(dma_state_ == DMAState::FetchImage && y == v_start_) {
|
||||
visible = true;
|
||||
}
|
||||
if(is_end_of_blank || y == v_stop_) {
|
||||
dma_state_ = DMAState::FetchControl;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sprite::advance_dma(int offset) {
|
||||
if(!visible) return false;
|
||||
|
||||
// Fetch another word.
|
||||
const uint16_t next_word = ram_[pointer_[0] & ram_mask_];
|
||||
++pointer_[0];
|
||||
|
||||
// Put the fetched word somewhere appropriate and update the DMA state.
|
||||
switch(dma_state_) {
|
||||
// i.e. stopped.
|
||||
default: return false;
|
||||
|
||||
case DMAState::FetchControl:
|
||||
if(offset) {
|
||||
set_stop_and_control(next_word);
|
||||
} else {
|
||||
set_start_position(next_word);
|
||||
}
|
||||
return true;
|
||||
|
||||
case DMAState::FetchImage:
|
||||
set_image_data(1 - bool(offset), next_word);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <int sprite> void 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; 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;
|
||||
overflow_ |= uint8_t((new_data << 8) >> delay_shift);
|
||||
}
|
||||
|
||||
template void TwoSpriteShifter::load<0>(uint16_t, uint16_t, int);
|
||||
template void TwoSpriteShifter::load<1>(uint16_t, uint16_t, int);
|
76
Machines/Amiga/Sprites.hpp
Normal file
76
Machines/Amiga/Sprites.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// Sprites.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 26/11/2021.
|
||||
// Copyright © 2021 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Sprites_hpp
|
||||
#define Sprites_hpp
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "DMADevice.hpp"
|
||||
|
||||
namespace Amiga {
|
||||
|
||||
class Sprite: public DMADevice<1> {
|
||||
public:
|
||||
using DMADevice::DMADevice;
|
||||
|
||||
void set_start_position(uint16_t value);
|
||||
void set_stop_and_control(uint16_t value);
|
||||
void set_image_data(int slot, uint16_t value);
|
||||
|
||||
void advance_line(int y, bool is_end_of_blank);
|
||||
bool advance_dma(int offset);
|
||||
|
||||
uint16_t data[2]{};
|
||||
bool attached = false;
|
||||
bool visible = false;
|
||||
uint16_t h_start = 0;
|
||||
|
||||
private:
|
||||
uint16_t v_start_ = 0, v_stop_ = 0;
|
||||
|
||||
enum class DMAState {
|
||||
FetchControl,
|
||||
FetchImage
|
||||
} dma_state_ = DMAState::FetchControl;
|
||||
};
|
||||
|
||||
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_ >> 56);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t data_;
|
||||
uint8_t overflow_;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* Sprites_hpp */
|
@ -433,6 +433,8 @@
|
||||
4B7BA03423C58B1F00B98D9E /* STX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03323C58B1E00B98D9E /* STX.cpp */; };
|
||||
4B7BA03723CEB86000B98D9E /* BD500.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03523CEB86000B98D9E /* BD500.cpp */; };
|
||||
4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */; };
|
||||
4B7C681627517A59001671EC /* Sprites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C681427517A59001671EC /* Sprites.cpp */; };
|
||||
4B7C681727517A59001671EC /* Sprites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C681427517A59001671EC /* Sprites.cpp */; };
|
||||
4B7F188E2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; };
|
||||
4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; };
|
||||
4B7F1897215486A200388727 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F1896215486A100388727 /* StaticAnalyser.cpp */; };
|
||||
@ -1425,6 +1427,8 @@
|
||||
4B7BA03823CEB8D200B98D9E /* DiskController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
|
||||
4B7BA03E23D55E7900B98D9E /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRC.hpp; sourceTree = "<group>"; };
|
||||
4B7BA03F23D55E7900B98D9E /* LFSR.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LFSR.hpp; sourceTree = "<group>"; };
|
||||
4B7C681427517A59001671EC /* Sprites.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sprites.cpp; sourceTree = "<group>"; };
|
||||
4B7C681527517A59001671EC /* Sprites.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sprites.hpp; sourceTree = "<group>"; };
|
||||
4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = "<group>"; };
|
||||
4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = "<group>"; };
|
||||
4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||
@ -4306,6 +4310,7 @@
|
||||
4BC6236C26F4235400F83DFE /* Copper.cpp */,
|
||||
4B1A1B1C27320FBB00119335 /* Disk.cpp */,
|
||||
4B9EC0E826B384080060A31F /* Keyboard.cpp */,
|
||||
4B7C681427517A59001671EC /* Sprites.cpp */,
|
||||
4BC080D726A25ADA00D03FD8 /* Amiga.hpp */,
|
||||
4B2130E1273A7A0A008A77B4 /* Audio.hpp */,
|
||||
4B9EC0E026AA260C0060A31F /* Blitter.hpp */,
|
||||
@ -4316,6 +4321,7 @@
|
||||
4B9EC0E926B384080060A31F /* Keyboard.hpp */,
|
||||
4BD1552E270B14AC00410C6E /* MemoryMap.hpp */,
|
||||
4BC6237026F94A5B00F83DFE /* Minterms.hpp */,
|
||||
4B7C681527517A59001671EC /* Sprites.hpp */,
|
||||
);
|
||||
path = Amiga;
|
||||
sourceTree = "<group>";
|
||||
@ -5344,6 +5350,7 @@
|
||||
4B2E86BF25D74F160024F1E9 /* Mouse.cpp in Sources */,
|
||||
4B6ED2F1208E2F8A0047B343 /* WOZ.cpp in Sources */,
|
||||
4B5D5C9825F56FC7001B4623 /* Spectrum.cpp in Sources */,
|
||||
4B7C681727517A59001671EC /* Sprites.cpp in Sources */,
|
||||
4B2E86D025D8D8C70024F1E9 /* Keyboard.cpp in Sources */,
|
||||
4B89452F201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4B894531201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
@ -5718,6 +5725,7 @@
|
||||
4B894528201967B4007DE474 /* Disk.cpp in Sources */,
|
||||
4B2E86CF25D8D8C70024F1E9 /* Keyboard.cpp in Sources */,
|
||||
4BBB70A4202011C2002FE009 /* MultiMediaTarget.cpp in Sources */,
|
||||
4B7C681627517A59001671EC /* Sprites.cpp in Sources */,
|
||||
4B0ACC02237756ED008902D0 /* Line.cpp in Sources */,
|
||||
4B89453A201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user