1// cc -o /tmp/gtf -g gtf.c -Wall
2
3
4#include <mach/mach.h>
5#include <mach/thread_switch.h>
6#include <sys/file.h>
7#include <sys/stat.h>
8#include <math.h>
9#include <unistd.h>
10#include <string.h>
11#include <stdio.h>
12#include <stdlib.h>
13
14
15__private_extern__ float
16ratioOver( float a, float b )
17{
18    if( a > b)
19        return( a / b );
20    else
21        return( b / a );
22}
23
24static int
25IODisplayGetCVTSyncWidth( int horizontalActive, int verticalActive )
26{
27    // CVT Table 2
28    enum {
29        kCVTAspect4By3    = 4,
30        kCVTAspect16By9   = 5,
31        kCVTAspect16By10  = 6,
32        kCVTAspect5By4    = 7,
33        kCVTAspect15By9   = 7,
34        kCVTAspectUnknown = 10
35    };
36
37    float ratio = ((float) horizontalActive) / ((float) verticalActive);
38
39    if (ratioOver(ratio, 4.0 / 3.0) <= 1.03125)
40        return (kCVTAspect4By3);
41
42    if (ratioOver(ratio, 16.0 / 9.0) <= 1.03125)
43        return (kCVTAspect16By9);
44
45    if (ratioOver(ratio, 16.0 / 10.0) <= 1.03125)
46        return (kCVTAspect16By10);
47
48    if (ratioOver(ratio, 5.0 / 4.0) <= 1.03125)
49        return (kCVTAspect5By4);
50
51    if (ratioOver(ratio, 15.0 / 9.0) <= 1.03125)
52        return (kCVTAspect15By9);
53
54    return (kCVTAspectUnknown);
55}
56
57//FromRefreshRate
58// 7.3
59void GenTiming ( int requestedWidth, int requestedHeight,
60                 float frameRate, boolean_t needInterlace,
61                 int genType )
62{
63    int         charSize = 8;
64
65    float       m = 600;  // % / kHz;
66    float       c = 40;   // %
67    float       k = 128;
68    float       j = 20;   // %
69
70    float       cPrime = ((c - j) * k / 256) + j;
71    float       mPrime = k / 256 * m;
72
73    float       fieldRate;                                              // V_FIELD_RATE_RQD
74    // 7.
75    float       interlace = needInterlace ? 0.5 : 0.0;
76    float       interlaceFactor = needInterlace ? 2.0 : 1.0;
77
78    // 1.
79    fieldRate = frameRate * interlaceFactor;
80
81    // 3.
82    int         leftMargin = 0;
83    int         rightMargin = 0;
84    // 4.
85    int         horizontalActive = roundf(requestedWidth / charSize) * charSize
86                                    + leftMargin + rightMargin;         // TOTAL_ACTIVE_PIXELS
87
88    // 5.
89    int         verticalActive = roundf(requestedHeight / interlaceFactor);     // V_LINES_RND
90    // 6.
91    int         topMargin = 0;
92    int         bottomMargin = 0;
93
94    int         verticalSyncWidth;                                      // V_SYNC_RND
95    int         verticalSyncAndBackPorch;                               // V_SYNC_BP
96    int         verticalSyncFrontPorch;
97    int         horizontalTotal;                                        // TOTAL_PIXELS
98    int         horizontalBlanking;                                     // H_BLANK
99    int         horizontalSyncWidth;                                    // H_SYNC_PIXELS
100
101
102    if (0 == genType)
103        verticalSyncWidth = 3;
104    else
105        verticalSyncWidth = IODisplayGetCVTSyncWidth(horizontalActive, verticalActive * interlaceFactor);
106
107    if (0 == genType)           /******************************* GTF */
108
109    {
110        float horizontalSyncPercent = 8.0/100.0;                        // H_SYNC_PER
111        float verticalSyncAndBackPorchTime = 550e-6;                    // MIN_VSYNC_BP
112        int   minVerticalFrontPorch = 1;                                // MIN_V_PORCH_RND
113        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
114        float verticalFieldTotal;                                       // TOTAL_V_LINES
115        float estimatedFieldRate;                                       // V_FIELD_RATE_EST
116
117        // 7.
118        estimatedHorizontalPeriod =
119            ((1 / fieldRate) - verticalSyncAndBackPorchTime)
120            / (verticalActive + (2 * topMargin) + minVerticalFrontPorch + interlace);
121
122        // 8.
123        verticalSyncAndBackPorch = roundf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod);
124        verticalSyncFrontPorch = minVerticalFrontPorch;
125
126//      printf("estimatedHorizontalPeriod %.9f us, verticalSyncAndBackPorch %d\n",
127//                  estimatedHorizontalPeriod*1e6, verticalSyncAndBackPorch);
128
129        // 10.
130        verticalFieldTotal = verticalActive + topMargin + bottomMargin
131                            + verticalSyncAndBackPorch + interlace + minVerticalFrontPorch;
132        // 11.
133        estimatedFieldRate = 1.0 / estimatedHorizontalPeriod / verticalFieldTotal;
134
135//    printf("verticalFieldTotal %.9f, estimatedFieldRate %.9f\n",
136//                      verticalFieldTotal, estimatedFieldRate);
137
138        // 12.
139        float hPeriod = estimatedHorizontalPeriod / (fieldRate / estimatedFieldRate);
140
141        printf("hPeriod %.9f us, ", hPeriod*1e6);
142        printf("hFreq %.9f kHz\n", 1/hPeriod/1e3);
143
144        // 18.
145        float idealDutyCycle = cPrime - (mPrime * hPeriod * 1e6 / 1000.0);
146        // 19.
147        horizontalBlanking = 2 * charSize * roundf(
148                                (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle)
149                                / (2 * charSize)));
150
151//      printf("idealDutyCycle %.9f, horizontalBlanking %d\n", idealDutyCycle, horizontalBlanking);
152
153        // 20.
154        horizontalTotal = horizontalActive + horizontalBlanking;
155        // 21.
156        float pixelFreq = horizontalTotal / hPeriod;
157
158        printf("pixFreq %.9f Mhz\n", pixelFreq/1e6);
159
160        // gtf 2.17.
161        horizontalSyncWidth = roundf(horizontalSyncPercent * horizontalTotal / charSize) * charSize;
162
163    }
164    else if (1 == genType)              /******************************* CVT */
165    {
166        float horizontalSyncPercent = 8.0/100.0;                        // H_SYNC_PER
167        float verticalSyncAndBackPorchTime = 550e-6;                    // MIN_VSYNC_BP
168        int   minVerticalBackPorch = 6;                                 // MIN_VBPORCH
169        int   minVerticalFrontPorch = 3;                                // MIN_V_PORCH_RND
170        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
171        float verticalFieldTotal;                                       // TOTAL_V_LINES
172
173        // 8.
174        estimatedHorizontalPeriod =
175            ((1 / fieldRate) - verticalSyncAndBackPorchTime)
176            / (verticalActive + (topMargin + bottomMargin) + minVerticalFrontPorch + interlace);
177        // 9.
178
179        verticalSyncAndBackPorch = 1 + truncf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod);
180
181        if (verticalSyncAndBackPorch < (verticalSyncWidth + minVerticalBackPorch))
182            verticalSyncAndBackPorch = verticalSyncWidth + minVerticalBackPorch;
183
184        // 10.
185//      int verticalSyncBackPorch = verticalSyncAndBackPorch - verticalSyncWidth;
186
187        verticalSyncFrontPorch = minVerticalFrontPorch;
188
189//        printf("estimatedHorizontalPeriod %.9f us, verticalSyncAndBackPorch %d\n",
190//                  estimatedHorizontalPeriod*1e6, verticalSyncAndBackPorch);
191
192        // 11.
193        verticalFieldTotal = verticalActive + topMargin + bottomMargin
194                            + verticalSyncAndBackPorch + interlace + minVerticalFrontPorch;
195        // 12.
196        float idealDutyCycle = cPrime - (mPrime * estimatedHorizontalPeriod * 1e6 / 1000.0);
197
198        // 13.
199        if (idealDutyCycle < 20.0)
200            idealDutyCycle = 20.0;
201
202        horizontalBlanking = 2 * charSize * truncf(
203                            (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle)
204                            / (2 * charSize)));
205
206        // 14.
207        horizontalTotal = horizontalActive + horizontalBlanking;
208
209        // 15.
210        float frequencyStep = 0.25e6;                                   // CLOCK_STEP
211        float pixelFrequency = frequencyStep * truncf(
212                        (horizontalTotal / estimatedHorizontalPeriod) / frequencyStep);
213
214        printf("pixFreq %.9f Mhz\n", pixelFrequency/1e6);
215
216        // 16.
217        float horizontalFrequency = pixelFrequency / horizontalTotal;
218
219        printf("hPeriod %.9f us, ", (1/horizontalFrequency)*1e6);
220        printf("hFreq %.9f kHz\n", horizontalFrequency/1e3);
221
222        // gtf 2.17.
223        horizontalSyncWidth = charSize * truncf(
224            horizontalSyncPercent * horizontalTotal / charSize);
225
226    }
227    else        /******************************* CVT reduced blank */
228    {
229        float minVerticalBlankTime = 460e-6;                            // RB_MIN_V_BLANK
230        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
231        int   verticalBlanking;                                         // VBI_LINES
232        int   minVerticalBackPorch = 6;                                 // MIN_VBPORCH
233
234        verticalSyncFrontPorch = 3;                                     // RB_V_FPORCH
235        horizontalBlanking = 160;                                       // RB_H_BLANK
236        horizontalSyncWidth = 32;                                       // RB_H_SYNC
237
238        // 8.
239        estimatedHorizontalPeriod = ((1 / fieldRate) - minVerticalBlankTime)
240                                    / (verticalActive + topMargin + bottomMargin);
241        // 9.
242        verticalBlanking = truncf(minVerticalBlankTime / estimatedHorizontalPeriod) + 1; // VBI_LINES
243
244//        printf("estimatedHorizontalPeriod %.9f us, verticalBlanking %d\n",
245//                      estimatedHorizontalPeriod*1e6, verticalBlanking);
246
247        // 10.
248        if (verticalBlanking < (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch))
249            verticalBlanking = (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch);
250
251
252        verticalSyncAndBackPorch = verticalBlanking - verticalSyncFrontPorch;
253
254        // 11.
255        int verticalFieldTotal = verticalBlanking  + verticalActive
256                                + topMargin + bottomMargin + interlace;
257
258        // 12.
259        horizontalTotal = horizontalActive + horizontalBlanking;
260
261        // 13.
262        float frequencyStep = 0.25e6;                                   // CLOCK_STEP
263        float pixelFrequency = frequencyStep * truncf(
264                            (horizontalTotal * verticalFieldTotal * fieldRate) / frequencyStep);
265
266        printf("pixFreq %.9f Mhz\n", pixelFrequency/1e6);
267
268        // 14.
269        float horizontalFrequency = pixelFrequency / horizontalTotal;
270
271        printf("hPeriod %.9f us, ", (1/horizontalFrequency)*1e6);
272        printf("hFreq %.9f kHz\n", horizontalFrequency/1e3);
273
274    }
275
276//    printf("verticalFieldTotal %.9f, estimatedFieldRate %.9f\n",
277//              verticalFieldTotal, estimatedFieldRate);
278//    printf("idealDutyCycle %.9f, horizontalBlanking %d\n",
279//              idealDutyCycle, horizontalBlanking);
280
281    // 17.
282//    float vFieldRate = hFreq / verticalFieldTotal;
283    // 18.
284//    float vFrameRate = vFieldRate / interlaceFactor;
285
286    // stage 2
287
288    // 3.
289    int verticalTotal = interlaceFactor *
290        (verticalActive + topMargin + bottomMargin
291            + verticalSyncAndBackPorch + interlace + verticalSyncFrontPorch);
292
293    int horizontalSyncOffset = (horizontalBlanking / 2) - horizontalSyncWidth;
294    // 30.
295    float verticalOddBlanking = verticalSyncAndBackPorch + verticalSyncFrontPorch;
296    // 32.
297    float verticalEvenBlanking = verticalSyncAndBackPorch + 2 * interlace + verticalSyncFrontPorch;
298    // 36.
299    float verticalSyncOddFrontPorch = verticalSyncFrontPorch + interlace;
300
301    printf("hTotal %d(%d), hFP %d(%d), hBlank %d(%d), hSync %d(%d)\n",
302            horizontalTotal/8, horizontalTotal, horizontalSyncOffset/8,
303            horizontalSyncOffset, horizontalBlanking/8, horizontalBlanking,
304            horizontalSyncWidth/8, horizontalSyncWidth);
305
306    printf("vTotal %d, vFP %.1f(E:%.1f), vBlank %.1f(E:%.1f), vSync %d\n\n",
307            verticalTotal, verticalSyncOddFrontPorch, (float) verticalSyncFrontPorch,
308            verticalOddBlanking, verticalEvenBlanking, verticalSyncWidth);
309
310}
311
312
313int main (int argc, char * argv[])
314{
315    char * endstr;
316    boolean_t needInterlace = FALSE;
317    int requestedWidth = 1400, requestedHeight = 1050;
318    float frameRate = 60.0;
319
320    requestedWidth = strtol(argv[1], 0, 0);
321    requestedHeight = strtol(argv[2], 0, 0);
322    frameRate = strtol(argv[3], &endstr, 0);
323    needInterlace = (endstr[0] == 'i') || (endstr[0] == 'I');
324
325    printf("\nGTF:\n\n");
326    GenTiming( requestedWidth, requestedHeight, frameRate, needInterlace, 0 );
327    printf("\nCVT:\n\n");
328    GenTiming( requestedWidth, requestedHeight, frameRate, needInterlace, 1 );
329    printf("\nCVT reduced blank:\n\n");
330    GenTiming( requestedWidth, requestedHeight, frameRate, needInterlace, 2 );
331
332    return(0);
333}
334
335