mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-07 23:25:00 +00:00
Gift all generators to YamahaFetcher.
This commit is contained in:
@@ -29,44 +29,268 @@ template <> struct Storage<Personality::TMS9918A> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct YamahaFetcher {
|
struct YamahaFetcher {
|
||||||
/// Describes an _observable_ memory access event. i.e. anything that it is safe
|
public:
|
||||||
/// (and convenient) to treat as atomic in between external slots.
|
/// Describes an _observable_ memory access event. i.e. anything that it is safe
|
||||||
struct Event {
|
/// (and convenient) to treat as atomic in between external slots.
|
||||||
/// Offset of the _beginning_ of the event. Not completely arbitrarily: this is when
|
struct Event {
|
||||||
/// external data must be ready by in order to take part in those slots.
|
/// Offset of the _beginning_ of the event. Not completely arbitrarily: this is when
|
||||||
uint16_t offset = 1368;
|
/// external data must be ready by in order to take part in those slots.
|
||||||
enum class Type: uint8_t {
|
uint16_t offset = 1368;
|
||||||
/// A slot for reading or writing data on behalf of the CPU or the command engine.
|
enum class Type: uint8_t {
|
||||||
External,
|
/// A slot for reading or writing data on behalf of the CPU or the command engine.
|
||||||
|
External,
|
||||||
|
|
||||||
//
|
//
|
||||||
// Sprites.
|
// Sprites.
|
||||||
//
|
//
|
||||||
SpriteY,
|
SpriteY,
|
||||||
SpriteLocation,
|
SpriteLocation,
|
||||||
SpritePattern,
|
SpritePattern,
|
||||||
|
|
||||||
//
|
//
|
||||||
// Backgrounds.
|
// Backgrounds.
|
||||||
//
|
//
|
||||||
Name,
|
Name,
|
||||||
Colour,
|
Colour,
|
||||||
Pattern,
|
Pattern,
|
||||||
} type = Type::External;
|
} type = Type::External;
|
||||||
uint8_t id = 0;
|
uint8_t id = 0;
|
||||||
|
|
||||||
constexpr Event(Type type, uint8_t id = 0) noexcept :
|
constexpr Event(Type type, uint8_t id = 0) noexcept :
|
||||||
type(type),
|
type(type),
|
||||||
id(id) {}
|
id(id) {}
|
||||||
|
|
||||||
constexpr Event() noexcept {}
|
constexpr Event() noexcept {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// State that tracks fetching position within a line.
|
// State that tracks fetching position within a line.
|
||||||
const Event *next_event_ = nullptr;
|
const Event *next_event_ = nullptr;
|
||||||
|
|
||||||
// Sprite collection state.
|
// Sprite collection state.
|
||||||
bool sprites_enabled_ = true;
|
bool sprites_enabled_ = true;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @return 1 + the number of times within a line that @c GeneratorT produces an event.
|
||||||
|
template <typename GeneratorT> static constexpr size_t events_size() {
|
||||||
|
size_t size = 0;
|
||||||
|
for(int c = 0; c < 1368; c++) {
|
||||||
|
const auto event_type = GeneratorT::event(c);
|
||||||
|
size += event_type.has_value();
|
||||||
|
}
|
||||||
|
return size + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return An array of all events generated by @c GeneratorT in line order.
|
||||||
|
template <typename GeneratorT, size_t size = events_size<GeneratorT>()>
|
||||||
|
static constexpr std::array<Event, size> events() {
|
||||||
|
std::array<Event, size> result{};
|
||||||
|
size_t index = 0;
|
||||||
|
for(int c = 0; c < 1368; c++) {
|
||||||
|
const auto event = GeneratorT::event(c);
|
||||||
|
if(!event) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result[index] = *event;
|
||||||
|
result[index].offset = uint16_t(c);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
result[index] = Event();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StandardGenerators {
|
||||||
|
static constexpr std::optional<Event> external_every_eight(int index) {
|
||||||
|
if(index & 7) return std::nullopt;
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RefreshGenerator {
|
||||||
|
static constexpr std::optional<Event> event(int grauw_index) {
|
||||||
|
// From 0 to 126: CPU/CMD slots at every cycle divisible by 8.
|
||||||
|
if(grauw_index < 126) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From 164 to 1234: eight-cycle windows, the first 15 of each 16 being
|
||||||
|
// CPU/CMD and the final being refresh.
|
||||||
|
if(grauw_index >= 164 && grauw_index < 1234) {
|
||||||
|
const int offset = grauw_index - 164;
|
||||||
|
if(offset & 7) return std::nullopt;
|
||||||
|
if(((offset >> 3) & 15) == 15) return std::nullopt;
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From 1268 to 1330: CPU/CMD slots at every cycle divisible by 8.
|
||||||
|
if(grauw_index >= 1268 && grauw_index < 1330) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 1268);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CPU/CMD at 1334.
|
||||||
|
if(grauw_index == 1334) {
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From 1344 to 1366: CPU/CMD slots every cycle divisible by 8.
|
||||||
|
if(grauw_index >= 1344 && grauw_index < 1366) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 1344);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise: nothing.
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool include_sprites> struct BitmapGenerator {
|
||||||
|
static constexpr std::optional<Event> event(int grauw_index) {
|
||||||
|
if(!include_sprites) {
|
||||||
|
// Various standard zones of one-every-eight external slots.
|
||||||
|
if(grauw_index < 124) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index + 2);
|
||||||
|
}
|
||||||
|
if(grauw_index > 1266) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 1266);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This records collection points for all data for selected sprites.
|
||||||
|
// There's only four of them (each site covering two sprites),
|
||||||
|
// so it's clearer just to be explicit.
|
||||||
|
//
|
||||||
|
// There's also a corresponding number of extra external slots to spell out.
|
||||||
|
switch(grauw_index) {
|
||||||
|
default: break;
|
||||||
|
case 1238: return Event(Event::Type::SpriteLocation, 0);
|
||||||
|
case 1302: return Event(Event::Type::SpriteLocation, 2);
|
||||||
|
case 2: return Event(Event::Type::SpriteLocation, 4);
|
||||||
|
case 66: return Event(Event::Type::SpriteLocation, 6);
|
||||||
|
case 1270: return Event(Event::Type::SpritePattern, 0);
|
||||||
|
case 1338: return Event(Event::Type::SpritePattern, 2);
|
||||||
|
case 34: return Event(Event::Type::SpritePattern, 4);
|
||||||
|
case 98: return Event(Event::Type::SpritePattern, 6);
|
||||||
|
case 1264: case 1330: case 28: case 92:
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(grauw_index >= 162 && grauw_index < 176) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 162);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everywhere else the pattern is:
|
||||||
|
//
|
||||||
|
// external or sprite y, external, data block
|
||||||
|
//
|
||||||
|
// Subject to caveats:
|
||||||
|
//
|
||||||
|
// 1) the first data block is just a dummy fetch with no side effects,
|
||||||
|
// so this emulator declines to record it; and
|
||||||
|
// 2) every fourth block, the second external is actually a refresh.
|
||||||
|
//
|
||||||
|
if(grauw_index >= 182 && grauw_index < 1238) {
|
||||||
|
const int offset = grauw_index - 182;
|
||||||
|
const int block = offset / 32;
|
||||||
|
const int sub_block = offset & 31;
|
||||||
|
|
||||||
|
switch(sub_block) {
|
||||||
|
default: return std::nullopt;
|
||||||
|
case 0:
|
||||||
|
if(include_sprites) {
|
||||||
|
// Don't include the sprite post-amble (i.e. a spurious read with no side effects).
|
||||||
|
if(block < 32) {
|
||||||
|
return Event(Event::Type::SpriteY, uint8_t(block));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
case 6:
|
||||||
|
if((block & 3) != 3) {
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
if(block) {
|
||||||
|
return Event(Event::Type::Pattern, uint8_t(block - 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextGenerator {
|
||||||
|
static constexpr std::optional<Event> event(int grauw_index) {
|
||||||
|
// Capture various one-in-eight zones.
|
||||||
|
if(grauw_index < 72) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 2);
|
||||||
|
}
|
||||||
|
if(grauw_index >= 166 && grauw_index < 228) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 166);
|
||||||
|
}
|
||||||
|
if(grauw_index >= 1206 && grauw_index < 1332) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 1206);
|
||||||
|
}
|
||||||
|
if(grauw_index == 1336) {
|
||||||
|
return Event::Type::External;
|
||||||
|
}
|
||||||
|
if(grauw_index >= 1346) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 1346);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elsewhere...
|
||||||
|
if(grauw_index >= 246) {
|
||||||
|
const int offset = grauw_index - 246;
|
||||||
|
const int block = offset / 48;
|
||||||
|
const int sub_block = offset % 48;
|
||||||
|
switch(sub_block) {
|
||||||
|
default: break;
|
||||||
|
case 0: return Event(Event::Type::Name, uint8_t(block));
|
||||||
|
case 18: return (block & 1) ? Event::Type::External : Event(Event::Type::Colour, uint8_t(block >> 1));
|
||||||
|
case 24: return Event(Event::Type::Pattern, uint8_t(block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharacterGenerator {
|
||||||
|
static constexpr std::optional<Event> event(int grauw_index) {
|
||||||
|
// Grab sprite events.
|
||||||
|
switch(grauw_index) {
|
||||||
|
default: break;
|
||||||
|
case 1242: return Event(Event::Type::SpriteLocation, 0);
|
||||||
|
case 1306: return Event(Event::Type::SpriteLocation, 1);
|
||||||
|
case 6: return Event(Event::Type::SpriteLocation, 2);
|
||||||
|
case 70: return Event(Event::Type::SpriteLocation, 3);
|
||||||
|
case 1274: return Event(Event::Type::SpritePattern, 0);
|
||||||
|
case 1342: return Event(Event::Type::SpritePattern, 1);
|
||||||
|
case 38: return Event(Event::Type::SpritePattern, 2);
|
||||||
|
case 102: return Event(Event::Type::SpritePattern, 3);
|
||||||
|
case 1268: case 1334: case 32: case 96: return Event::Type::External;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(grauw_index >= 166 && grauw_index < 180) {
|
||||||
|
return StandardGenerators::external_every_eight(grauw_index - 166);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(grauw_index >= 182 && grauw_index < 1238) {
|
||||||
|
const int offset = grauw_index - 182;
|
||||||
|
const int block = offset / 32;
|
||||||
|
const int sub_block = offset & 31;
|
||||||
|
switch(sub_block) {
|
||||||
|
case 0: if(block > 0) return Event(Event::Type::Name, uint8_t(block - 1));
|
||||||
|
case 6: if((sub_block & 3) != 3) return Event::Type::External;
|
||||||
|
case 12: if(block < 32) return Event(Event::Type::SpriteY, uint8_t(block));
|
||||||
|
case 18: if(block > 0) return Event(Event::Type::Pattern, uint8_t(block - 1));
|
||||||
|
case 24: if(block > 0) return Event(Event::Type::Colour, uint8_t(block - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Yamaha-specific storage.
|
// Yamaha-specific storage.
|
||||||
@@ -229,229 +453,10 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename GeneratorT> static constexpr size_t events_size() {
|
|
||||||
size_t size = 0;
|
|
||||||
for(int c = 0; c < 1368; c++) {
|
|
||||||
const auto event_type = GeneratorT::event(c);
|
|
||||||
size += event_type.has_value();
|
|
||||||
}
|
|
||||||
return size + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename GeneratorT, size_t size = events_size<GeneratorT>()>
|
|
||||||
static constexpr std::array<Event, size> events() {
|
|
||||||
std::array<Event, size> result{};
|
|
||||||
size_t index = 0;
|
|
||||||
for(int c = 0; c < 1368; c++) {
|
|
||||||
const auto event = GeneratorT::event(c);
|
|
||||||
if(!event) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result[index] = *event;
|
|
||||||
result[index].offset = uint16_t(c);
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
result[index] = Event();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StandardGenerators {
|
|
||||||
static constexpr std::optional<Event> external_every_eight(int index) {
|
|
||||||
if(index & 7) return std::nullopt;
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RefreshGenerator {
|
|
||||||
static constexpr std::optional<Event> event(int grauw_index) {
|
|
||||||
// From 0 to 126: CPU/CMD slots at every cycle divisible by 8.
|
|
||||||
if(grauw_index < 126) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 164 to 1234: eight-cycle windows, the first 15 of each 16 being
|
|
||||||
// CPU/CMD and the final being refresh.
|
|
||||||
if(grauw_index >= 164 && grauw_index < 1234) {
|
|
||||||
const int offset = grauw_index - 164;
|
|
||||||
if(offset & 7) return std::nullopt;
|
|
||||||
if(((offset >> 3) & 15) == 15) return std::nullopt;
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 1268 to 1330: CPU/CMD slots at every cycle divisible by 8.
|
|
||||||
if(grauw_index >= 1268 && grauw_index < 1330) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 1268);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A CPU/CMD at 1334.
|
|
||||||
if(grauw_index == 1334) {
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 1344 to 1366: CPU/CMD slots every cycle divisible by 8.
|
|
||||||
if(grauw_index >= 1344 && grauw_index < 1366) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 1344);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise: nothing.
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static constexpr auto refresh_events = events<RefreshGenerator>();
|
static constexpr auto refresh_events = events<RefreshGenerator>();
|
||||||
|
|
||||||
template <bool include_sprites> struct BitmapGenerator {
|
|
||||||
static constexpr std::optional<Event> event(int grauw_index) {
|
|
||||||
if(!include_sprites) {
|
|
||||||
// Various standard zones of one-every-eight external slots.
|
|
||||||
if(grauw_index < 124) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index + 2);
|
|
||||||
}
|
|
||||||
if(grauw_index > 1266) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 1266);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This records collection points for all data for selected sprites.
|
|
||||||
// There's only four of them (each site covering two sprites),
|
|
||||||
// so it's clearer just to be explicit.
|
|
||||||
//
|
|
||||||
// There's also a corresponding number of extra external slots to spell out.
|
|
||||||
switch(grauw_index) {
|
|
||||||
default: break;
|
|
||||||
case 1238: return Event(Event::Type::SpriteLocation, 0);
|
|
||||||
case 1302: return Event(Event::Type::SpriteLocation, 2);
|
|
||||||
case 2: return Event(Event::Type::SpriteLocation, 4);
|
|
||||||
case 66: return Event(Event::Type::SpriteLocation, 6);
|
|
||||||
case 1270: return Event(Event::Type::SpritePattern, 0);
|
|
||||||
case 1338: return Event(Event::Type::SpritePattern, 2);
|
|
||||||
case 34: return Event(Event::Type::SpritePattern, 4);
|
|
||||||
case 98: return Event(Event::Type::SpritePattern, 6);
|
|
||||||
case 1264: case 1330: case 28: case 92:
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(grauw_index >= 162 && grauw_index < 176) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 162);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everywhere else the pattern is:
|
|
||||||
//
|
|
||||||
// external or sprite y, external, data block
|
|
||||||
//
|
|
||||||
// Subject to caveats:
|
|
||||||
//
|
|
||||||
// 1) the first data block is just a dummy fetch with no side effects,
|
|
||||||
// so this emulator declines to record it; and
|
|
||||||
// 2) every fourth block, the second external is actually a refresh.
|
|
||||||
//
|
|
||||||
if(grauw_index >= 182 && grauw_index < 1238) {
|
|
||||||
const int offset = grauw_index - 182;
|
|
||||||
const int block = offset / 32;
|
|
||||||
const int sub_block = offset & 31;
|
|
||||||
|
|
||||||
switch(sub_block) {
|
|
||||||
default: return std::nullopt;
|
|
||||||
case 0:
|
|
||||||
if(include_sprites) {
|
|
||||||
// Don't include the sprite post-amble (i.e. a spurious read with no side effects).
|
|
||||||
if(block < 32) {
|
|
||||||
return Event(Event::Type::SpriteY, uint8_t(block));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
if((block & 3) != 3) {
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
if(block) {
|
|
||||||
return Event(Event::Type::Pattern, uint8_t(block - 1));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static constexpr auto no_sprites_events = events<BitmapGenerator<false>>();
|
static constexpr auto no_sprites_events = events<BitmapGenerator<false>>();
|
||||||
static constexpr auto sprites_events = events<BitmapGenerator<true>>();
|
static constexpr auto sprites_events = events<BitmapGenerator<true>>();
|
||||||
|
|
||||||
struct TextGenerator {
|
|
||||||
static constexpr std::optional<Event> event(int grauw_index) {
|
|
||||||
// Capture various one-in-eight zones.
|
|
||||||
if(grauw_index < 72) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 2);
|
|
||||||
}
|
|
||||||
if(grauw_index >= 166 && grauw_index < 228) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 166);
|
|
||||||
}
|
|
||||||
if(grauw_index >= 1206 && grauw_index < 1332) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 1206);
|
|
||||||
}
|
|
||||||
if(grauw_index == 1336) {
|
|
||||||
return Event::Type::External;
|
|
||||||
}
|
|
||||||
if(grauw_index >= 1346) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 1346);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Elsewhere...
|
|
||||||
if(grauw_index >= 246) {
|
|
||||||
const int offset = grauw_index - 246;
|
|
||||||
const int block = offset / 48;
|
|
||||||
const int sub_block = offset % 48;
|
|
||||||
switch(sub_block) {
|
|
||||||
default: break;
|
|
||||||
case 0: return Event(Event::Type::Name, uint8_t(block));
|
|
||||||
case 18: return (block & 1) ? Event::Type::External : Event(Event::Type::Colour, uint8_t(block >> 1));
|
|
||||||
case 24: return Event(Event::Type::Pattern, uint8_t(block));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static constexpr auto text_events = events<TextGenerator>();
|
static constexpr auto text_events = events<TextGenerator>();
|
||||||
|
|
||||||
struct CharacterGenerator {
|
|
||||||
static constexpr std::optional<Event> event(int grauw_index) {
|
|
||||||
// Grab sprite events.
|
|
||||||
switch(grauw_index) {
|
|
||||||
default: break;
|
|
||||||
case 1242: return Event(Event::Type::SpriteLocation, 0);
|
|
||||||
case 1306: return Event(Event::Type::SpriteLocation, 1);
|
|
||||||
case 6: return Event(Event::Type::SpriteLocation, 2);
|
|
||||||
case 70: return Event(Event::Type::SpriteLocation, 3);
|
|
||||||
case 1274: return Event(Event::Type::SpritePattern, 0);
|
|
||||||
case 1342: return Event(Event::Type::SpritePattern, 1);
|
|
||||||
case 38: return Event(Event::Type::SpritePattern, 2);
|
|
||||||
case 102: return Event(Event::Type::SpritePattern, 3);
|
|
||||||
case 1268: case 1334: case 32: case 96: return Event::Type::External;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(grauw_index >= 166 && grauw_index < 180) {
|
|
||||||
return StandardGenerators::external_every_eight(grauw_index - 166);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(grauw_index >= 182 && grauw_index < 1238) {
|
|
||||||
const int offset = grauw_index - 182;
|
|
||||||
const int block = offset / 32;
|
|
||||||
const int sub_block = offset & 31;
|
|
||||||
switch(sub_block) {
|
|
||||||
case 0: if(block > 0) return Event(Event::Type::Name, uint8_t(block - 1));
|
|
||||||
case 6: if((sub_block & 3) != 3) return Event::Type::External;
|
|
||||||
case 12: if(block < 32) return Event(Event::Type::SpriteY, uint8_t(block));
|
|
||||||
case 18: if(block > 0) return Event(Event::Type::Pattern, uint8_t(block - 1));
|
|
||||||
case 24: if(block > 0) return Event(Event::Type::Colour, uint8_t(block - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static constexpr auto character_events = events<CharacterGenerator>();
|
static constexpr auto character_events = events<CharacterGenerator>();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user