1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-30 04:50:08 +00:00

Start pivoting to a more natural expression of TMS patterns.

This commit is contained in:
Thomas Harte 2023-02-03 23:06:27 -05:00
parent d41081c59f
commit 34722bae89
2 changed files with 93 additions and 90 deletions

View File

@ -823,6 +823,14 @@ template <Personality personality> struct Base: public Storage<personality> {
queued_access_ = MemoryAccess::None; queued_access_ = MemoryAccess::None;
} }
/// Helper for TMS dispatches; contains a switch statement with cases 0 to 170, each of the form:
///
/// if constexpr (use_end && end == n) return; [[fallthrough]]; case n: fetcher.fetch<n>();
///
/// i.e. it provides standard glue to enter a fetch sequence at any point, while the fetches themselves are templated on the cycle
/// at which they appear for neater expression.
template<bool use_end, typename Fetcher> void dispatch(Fetcher &fetcher, int start, int end);
// Various fetchers. // Various fetchers.
template<bool use_end> void fetch_tms_refresh(LineBuffer &, int y, int start, int end); template<bool use_end> void fetch_tms_refresh(LineBuffer &, int y, int start, int end);
template<bool use_end> void fetch_tms_text(LineBuffer &, int y, int start, int end); template<bool use_end> void fetch_tms_text(LineBuffer &, int y, int start, int end);

View File

@ -73,105 +73,100 @@
// MARK: - TMS9918 // MARK: - TMS9918
template <Personality personality> template <Personality personality>
template<bool use_end> void Base<personality>::fetch_tms_refresh(LineBuffer &, int, int start, int end) { template<bool use_end, typename Fetcher> void Base<personality>::dispatch(Fetcher &fetcher, int start, int end) {
#define refresh(location) \ #define index(n) \
slot(location): \ if(use_end && end == n) return; \
external_slot(location+1); [[fallthrough]]; \
case n: fetcher.template fetch<n>();
#define refreshes_2(location) \
refresh(location); \
refresh(location+2);
#define refreshes_4(location) \
refreshes_2(location); \
refreshes_2(location+4);
#define refreshes_8(location) \
refreshes_4(location); \
refreshes_4(location+8);
switch(start) { switch(start) {
default: assert(false); default: assert(false);
index(0); index(1); index(2); index(3); index(4); index(5); index(6); index(7); index(8); index(9);
/* 44 external slots */ index(10); index(11); index(12); index(13); index(14); index(15); index(16); index(17); index(18); index(19);
external_slots_32(0) index(20); index(21); index(22); index(23); index(24); index(25); index(26); index(27); index(28); index(29);
external_slots_8(32) index(30); index(31); index(32); index(33); index(34); index(35); index(36); index(37); index(38); index(39);
external_slots_4(40) index(40); index(41); index(42); index(43); index(44); index(45); index(46); index(47); index(48); index(49);
index(50); index(51); index(52); index(53); index(54); index(55); index(56); index(57); index(58); index(59);
/* 64 refresh/external slot pairs (= 128 windows) */ index(60); index(61); index(62); index(63); index(64); index(65); index(66); index(67); index(68); index(69);
refreshes_8(44); index(70); index(71); index(72); index(73); index(74); index(75); index(76); index(77); index(78); index(79);
refreshes_8(60); index(80); index(81); index(82); index(83); index(84); index(85); index(86); index(87); index(88); index(89);
refreshes_8(76); index(90); index(91); index(92); index(93); index(94); index(95); index(96); index(97); index(98); index(99);
refreshes_8(92); index(100); index(101); index(102); index(103); index(104); index(105); index(106); index(107); index(108); index(109);
refreshes_8(108); index(110); index(111); index(112); index(113); index(114); index(115); index(116); index(117); index(118); index(119);
refreshes_8(124); index(120); index(121); index(122); index(123); index(124); index(125); index(126); index(127); index(128); index(129);
refreshes_8(140); index(130); index(131); index(132); index(133); index(134); index(135); index(136); index(137); index(138); index(139);
refreshes_8(156); index(140); index(141); index(142); index(143); index(144); index(145); index(146); index(147); index(148); index(149);
index(150); index(151); index(152); index(153); index(154); index(155); index(156); index(157); index(158); index(159);
return; index(160); index(161); index(162); index(163); index(164); index(165); index(166); index(167); index(168); index(169);
index(170);
} }
#undef refreshes_8 #undef index
#undef refreshes_4 }
#undef refreshes_2
#undef refresh namespace {
template <Personality personality>
struct RefreshFetcher {
RefreshFetcher(Base<personality> *base) : base(base) {}
template <int cycle> void fetch() {
// Do 44 external slots in a block, then treat every other slot as external.
if(cycle < 44 || (cycle&1)) {
base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
}
}
Base<personality> *const base;
};
template <Personality personality>
struct TextFetcher {
using AddressT = typename Base<personality>::AddressT;
TextFetcher(Base<personality> *base, LineBuffer &buffer, int y) :
base(base),
line_buffer(buffer),
row_base(base->pattern_name_address_ & (0x3c00 | size_t(y >> 3) * 40)),
row_offset(base->pattern_generator_table_address_ & (0x3800 | (y & 7))) {}
template <int cycle> void fetch() {
// The first 47 and the final 4 slots are external.
if constexpr (cycle < 47 || cycle >= 167) {
base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
return;
}
// For the 120 slots in between follow a three-step pattern of:
if constexpr (cycle >= 47) {
constexpr int offset = cycle - 47;
constexpr auto column = AddressT(offset / 3);
switch(offset % 3) {
case 0: line_buffer.names[column].offset = base->ram_[row_base + column]; break; // (1) fetch tile name.
case 1: base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle)); break; // (2) external slot.
case 2: line_buffer.patterns[column][0] = base->ram_[row_offset + size_t(line_buffer.names[column].offset << 3)]; break; // (3) fetch tile pattern.
}
}
}
Base<personality> *const base;
LineBuffer &line_buffer;
const AddressT row_base;
const AddressT row_offset;
};
}
template <Personality personality>
template<bool use_end> void Base<personality>::fetch_tms_refresh(LineBuffer &, int, int start, int end) {
RefreshFetcher refresher(this);
dispatch<use_end>(refresher, start, end);
} }
template <Personality personality> template <Personality personality>
template<bool use_end> void Base<personality>::fetch_tms_text(LineBuffer &line_buffer, int y, int start, int end) { template<bool use_end> void Base<personality>::fetch_tms_text(LineBuffer &line_buffer, int y, int start, int end) {
#define fetch_tile_name(location, column) slot(location): line_buffer.names[column].offset = ram_[row_base + column]; TextFetcher fetcher(this, line_buffer, y);
#define fetch_tile_pattern(location, column) slot(location): line_buffer.patterns[column][0] = ram_[row_offset + size_t(line_buffer.names[column].offset << 3)]; dispatch<use_end>(fetcher, start, end);
#define fetch_column(location, column) \
fetch_tile_name(location, column); \
external_slot(location+1); \
fetch_tile_pattern(location+2, column);
#define fetch_columns_2(location, column) \
fetch_column(location, column); \
fetch_column(location+3, column+1);
#define fetch_columns_4(location, column) \
fetch_columns_2(location, column); \
fetch_columns_2(location+6, column+2);
#define fetch_columns_8(location, column) \
fetch_columns_4(location, column); \
fetch_columns_4(location+12, column+4);
const size_t row_base = pattern_name_address_ & (0x3c00 | size_t(y >> 3) * 40);
const size_t row_offset = pattern_generator_table_address_ & (0x3800 | (y & 7));
switch(start) {
default: assert(false);
/* 47 external slots (= 47 windows) */
external_slots_32(0)
external_slots_8(32)
external_slots_4(40)
external_slots_2(44)
external_slot(46)
/* 40 column fetches (= 120 windows) */
fetch_columns_8(47, 0);
fetch_columns_8(71, 8);
fetch_columns_8(95, 16);
fetch_columns_8(119, 24);
fetch_columns_8(143, 32);
/* 5 more external slots */
external_slots_4(167);
external_slot(171);
return;
}
#undef fetch_columns_8
#undef fetch_columns_4
#undef fetch_columns_2
#undef fetch_column
#undef fetch_tile_pattern
#undef fetch_tile_name
} }
template <Personality personality> template <Personality personality>