1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/env python3
"""Find K and N values for boot ROM fine-tune delay that give DIV=$AB and LY=$0A."""
return , 1, 0
, , =
return , , - *
, , =
return None
= * //
= %
return
# From empirical measurement: K=1, N=60510 → DIV=$A0, LY=$0A
# At K=1, N=60000, hold=32: total_M = 5134835
# Each N adds 7 M-cycles, so at N=60510: total ≈ 5134835 + 7*510 = 5138405
# B-loop adds 4K+1 M, HL-loop adds 7N+2 M, overhead 0 M
# Total = C + (4K+1) + (7N+2) where C is the fixed cost from main loop
# At K=1, N=60510: total = C + 5 + 423572 = C + 423577
# DIV = floor(total_T / 256) & 0xFF = floor(4*total_M / 256) & 0xFF = floor(total_M/64) & 0xFF
# DIV=$A0 means total_M mod 16384 ∈ [0xA0*64, 0xA0*64+63] = [10240, 10303]
# LY = scanline counter. total_M mod 17556 determines LY.
# LY=$0A window is empirically ~106 M-cycles wide.
# Approach: Search D = 4*(K-1) + 7*(N-60510) such that:
# (T0 + D) mod 16384 ∈ [0xAB*64, 0xAB*64+63] (DIV=$AB)
# (T0 + D) mod 17556 ∈ [T0%17556 - 53, T0%17556 + 53] (LY stays $0A)
# We don't know exact T0, but T0 % 16384 ∈ [10240, 10303].
# Use the measurement: at N=60510, K=1, DIV=$A0 → let's assume T0%16384 = 10270 (estimated).
# And T0 % 17556 is in the LY=$0A window center.
# More robust: search all (K, N) where D = 4*(K-1) + 7*(N-60510)
# and D mod 16384 ∈ [target_div_lo - t0_mod, target_div_hi - t0_mod]
# and D mod 17556 ∈ [-53, 53]
# From data: at K=12, N=60500: DIV=$9F, LY=$0A. At K=39, N=60500: DIV=$A1, LY=$0A.
# LY=$0A window at N=60500 spans K=12..39 = 28 K = 112 M-cycles = 112 mod 17556 shift.
# Key: D % 16384 must be in [target_range] and D % 17556 must be near 0.
# Since gcd(16384, 17556) = 4, CRT period = lcm = 71917056.
# Instead of CRT, just iterate over reasonable (K, N) and check.
# K ∈ [1, 255], N ∈ [1, 65535]
# D = 4*(K-1) + 7*(N-60510)
# For DIV=$AB: need (T0 + D) / 64 & 0xFF == 0xAB
# T0/64 & 0xFF = 0xA0, so (T0+D)/64 & 0xFF = 0xAB
# D/64 & 0xFF must shift by $0B = 11
# D mod 16384 ∈ [11*64, 11*64+63] = [704, 767]
# BUT this ignores the exact T0 value within its 64-value range.
# More precisely: D mod 16384 ∈ [704 - (T0%64), 767 - (T0%64) + 63]
# Since T0%64 is unknown (0-63), D mod 16384 ∈ [704-63, 767+0] = [641, 767]
# For LY=$0A: D mod 17556 ∈ [-53, 53] (to stay within the ~106 M-cycle window)
# Search D = 16384*a + r where r ∈ [641, 767] and D % 17556 ∈ [-53, 53]
# D can be decomposed as 4*(K-1) + 7*(N-60510)
# First find valid D values
# Each hold iteration adds ~35113 M-cycles.
# Changing hold by 1 shifts total by ±35113, changing D by ±35113.
# So for hold H (vs baseline 32): D_offset = (H-32) * 35113
# New D = D_offset + 4*(K-1) + 7*(N-60510)
# Need: (T0 + D) mod 16384 ∈ [10944, 11007] (DIV=$AB)
# Need: (T0 + D) mod 17556 in LY=$0A window
# T0 is at hold=32, K=1, N=60510
# T0 mod 16384 ∈ [10240, 10303] (DIV=$A0)
# T0 mod 17556 = center of LY=$0A window
# For different holds, the offset changes:
# D_total = 35113*(H-32) + 4*(K-1) + 7*(N-60510)
# Need D_total mod 16384 ∈ [704, 767] (DIV shift from $A0 to $AB)
# Need D_total mod 17556 ∈ [-53, 53]
# 35113 mod 16384 = 35113 - 2*16384 = 2345
# 35113 mod 17556 = 35113 - 17556 = 17557. Wait: 35113 - 17556 = 17557. 17557 - 17556 = 1.
# So 35113 mod 17556 = 1!
# 35113 mod 17556 = 1! This means each hold iteration shifts LY by just 1 M-cycle.
# After H-32 extra hold iterations, the LY shift is (H-32) mod 17556.
# And the DIV shift is ((H-32)*2345) mod 16384.
# So for hold H:
# D_total mod 16384 = (H-32)*2345 + 4*(K-1) + 7*(N-60510)) mod 16384
# D_total mod 17556 = (H-32)*1 + 4*(K-1) + 7*(N-60510)) mod 17556
# Need D_total mod 16384 ∈ [704, 767]
# Need D_total mod 17556 ∈ [-53, 53]
# Since hold change barely affects LY (1 M per hold), the N range stays similar.
# The DIV shift from hold change: (H-32)*2345 mod 16384.
# We need: ((H-32)*2345 + 4*(K-1) + 7*(N-60510)) mod 16384 ∈ [704, 767]
# So: (4*(K-1) + 7*(N-60510)) mod 16384 ∈ [704 - (H-32)*2345, 767 - (H-32)*2345] (mod 16384)
# And for LY: (H-32 + 4*(K-1) + 7*(N-60510)) mod 17556 ∈ [-53, 53]
# Let X = 4*(K-1) + 7*(N-60510) = 4*dk + 7*dn
# Need X mod 16384 = (704 - (H-32)*2345) mod 16384 (within range)
# Need X mod 17556 = (-(H-32)) mod 17556 (within range ±53)
# For LY: X mod 17556 ≈ -(H-32) ± 53
# For small |H-32|, X mod 17556 is near -(H-32).
# For H=32: X mod 16384 ∈ [704, 767], X mod 17556 ∈ [-53, 53]. (Already proven impossible)
# For H=33: X mod 16384 ∈ [704-2345, 767-2345] mod 16384 = [-1641, -1578] = [14743, 14806]
# X mod 17556 ∈ [-1-53, -1+53] = [-54, 52]
# For H=31: X mod 16384 ∈ [704+2345, 767+2345] = [3049, 3112]
# X mod 17556 ∈ [1-53, 1+53] = [-52, 54]
=
= % 16384
= - 32 # each hold adds 1 to LY mod
= % 16384
= % 16384
# Handle wraparound
=
=
= -
= - 53
= + 53
= % 17556
continue
=
continue
# Try X_base and X_base - lcm_val
= 16384 * 17556 //
= - 4 *
= // 7
= 60510 +
= 1 +
break
# prefer hold close to 32