mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Start attempting to use table-based Yamaha fetch.
This commit is contained in:
parent
c6dd7d4726
commit
91047e5b3a
@ -200,52 +200,28 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// ------------------------
|
// ------------------------
|
||||||
// Perform memory accesses.
|
// Perform memory accesses.
|
||||||
// ------------------------
|
// ------------------------
|
||||||
#define fetch(function_true, function_false, clock) { \
|
#define fetch(function, clock) { \
|
||||||
const int first_window = from_internal<personality, clock>(this->fetch_pointer_.column);\
|
const int first_window = from_internal<personality, clock>(this->fetch_pointer_.column);\
|
||||||
const int final_window = from_internal<personality, clock>(end_column); \
|
const int final_window = from_internal<personality, clock>(end_column); \
|
||||||
if(first_window == final_window) break; \
|
if(first_window == final_window) break; \
|
||||||
if(final_window != clock_rate<personality, clock>()) { \
|
if(final_window != clock_rate<personality, clock>()) { \
|
||||||
function_true(first_window, final_window); \
|
function<true>(first_window, final_window); \
|
||||||
} else { \
|
} else { \
|
||||||
function_false(first_window, final_window); \
|
function<false>(first_window, final_window); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define fetch_simple(function, clock) fetch(function<true>, function<false>, clock)
|
|
||||||
|
|
||||||
switch(line_buffer.line_mode) {
|
switch(line_buffer.line_mode) {
|
||||||
case LineMode::Text: fetch_simple(this->template fetch_tms_text, Clock::TMSMemoryWindow); break;
|
case LineMode::Text: fetch(this->template fetch_tms_text, Clock::TMSMemoryWindow); break;
|
||||||
case LineMode::Character: fetch_simple(this->template fetch_tms_character, Clock::TMSMemoryWindow); break;
|
case LineMode::Character: fetch(this->template fetch_tms_character, Clock::TMSMemoryWindow); break;
|
||||||
case LineMode::SMS: fetch_simple(this->template fetch_sms, Clock::TMSMemoryWindow); break;
|
case LineMode::SMS: fetch(this->template fetch_sms, Clock::TMSMemoryWindow); break;
|
||||||
case LineMode::Refresh: fetch_simple(this->template fetch_tms_refresh, Clock::TMSMemoryWindow); break;
|
case LineMode::Refresh: fetch(this->template fetch_tms_refresh, Clock::TMSMemoryWindow); break;
|
||||||
|
|
||||||
case LineMode::Yamaha:
|
case LineMode::Yamaha: fetch(this->template fetch_yamaha, Clock::Internal); break;
|
||||||
#define true_func this->template fetch_yamaha<true, true>
|
|
||||||
#define false_func this->template fetch_yamaha<false, true>
|
|
||||||
fetch(
|
|
||||||
true_func,
|
|
||||||
false_func,
|
|
||||||
Clock::Internal);
|
|
||||||
#undef true_func
|
|
||||||
#undef false_func
|
|
||||||
break;
|
|
||||||
#define true_func this->template fetch_yamaha<true, false>
|
|
||||||
#define false_func this->template fetch_yamaha<false, false>
|
|
||||||
case LineMode::YamahaNoSprites:
|
|
||||||
fetch(
|
|
||||||
true_func,
|
|
||||||
false_func,
|
|
||||||
Clock::Internal);
|
|
||||||
#undef true_func
|
|
||||||
#undef false_func
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef fetch_simple
|
|
||||||
#undef fetch
|
#undef fetch
|
||||||
|
|
||||||
// TODO: the above is too macro-heavy. Simplify.
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Check for interrupt conditions.
|
// Check for interrupt conditions.
|
||||||
@ -316,8 +292,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
case ScreenMode::YamahaGraphics5:
|
case ScreenMode::YamahaGraphics5:
|
||||||
case ScreenMode::YamahaGraphics6:
|
case ScreenMode::YamahaGraphics6:
|
||||||
case ScreenMode::YamahaGraphics7:
|
case ScreenMode::YamahaGraphics7:
|
||||||
// TODO: sprites?
|
next_line_buffer.line_mode = LineMode::Yamaha;
|
||||||
next_line_buffer.line_mode = LineMode::YamahaNoSprites;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// This covers both MultiColour and Graphics modes.
|
// This covers both MultiColour and Graphics modes.
|
||||||
@ -329,6 +304,9 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
(this->screen_mode_ == ScreenMode::Blank) ||
|
(this->screen_mode_ == ScreenMode::Blank) ||
|
||||||
this->is_vertical_blank())
|
this->is_vertical_blank())
|
||||||
next_line_buffer.line_mode = LineMode::Refresh;
|
next_line_buffer.line_mode = LineMode::Refresh;
|
||||||
|
|
||||||
|
// TODO: an actual sprites-enabled flag.
|
||||||
|
Storage<personality>::begin_line(this->screen_mode_, next_line_buffer.line_mode == LineMode::Refresh, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,6 @@ enum class LineMode {
|
|||||||
Refresh,
|
Refresh,
|
||||||
SMS,
|
SMS,
|
||||||
Yamaha,
|
Yamaha,
|
||||||
YamahaNoSprites,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MemoryAccess {
|
enum class MemoryAccess {
|
||||||
@ -155,6 +154,7 @@ template <Personality personality, typename Enable = void> struct Storage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <> struct Storage<Personality::TMS9918A> {
|
template <> struct Storage<Personality::TMS9918A> {
|
||||||
|
void begin_line(ScreenMode, bool, bool) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Yamaha-specific storage.
|
// Yamaha-specific storage.
|
||||||
@ -169,6 +169,183 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
|
|||||||
uint8_t palette_entry_ = 0;
|
uint8_t palette_entry_ = 0;
|
||||||
|
|
||||||
uint8_t mode_ = 0;
|
uint8_t mode_ = 0;
|
||||||
|
|
||||||
|
/// Describes an _observable_ memory access event. i.e. anything that it is safe
|
||||||
|
/// (and convenient) to treat as atomic in between external slots.
|
||||||
|
struct Event {
|
||||||
|
/// Offset of the _beginning_ of the event. Not completely arbitrarily: this is when
|
||||||
|
/// external data must be ready by in order to take part in those slots.
|
||||||
|
int offset = 1368;
|
||||||
|
enum class Type {
|
||||||
|
External,
|
||||||
|
DataBlock,
|
||||||
|
} type = Type::External;
|
||||||
|
|
||||||
|
constexpr Event(int offset, Type type) noexcept :
|
||||||
|
offset(grauw_to_internal(offset)),
|
||||||
|
type(type) {}
|
||||||
|
|
||||||
|
constexpr Event(int offset) noexcept :
|
||||||
|
offset(grauw_to_internal(offset)) {}
|
||||||
|
|
||||||
|
constexpr Event() noexcept {}
|
||||||
|
};
|
||||||
|
const Event *next_event_ = nullptr;
|
||||||
|
void begin_line([[maybe_unused]] ScreenMode mode, bool is_refresh, [[maybe_unused]] bool sprites_enabled) {
|
||||||
|
// TODO: remove this check. It's temporary, while the Yamaha is still using the TMS fetchers.
|
||||||
|
if(mode < ScreenMode::YamahaText80) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(next_event_ == nullptr || next_event_->offset == 1368);
|
||||||
|
|
||||||
|
if(is_refresh) {
|
||||||
|
next_event_ = refresh_events;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: obey sprites_enabled flag, at least.
|
||||||
|
next_event_ = no_sprites_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage() noexcept {
|
||||||
|
// Perform sanity checks on the event lists.
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const Event *lists[] = { no_sprites_events, refresh_events, nullptr };
|
||||||
|
const Event **list = lists;
|
||||||
|
while(*list) {
|
||||||
|
const Event *cursor = *list;
|
||||||
|
++list;
|
||||||
|
|
||||||
|
while(cursor[1].offset != 1368) {
|
||||||
|
assert(cursor[1].offset > cursor[0].offset);
|
||||||
|
++cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This emulator treats position 0 as being immediately after the standard pixel area.
|
||||||
|
// i.e. offset 1282 on Grauw's http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing.png
|
||||||
|
constexpr static int grauw_to_internal(int offset) {
|
||||||
|
return (offset + 1368 - 1282) % 1368;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Event refresh_events[] = {
|
||||||
|
Event(1284), Event(1292), Event(1300), Event(1308), Event(1316), Event(1324),
|
||||||
|
Event(1334), Event(1344), Event(1352), Event(1360), Event(0), Event(8),
|
||||||
|
Event(16), Event(24), Event(32), Event(40), Event(48), Event(56),
|
||||||
|
Event(64), Event(72), Event(80), Event(88), Event(96), Event(104),
|
||||||
|
Event(112), Event(120),
|
||||||
|
|
||||||
|
Event(164), Event(172), Event(180), Event(188), Event(196), Event(204),
|
||||||
|
Event(212), Event(220), Event(228), Event(236), Event(244), Event(252),
|
||||||
|
Event(260), Event(268), Event(276), /* Refresh. */ Event(292), Event(300),
|
||||||
|
Event(308), Event(316), Event(324), Event(332), Event(340), Event(348),
|
||||||
|
Event(356), Event(364), Event(372), Event(380), Event(388), Event(396),
|
||||||
|
Event(404), /* Refresh. */ Event(420), Event(428), Event(436), Event(444),
|
||||||
|
Event(452), Event(460), Event(468), Event(476), Event(484), Event(492),
|
||||||
|
Event(500), Event(508), Event(516), Event(524), Event(532), /* Refresh. */
|
||||||
|
Event(548), Event(556), Event(564), Event(570), Event(580), Event(588),
|
||||||
|
Event(596), Event(604), Event(612), Event(620), Event(628), Event(636),
|
||||||
|
Event(644), Event(652), Event(660), /* Refresh. */ Event(676), Event(684),
|
||||||
|
Event(692), Event(700), Event(708), Event(716), Event(724), Event(732),
|
||||||
|
Event(740), Event(748), Event(756), Event(764), Event(772), Event(780),
|
||||||
|
Event(788), /* Refresh. */ Event(804), Event(812), Event(820), Event(828),
|
||||||
|
Event(836), Event(844), Event(852), Event(860), Event(868), Event(876),
|
||||||
|
Event(884), Event(892), Event(900), Event(908), Event(916), /* Refresh. */
|
||||||
|
Event(932), Event(940), Event(948), Event(956), Event(964), Event(972),
|
||||||
|
Event(980), Event(988), Event(996), Event(1004), Event(1012), Event(1020),
|
||||||
|
Event(1028), Event(1036), Event(1044), /* Refresh. */ Event(1060), Event(1068),
|
||||||
|
Event(1076), Event(1084), Event(1092), Event(1100), Event(1108), Event(1116),
|
||||||
|
Event(1124), Event(1132), Event(1140), Event(1148), Event(1156), Event(1164),
|
||||||
|
Event(1172), /* Refresh. */ Event(1188), Event(1196), Event(1204), Event(1212),
|
||||||
|
Event(1220), Event(1228),
|
||||||
|
|
||||||
|
Event(1268), Event(1276),
|
||||||
|
|
||||||
|
Event()
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Event no_sprites_events[] = {
|
||||||
|
Event(1282, Event::Type::External),
|
||||||
|
Event(1290, Event::Type::External),
|
||||||
|
Event(1298, Event::Type::External),
|
||||||
|
Event(1306, Event::Type::External),
|
||||||
|
Event(1314, Event::Type::External),
|
||||||
|
Event(1322, Event::Type::External),
|
||||||
|
Event(1332, Event::Type::External),
|
||||||
|
Event(1342, Event::Type::External),
|
||||||
|
Event(1350, Event::Type::External),
|
||||||
|
Event(1358, Event::Type::External),
|
||||||
|
Event(1366, Event::Type::External),
|
||||||
|
|
||||||
|
Event(6, Event::Type::External),
|
||||||
|
Event(14, Event::Type::External),
|
||||||
|
Event(22, Event::Type::External),
|
||||||
|
Event(30, Event::Type::External),
|
||||||
|
Event(38, Event::Type::External),
|
||||||
|
Event(46, Event::Type::External),
|
||||||
|
Event(54, Event::Type::External),
|
||||||
|
Event(62, Event::Type::External),
|
||||||
|
Event(70, Event::Type::External),
|
||||||
|
Event(78, Event::Type::External),
|
||||||
|
Event(86, Event::Type::External),
|
||||||
|
Event(94, Event::Type::External),
|
||||||
|
Event(102, Event::Type::External),
|
||||||
|
Event(110, Event::Type::External),
|
||||||
|
Event(118, Event::Type::External),
|
||||||
|
|
||||||
|
Event(162, Event::Type::External),
|
||||||
|
Event(170, Event::Type::External),
|
||||||
|
Event(182, Event::Type::External),
|
||||||
|
Event(188, Event::Type::External),
|
||||||
|
// Omitted: dummy data block. Is not observable.
|
||||||
|
Event(214, Event::Type::External),
|
||||||
|
Event(220, Event::Type::External),
|
||||||
|
|
||||||
|
Event(226, Event::Type::DataBlock), Event(246, Event::Type::External), Event(252, Event::Type::External),
|
||||||
|
Event(258, Event::Type::DataBlock), Event(278, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(290, Event::Type::DataBlock), Event(310, Event::Type::External), Event(316, Event::Type::External),
|
||||||
|
Event(322, Event::Type::DataBlock), Event(342, Event::Type::External), Event(348, Event::Type::External),
|
||||||
|
Event(354, Event::Type::DataBlock), Event(374, Event::Type::External), Event(380, Event::Type::External),
|
||||||
|
Event(386, Event::Type::DataBlock), Event(406, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(418, Event::Type::DataBlock), Event(438, Event::Type::External), Event(444, Event::Type::External),
|
||||||
|
Event(450, Event::Type::DataBlock), Event(470, Event::Type::External), Event(476, Event::Type::External),
|
||||||
|
|
||||||
|
Event(482, Event::Type::DataBlock), Event(502, Event::Type::External), Event(508, Event::Type::External),
|
||||||
|
Event(514, Event::Type::DataBlock), Event(534, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(546, Event::Type::DataBlock), Event(566, Event::Type::External), Event(572, Event::Type::External),
|
||||||
|
Event(578, Event::Type::DataBlock), Event(598, Event::Type::External), Event(604, Event::Type::External),
|
||||||
|
Event(610, Event::Type::DataBlock), Event(630, Event::Type::External), Event(636, Event::Type::External),
|
||||||
|
Event(642, Event::Type::DataBlock), Event(662, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(674, Event::Type::DataBlock), Event(694, Event::Type::External), Event(700, Event::Type::External),
|
||||||
|
Event(706, Event::Type::DataBlock), Event(726, Event::Type::External), Event(732, Event::Type::External),
|
||||||
|
|
||||||
|
Event(738, Event::Type::DataBlock), Event(758, Event::Type::External), Event(764, Event::Type::External),
|
||||||
|
Event(770, Event::Type::DataBlock), Event(790, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(802, Event::Type::DataBlock), Event(822, Event::Type::External), Event(828, Event::Type::External),
|
||||||
|
Event(834, Event::Type::DataBlock), Event(854, Event::Type::External), Event(860, Event::Type::External),
|
||||||
|
Event(866, Event::Type::DataBlock), Event(886, Event::Type::External), Event(892, Event::Type::External),
|
||||||
|
Event(898, Event::Type::DataBlock), Event(918, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(930, Event::Type::DataBlock), Event(950, Event::Type::External), Event(956, Event::Type::External),
|
||||||
|
Event(962, Event::Type::DataBlock), Event(982, Event::Type::External), Event(988, Event::Type::External),
|
||||||
|
|
||||||
|
Event(994, Event::Type::DataBlock), Event(1014, Event::Type::External), Event(1020, Event::Type::External),
|
||||||
|
Event(1026, Event::Type::DataBlock), Event(1046, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(1058, Event::Type::DataBlock), Event(1078, Event::Type::External), Event(1084, Event::Type::External),
|
||||||
|
Event(1090, Event::Type::DataBlock), Event(1110, Event::Type::External), Event(1116, Event::Type::External),
|
||||||
|
Event(1122, Event::Type::DataBlock), Event(1142, Event::Type::External), Event(1148, Event::Type::External),
|
||||||
|
Event(1154, Event::Type::DataBlock), Event(1174, Event::Type::External), // Omitted: refresh.
|
||||||
|
Event(1186, Event::Type::DataBlock), Event(1206, Event::Type::External), Event(1212, Event::Type::External),
|
||||||
|
Event(1218, Event::Type::DataBlock),
|
||||||
|
|
||||||
|
Event(1266, Event::Type::External),
|
||||||
|
Event(1274, Event::Type::External),
|
||||||
|
|
||||||
|
Event()
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Master System-specific storage.
|
// Master System-specific storage.
|
||||||
@ -207,6 +384,8 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
|
|||||||
size_t pattern_name_address_;
|
size_t pattern_name_address_;
|
||||||
size_t sprite_attribute_table_address_;
|
size_t sprite_attribute_table_address_;
|
||||||
size_t sprite_generator_table_address_;
|
size_t sprite_generator_table_address_;
|
||||||
|
|
||||||
|
void begin_line(ScreenMode, bool, bool) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <Personality personality> struct Base: public Storage<personality> {
|
template <Personality personality> struct Base: public Storage<personality> {
|
||||||
@ -475,8 +654,7 @@ template <Personality personality> struct Base: public Storage<personality> {
|
|||||||
template<bool use_end> void fetch_tms_text(int start, int end);
|
template<bool use_end> void fetch_tms_text(int start, int end);
|
||||||
template<bool use_end> void fetch_tms_character(int start, int end);
|
template<bool use_end> void fetch_tms_character(int start, int end);
|
||||||
|
|
||||||
template<bool use_end> void fetch_yamaha_refresh(int start, int end);
|
template<bool use_end> void fetch_yamaha(int start, int end);
|
||||||
template<bool use_end, bool fetch_sprites> void fetch_yamaha(int start, int end);
|
|
||||||
|
|
||||||
template<bool use_end> void fetch_sms(int start, int end);
|
template<bool use_end> void fetch_sms(int start, int end);
|
||||||
|
|
||||||
|
@ -470,148 +470,39 @@ template<bool use_end> void Base<personality>::fetch_sms(int start, int end) {
|
|||||||
|
|
||||||
// MARK: - Yamaha
|
// MARK: - Yamaha
|
||||||
|
|
||||||
// TODO.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// This emulator treats position 0 as being immediately after the standard pixel area.
|
|
||||||
// i.e. offset 1282 on Grauw's http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing.png
|
|
||||||
constexpr int grauw_to_internal(int offset) {
|
|
||||||
return (offset + 1368 - 1282) % 1368;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
template<bool use_end> void Base<personality>::fetch_yamaha_refresh(int start, int end) {
|
template<bool use_end> void Base<personality>::fetch_yamaha([[maybe_unused]] int start, int end) {
|
||||||
(void)start;
|
if constexpr (is_yamaha_vdp(personality)) {
|
||||||
(void)end;
|
/*
|
||||||
}
|
Per http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing.html :
|
||||||
|
|
||||||
template <Personality personality>
|
The major change compared to the previous mode is that now the VDP needs to fetch extra data
|
||||||
template<bool use_end, bool fetch_sprites> void Base<personality>::fetch_yamaha(int start, int end) {
|
for the bitmap rendering. These fetches happen in 32 blocks of 4 bytes (screen 5/6) or
|
||||||
/*
|
8 bytes (screen 7/8). The fetches within one block happen in burst mode. This means that
|
||||||
Per http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing.html :
|
one block takes 18 cycles (screen 5/6) or 20 cycles (screen 7/8). Though later we'll see
|
||||||
|
that the two spare cycles for screen 5/6 are not used for anything else, so for simplicity
|
||||||
|
we can say that in all bitmap modes a bitmap-fetch-block takes 20 cycles. This is even
|
||||||
|
clearer if you look at the RAS signal: this signal follows the exact same pattern in all
|
||||||
|
(bitmap) screen modes, so in screen 5/6 it remains active for two cycles longer than
|
||||||
|
strictly necessary.
|
||||||
|
|
||||||
The major change compared to the previous mode is that now the VDP needs to fetch extra data
|
Actually before these 32 blocks there's one extra dummy block. This block has the same timing
|
||||||
for the bitmap rendering. These fetches happen in 32 blocks of 4 bytes (screen 5/6) or
|
as the other blocks, but it always reads address 0x1FFFF. From an emulator point of view,
|
||||||
8 bytes (screen 7/8). The fetches within one block happen in burst mode. This means that
|
these dummy reads don't matter, it only matters that at those moments no other VRAM accesses
|
||||||
one block takes 18 cycles (screen 5/6) or 20 cycles (screen 7/8). Though later we'll see
|
can occur.
|
||||||
that the two spare cycles for screen 5/6 are not used for anything else, so for simplicity
|
*/
|
||||||
we can say that in all bitmap modes a bitmap-fetch-block takes 20 cycles. This is even
|
while(Storage<personality>::next_event_->offset < end) {
|
||||||
clearer if you look at the RAS signal: this signal follows the exact same pattern in all
|
switch(Storage<personality>::next_event_->type) {
|
||||||
(bitmap) screen modes, so in screen 5/6 it remains active for two cycles longer than
|
case Storage<personality>::Event::Type::External:
|
||||||
strictly necessary.
|
do_external_slot(Storage<personality>::next_event_->offset);
|
||||||
|
break;
|
||||||
|
|
||||||
Actually before these 32 blocks there's one extra dummy block. This block has the same timing
|
default: break;
|
||||||
as the other blocks, but it always reads address 0x1FFFF. From an emulator point of view,
|
}
|
||||||
these dummy reads don't matter, it only matters that at those moments no other VRAM accesses
|
|
||||||
can occur.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This emulator treats position 0 as being immediately after the standard pixel area.
|
++Storage<personality>::next_event_;
|
||||||
// i.e. offset 1282 on Grauw's http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing.png
|
}
|
||||||
//
|
}
|
||||||
// That being the case...
|
|
||||||
//
|
|
||||||
// Data blocks are located at:
|
|
||||||
//
|
|
||||||
// 194
|
|
||||||
|
|
||||||
/// Describes an _observable_ memory access event. i.e. anything that it is safe
|
|
||||||
/// (and convenient) to treat as atomic in between external slots.
|
|
||||||
struct Event {
|
|
||||||
/// Offset of the _beginning_ of the event. Not completely arbitrarily: this is when
|
|
||||||
/// external data must be ready by in order to take part in those slots.
|
|
||||||
int offset;
|
|
||||||
enum class Type {
|
|
||||||
External,
|
|
||||||
DataBlock,
|
|
||||||
} type;
|
|
||||||
|
|
||||||
constexpr Event(int offset, Type type) noexcept :
|
|
||||||
offset(grauw_to_internal(offset)),
|
|
||||||
type(type) {}
|
|
||||||
};
|
|
||||||
constexpr Event no_sprites_events[] = {
|
|
||||||
Event(1282, Event::Type::External),
|
|
||||||
Event(1290, Event::Type::External),
|
|
||||||
Event(1298, Event::Type::External),
|
|
||||||
Event(1306, Event::Type::External),
|
|
||||||
Event(1314, Event::Type::External),
|
|
||||||
Event(1322, Event::Type::External),
|
|
||||||
Event(1332, Event::Type::External),
|
|
||||||
Event(1342, Event::Type::External),
|
|
||||||
Event(1350, Event::Type::External),
|
|
||||||
Event(1358, Event::Type::External),
|
|
||||||
Event(1366, Event::Type::External),
|
|
||||||
|
|
||||||
Event(6, Event::Type::External),
|
|
||||||
Event(14, Event::Type::External),
|
|
||||||
Event(22, Event::Type::External),
|
|
||||||
Event(30, Event::Type::External),
|
|
||||||
Event(38, Event::Type::External),
|
|
||||||
Event(46, Event::Type::External),
|
|
||||||
Event(54, Event::Type::External),
|
|
||||||
Event(62, Event::Type::External),
|
|
||||||
Event(70, Event::Type::External),
|
|
||||||
Event(78, Event::Type::External),
|
|
||||||
Event(86, Event::Type::External),
|
|
||||||
Event(94, Event::Type::External),
|
|
||||||
Event(102, Event::Type::External),
|
|
||||||
Event(110, Event::Type::External),
|
|
||||||
Event(118, Event::Type::External),
|
|
||||||
|
|
||||||
Event(162, Event::Type::External),
|
|
||||||
Event(170, Event::Type::External),
|
|
||||||
Event(182, Event::Type::External),
|
|
||||||
Event(188, Event::Type::External),
|
|
||||||
// Omitted: dummy data block. Is not observable.
|
|
||||||
Event(214, Event::Type::External),
|
|
||||||
Event(220, Event::Type::External),
|
|
||||||
|
|
||||||
Event(226, Event::Type::DataBlock), Event(246, Event::Type::External), Event(252, Event::Type::External),
|
|
||||||
Event(258, Event::Type::DataBlock), Event(278, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(290, Event::Type::DataBlock), Event(310, Event::Type::External), Event(316, Event::Type::External),
|
|
||||||
Event(322, Event::Type::DataBlock), Event(342, Event::Type::External), Event(348, Event::Type::External),
|
|
||||||
Event(354, Event::Type::DataBlock), Event(374, Event::Type::External), Event(380, Event::Type::External),
|
|
||||||
Event(386, Event::Type::DataBlock), Event(406, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(418, Event::Type::DataBlock), Event(438, Event::Type::External), Event(444, Event::Type::External),
|
|
||||||
Event(450, Event::Type::DataBlock), Event(470, Event::Type::External), Event(476, Event::Type::External),
|
|
||||||
|
|
||||||
Event(482, Event::Type::DataBlock), Event(502, Event::Type::External), Event(508, Event::Type::External),
|
|
||||||
Event(514, Event::Type::DataBlock), Event(534, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(546, Event::Type::DataBlock), Event(566, Event::Type::External), Event(572, Event::Type::External),
|
|
||||||
Event(578, Event::Type::DataBlock), Event(598, Event::Type::External), Event(604, Event::Type::External),
|
|
||||||
Event(610, Event::Type::DataBlock), Event(630, Event::Type::External), Event(636, Event::Type::External),
|
|
||||||
Event(642, Event::Type::DataBlock), Event(662, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(674, Event::Type::DataBlock), Event(694, Event::Type::External), Event(700, Event::Type::External),
|
|
||||||
Event(706, Event::Type::DataBlock), Event(726, Event::Type::External), Event(732, Event::Type::External),
|
|
||||||
|
|
||||||
Event(738, Event::Type::DataBlock), Event(758, Event::Type::External), Event(764, Event::Type::External),
|
|
||||||
Event(770, Event::Type::DataBlock), Event(790, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(802, Event::Type::DataBlock), Event(822, Event::Type::External), Event(828, Event::Type::External),
|
|
||||||
Event(834, Event::Type::DataBlock), Event(854, Event::Type::External), Event(860, Event::Type::External),
|
|
||||||
Event(866, Event::Type::DataBlock), Event(886, Event::Type::External), Event(892, Event::Type::External),
|
|
||||||
Event(898, Event::Type::DataBlock), Event(918, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(930, Event::Type::DataBlock), Event(950, Event::Type::External), Event(956, Event::Type::External),
|
|
||||||
Event(962, Event::Type::DataBlock), Event(982, Event::Type::External), Event(988, Event::Type::External),
|
|
||||||
|
|
||||||
Event(994, Event::Type::DataBlock), Event(1014, Event::Type::External), Event(1020, Event::Type::External),
|
|
||||||
Event(1026, Event::Type::DataBlock), Event(1046, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(1058, Event::Type::DataBlock), Event(1078, Event::Type::External), Event(1084, Event::Type::External),
|
|
||||||
Event(1090, Event::Type::DataBlock), Event(1110, Event::Type::External), Event(1116, Event::Type::External),
|
|
||||||
Event(1122, Event::Type::DataBlock), Event(1142, Event::Type::External), Event(1148, Event::Type::External),
|
|
||||||
Event(1154, Event::Type::DataBlock), Event(1174, Event::Type::External), // Omitted: refresh.
|
|
||||||
Event(1186, Event::Type::DataBlock), Event(1206, Event::Type::External), Event(1212, Event::Type::External),
|
|
||||||
Event(1218, Event::Type::DataBlock),
|
|
||||||
|
|
||||||
Event(1266, Event::Type::External),
|
|
||||||
Event(1274, Event::Type::External),
|
|
||||||
};
|
|
||||||
|
|
||||||
(void)start;
|
|
||||||
(void)end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Mega Drive
|
// MARK: - Mega Drive
|
||||||
|
Loading…
Reference in New Issue
Block a user