mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Reorient sequencers around HSYNC.
This commit is contained in:
parent
224c79c492
commit
e0a5d9f31c
@ -16,7 +16,15 @@
|
|||||||
operations for the period: start <= time < end.
|
operations for the period: start <= time < end.
|
||||||
2) times are measured relative to a 172-cycles-per-line clock (so: they directly
|
2) times are measured relative to a 172-cycles-per-line clock (so: they directly
|
||||||
count access windows on the TMS and Master System).
|
count access windows on the TMS and Master System).
|
||||||
3) time 0 is the beginning of the access window immediately after the last pattern/data
|
3) within each sequencer, time 0 is the access window that straddles the beginning of
|
||||||
|
horizontal sync. Which, conveniently, is the place to which Grauw's timing diagrams
|
||||||
|
are aligned.
|
||||||
|
4) all of these functions are templated with a `use_end` parameter. That will be true if
|
||||||
|
end is < 172, false otherwise. So functions can use it to eliminate should-exit-not checks,
|
||||||
|
for the more usual path of execution.
|
||||||
|
|
||||||
|
[Historically:
|
||||||
|
position 0 was the beginning of the access window immediately after the last pattern/data
|
||||||
block fetch that would contribute to this line, in a normal 32-column mode. So:
|
block fetch that would contribute to this line, in a normal 32-column mode. So:
|
||||||
|
|
||||||
* it's cycle 309 on Mattias' TMS diagram;
|
* it's cycle 309 on Mattias' TMS diagram;
|
||||||
@ -26,9 +34,8 @@
|
|||||||
That division point was selected, albeit arbitrarily, because it puts all the tile
|
That division point was selected, albeit arbitrarily, because it puts all the tile
|
||||||
fetches for a single line into the same [0, 171] period.
|
fetches for a single line into the same [0, 171] period.
|
||||||
|
|
||||||
4) all of these functions are templated with a `use_end` parameter. That will be true if
|
I'm moving away from this per the desire not to have V9938 output straddle two lines if horizontally-adjusted,
|
||||||
end is < 172, false otherwise. So functions can use it to eliminate should-exit-not checks,
|
amongst other concerns.]
|
||||||
for the more usual path of execution.
|
|
||||||
|
|
||||||
Provided for the benefit of the methods below:
|
Provided for the benefit of the methods below:
|
||||||
|
|
||||||
@ -64,7 +71,8 @@ template<bool use_end, typename SequencerT> void Base<personality>::dispatch(Seq
|
|||||||
#define index(n) \
|
#define index(n) \
|
||||||
if(use_end && end == n) return; \
|
if(use_end && end == n) return; \
|
||||||
[[fallthrough]]; \
|
[[fallthrough]]; \
|
||||||
case n: fetcher.template fetch<n>();
|
case n: fetcher.template fetch<(n + 171 - 16) % 171>();
|
||||||
|
// `template fetch` call includes an in-place internal -> sync-aligned conversion for now, during transition.
|
||||||
|
|
||||||
switch(start) {
|
switch(start) {
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
@ -382,7 +390,7 @@ struct RefreshSequencer {
|
|||||||
RefreshSequencer(Base<personality> *base) : base(base) {}
|
RefreshSequencer(Base<personality> *base) : base(base) {}
|
||||||
|
|
||||||
template <int cycle> void fetch() {
|
template <int cycle> void fetch() {
|
||||||
if(cycle < 44 || (cycle&1)) {
|
if(cycle < 26 || (cycle & 1) || cycle >= 154) {
|
||||||
base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,13 +403,13 @@ struct TextSequencer {
|
|||||||
template <typename... Args> TextSequencer(Args&&... args) : fetcher(std::forward<Args>(args)...) {}
|
template <typename... Args> TextSequencer(Args&&... args) : fetcher(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
template <int cycle> void fetch() {
|
template <int cycle> void fetch() {
|
||||||
// The first 47 and the final 4 slots are external.
|
// The first 30 and the final 4 slots are external.
|
||||||
if constexpr (cycle < 47 || cycle >= 167) {
|
if constexpr (cycle < 30 || cycle >= 150) {
|
||||||
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// For the 120 slots in between follow a three-step pattern of:
|
// For the 120 slots in between follow a three-step pattern of:
|
||||||
constexpr int offset = cycle - 47;
|
constexpr int offset = cycle - 30;
|
||||||
constexpr auto column = AddressT(offset / 3);
|
constexpr auto column = AddressT(offset / 3);
|
||||||
switch(offset % 3) {
|
switch(offset % 3) {
|
||||||
case 0: fetcher.fetch_name(column); break; // (1) fetch tile name.
|
case 0: fetcher.fetch_name(column); break; // (1) fetch tile name.
|
||||||
@ -422,43 +430,30 @@ struct CharacterSequencer {
|
|||||||
sprite_fetcher(std::forward<Args>(args)...) {}
|
sprite_fetcher(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
template <int cycle> void fetch() {
|
template <int cycle> void fetch() {
|
||||||
if(cycle < 2) {
|
if(cycle < 5) {
|
||||||
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle == 2) {
|
if(cycle == 5) {
|
||||||
// Fetch: y0, x0, n0, c0, pat0a, pat0b, y1, x1, n1, c1, pat1a, pat1b, y2, x2.
|
|
||||||
sprite_fetcher.fetch_location(0);
|
|
||||||
sprite_fetcher.fetch_pattern(0);
|
|
||||||
sprite_fetcher.fetch_location(1);
|
|
||||||
sprite_fetcher.fetch_pattern(1);
|
|
||||||
sprite_fetcher.fetch_location(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cycle > 16 && cycle < 21) {
|
|
||||||
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cycle == 21) {
|
|
||||||
// Fetch: n1, c2, pat2a, pat2b, y3, x3, n3, c3, pat3a, pat3b.
|
// Fetch: n1, c2, pat2a, pat2b, y3, x3, n3, c3, pat3a, pat3b.
|
||||||
sprite_fetcher.fetch_pattern(2);
|
sprite_fetcher.fetch_pattern(2);
|
||||||
sprite_fetcher.fetch_location(3);
|
sprite_fetcher.fetch_location(3);
|
||||||
sprite_fetcher.fetch_pattern(3);
|
sprite_fetcher.fetch_pattern(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle >= 31 && cycle < 35) {
|
if(cycle > 14 && cycle < 19) {
|
||||||
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cycles 35 to 43: fetch 8 new sprite Y coordinates, to begin selecting sprites for next line.
|
// Fetch 8 new sprite Y coordinates, to begin selecting sprites for next line.
|
||||||
if(cycle == 35) {
|
if(cycle == 19) {
|
||||||
sprite_fetcher.fetch_y(0); sprite_fetcher.fetch_y(1); sprite_fetcher.fetch_y(2); sprite_fetcher.fetch_y(3);
|
sprite_fetcher.fetch_y(0); sprite_fetcher.fetch_y(1); sprite_fetcher.fetch_y(2); sprite_fetcher.fetch_y(3);
|
||||||
sprite_fetcher.fetch_y(4); sprite_fetcher.fetch_y(5); sprite_fetcher.fetch_y(6); sprite_fetcher.fetch_y(7);
|
sprite_fetcher.fetch_y(4); sprite_fetcher.fetch_y(5); sprite_fetcher.fetch_y(6); sprite_fetcher.fetch_y(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest of line: tiles themselves, plus some additional potential sprites.
|
// Body of line: tiles themselves, plus some additional potential sprites.
|
||||||
if(cycle >= 43) {
|
if(cycle >= 27 && cycle < 155) {
|
||||||
constexpr int offset = cycle - 43;
|
constexpr int offset = cycle - 27;
|
||||||
constexpr int block = offset >> 2;
|
constexpr int block = offset >> 2;
|
||||||
constexpr int sub_block = offset & 3;
|
constexpr int sub_block = offset & 3;
|
||||||
switch(sub_block) {
|
switch(sub_block) {
|
||||||
@ -478,6 +473,19 @@ struct CharacterSequencer {
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cycle >= 155 && cycle < 157) {
|
||||||
|
character_fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cycle == 157) {
|
||||||
|
// Fetch: y0, x0, n0, c0, pat0a, pat0b, y1, x1, n1, c1, pat1a, pat1b, y2, x2.
|
||||||
|
sprite_fetcher.fetch_location(0);
|
||||||
|
sprite_fetcher.fetch_pattern(0);
|
||||||
|
sprite_fetcher.fetch_location(1);
|
||||||
|
sprite_fetcher.fetch_pattern(1);
|
||||||
|
sprite_fetcher.fetch_location(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using AddressT = typename Base<personality>::AddressT;
|
using AddressT = typename Base<personality>::AddressT;
|
||||||
@ -511,37 +519,32 @@ template <Personality personality>
|
|||||||
struct SMSSequencer {
|
struct SMSSequencer {
|
||||||
template <typename... Args> SMSSequencer(Args&&... args) : fetcher(std::forward<Args>(args)...) {}
|
template <typename... Args> SMSSequencer(Args&&... args) : fetcher(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
|
// Cf. https://www.smspower.org/forums/16485-GenesisMode4VRAMTiming with this implementation pegging
|
||||||
|
// window 0 to HSYNC low.
|
||||||
template <int cycle> void fetch() {
|
template <int cycle> void fetch() {
|
||||||
if(!cycle) {
|
if(cycle < 3) {
|
||||||
fetcher.fetch_sprite(0);
|
|
||||||
fetcher.fetch_sprite(1);
|
|
||||||
fetcher.fetch_sprite(2);
|
|
||||||
fetcher.fetch_sprite(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cycle >= 12 && cycle < 17) {
|
|
||||||
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle == 17) {
|
if(cycle == 3) {
|
||||||
fetcher.fetch_sprite(4);
|
fetcher.fetch_sprite(4);
|
||||||
fetcher.fetch_sprite(5);
|
fetcher.fetch_sprite(5);
|
||||||
fetcher.fetch_sprite(6);
|
fetcher.fetch_sprite(6);
|
||||||
fetcher.fetch_sprite(7);
|
fetcher.fetch_sprite(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle == 29 || cycle == 30) {
|
if(cycle == 15 || cycle == 16) {
|
||||||
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle == 31) {
|
if(cycle == 17) {
|
||||||
fetcher.posit_sprite(0); fetcher.posit_sprite(1); fetcher.posit_sprite(2); fetcher.posit_sprite(3);
|
fetcher.posit_sprite(0); fetcher.posit_sprite(1); fetcher.posit_sprite(2); fetcher.posit_sprite(3);
|
||||||
fetcher.posit_sprite(4); fetcher.posit_sprite(5); fetcher.posit_sprite(6); fetcher.posit_sprite(7);
|
fetcher.posit_sprite(4); fetcher.posit_sprite(5); fetcher.posit_sprite(6); fetcher.posit_sprite(7);
|
||||||
fetcher.posit_sprite(8); fetcher.posit_sprite(9); fetcher.posit_sprite(10); fetcher.posit_sprite(11);
|
fetcher.posit_sprite(8); fetcher.posit_sprite(9); fetcher.posit_sprite(10); fetcher.posit_sprite(11);
|
||||||
fetcher.posit_sprite(12); fetcher.posit_sprite(13); fetcher.posit_sprite(14); fetcher.posit_sprite(15);
|
fetcher.posit_sprite(12); fetcher.posit_sprite(13); fetcher.posit_sprite(14); fetcher.posit_sprite(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle >= 39 && cycle < 167) {
|
if(cycle >= 25 && cycle < 153) {
|
||||||
constexpr int offset = cycle - 39;
|
constexpr int offset = cycle - 39;
|
||||||
constexpr int block = offset >> 2;
|
constexpr int block = offset >> 2;
|
||||||
constexpr int sub_block = offset & 3;
|
constexpr int sub_block = offset & 3;
|
||||||
@ -563,7 +566,18 @@ struct SMSSequencer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle >= 167) {
|
if(cycle >= 153 && cycle < 157) {
|
||||||
|
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cycle == 157) {
|
||||||
|
fetcher.fetch_sprite(0);
|
||||||
|
fetcher.fetch_sprite(1);
|
||||||
|
fetcher.fetch_sprite(2);
|
||||||
|
fetcher.fetch_sprite(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cycle >= 169) {
|
||||||
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
fetcher.base->do_external_slot(to_internal<personality, Clock::TMSMemoryWindow>(cycle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user