gtfcalc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /****************************************************************************
  2. *
  3. * VESA Generalized Timing Formula (GTF)
  4. * Version 1.1
  5. *
  6. * ========================================================================
  7. *
  8. * The contents of this file are subject to the SciTech MGL Public
  9. * License Version 1.0 (the "License"); you may not use this file
  10. * except in compliance with the License. You may obtain a copy of
  11. * the License at http://www.scitechsoft.com/mgl-license.txt
  12. *
  13. * Software distributed under the License is distributed on an
  14. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  15. * implied. See the License for the specific language governing
  16. * rights and limitations under the License.
  17. *
  18. * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
  19. *
  20. * The Initial Developer of the Original Code is SciTech Software, Inc.
  21. * All Rights Reserved.
  22. *
  23. * ========================================================================
  24. *
  25. * Developed by: SciTech Software, Inc.
  26. *
  27. * Language: ANSI C
  28. * Environment: Any.
  29. *
  30. * Description: C module for generating GTF compatible timings given a set
  31. * of input requirements. Translated from the original GTF
  32. * 1.14 spreadsheet definition.
  33. *
  34. * Compile with #define TESTING to build a command line test
  35. * program.
  36. *
  37. * NOTE: The code in here has been written for clarity and
  38. * to follow the original GTF spec as closely as
  39. * possible.
  40. *
  41. ****************************************************************************/
  42. #include "gtf.h"
  43. #ifndef __WIN32_VXD__
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #include <math.h>
  49. #endif
  50. /*------------------------- Global Variables ------------------------------*/
  51. static GTF_constants GC = {
  52. 1.8, /* Margin size as percentage of display */
  53. 8, /* Character cell granularity */
  54. 1, /* Minimum front porch in lines/chars */
  55. 3, /* Width of V sync in lines */
  56. 8, /* Width of H sync as percent of total */
  57. 550, /* Minimum vertical sync + back porch (us) */
  58. 600, /* Blanking formula gradient */
  59. 40, /* Blanking formula offset */
  60. 128, /* Blanking formula scaling factor */
  61. 20, /* Blanking formula scaling factor weight */
  62. };
  63. /*-------------------------- Implementation -------------------------------*/
  64. #ifdef __WIN32_VXD__
  65. /* These functions are not supported in a VxD, so we stub them out so this
  66. * module will at least compile. Calling the functions in here will do
  67. * something wierd!
  68. */
  69. double sqrt(double x)
  70. { return x; }
  71. double floor(double x)
  72. { return x; }
  73. double pow(double x,double y)
  74. { return x*y; }
  75. #endif
  76. static double round(double v)
  77. {
  78. return floor(v + 0.5);
  79. }
  80. static void GetInternalConstants(GTF_constants *c)
  81. /****************************************************************************
  82. *
  83. * Function: GetInternalConstants
  84. * Parameters: c - Place to store the internal constants
  85. *
  86. * Description: Calculates the rounded, internal set of GTF constants.
  87. * These constants are different to the real GTF constants
  88. * that can be set up for the monitor. The calculations to
  89. * get these real constants are defined in the 'Work Area'
  90. * after the constants are defined in the Excel spreadsheet.
  91. *
  92. ****************************************************************************/
  93. {
  94. c->margin = GC.margin;
  95. c->cellGran = round(GC.cellGran);
  96. c->minPorch = round(GC.minPorch);
  97. c->vSyncRqd = round(GC.vSyncRqd);
  98. c->hSync = GC.hSync;
  99. c->minVSyncBP = GC.minVSyncBP;
  100. if (GC.k == 0)
  101. c->k = 0.001;
  102. else
  103. c->k = GC.k;
  104. c->m = (c->k / 256) * GC.m;
  105. c->c = (GC.c - GC.j) * (c->k / 256) + GC.j;
  106. c->j = GC.j;
  107. }
  108. void GTF_calcTimings(double hPixels,double vLines,double freq,
  109. int type,ibool wantMargins,ibool wantInterlace,GTF_timings *t)
  110. /****************************************************************************
  111. *
  112. * Function: GTF_calcTimings
  113. * Parameters: hPixels - X resolution
  114. * vLines - Y resolution
  115. * freq - Frequency (Hz, KHz or MHz depending on type)
  116. * type - 1 - vertical, 2 - horizontal, 3 - dot clock
  117. * margins - True if margins should be generated
  118. * interlace - True if interlaced timings to be generated
  119. * t - Place to store the resulting timings
  120. *
  121. * Description: Calculates a set of GTF timing parameters given a specified
  122. * resolution and vertical frequency. The horizontal frequency
  123. * and dot clock will be automatically generated by this
  124. * routines.
  125. *
  126. * For interlaced modes the CRTC parameters are calculated for
  127. * a single field, so will be half what would be used in
  128. * a non-interlaced mode.
  129. *
  130. ****************************************************************************/
  131. {
  132. double interlace,vFieldRate,hPeriod;
  133. double topMarginLines,botMarginLines;
  134. double leftMarginPixels,rightMarginPixels;
  135. double hPeriodEst,vSyncBP,vBackPorch;
  136. double vTotalLines,vFieldRateEst;
  137. double hTotalPixels,hTotalActivePixels,hBlankPixels;
  138. double idealDutyCycle,hSyncWidth,hSyncBP,hBackPorch;
  139. double idealHPeriod;
  140. double vFreq,hFreq,dotClock;
  141. GTF_constants c;
  142. /* Get rounded GTF constants used for internal calculations */
  143. GetInternalConstants(&c);
  144. /* Move input parameters into appropriate variables */
  145. vFreq = hFreq = dotClock = freq;
  146. /* Round pixels to character cell granularity */
  147. hPixels = round(hPixels / c.cellGran) * c.cellGran;
  148. /* For interlaced mode halve the vertical parameters, and double
  149. * the required field refresh rate.
  150. */
  151. vFieldRate = vFreq;
  152. interlace = 0;
  153. if (wantInterlace)
  154. dotClock *= 2;
  155. /* Determine the lines for margins */
  156. if (wantMargins) {
  157. topMarginLines = round(c.margin / 100 * vLines);
  158. botMarginLines = round(c.margin / 100 * vLines);
  159. }
  160. else {
  161. topMarginLines = 0;
  162. botMarginLines = 0;
  163. }
  164. if (type != GTF_lockPF) {
  165. if (type == GTF_lockVF) {
  166. /* Estimate the horizontal period */
  167. hPeriodEst = ((1/vFieldRate) - (c.minVSyncBP/1000000)) /
  168. (vLines + (2*topMarginLines) + c.minPorch + interlace) * 1000000;
  169. /* Find the number of lines in vSync + back porch */
  170. vSyncBP = round(c.minVSyncBP / hPeriodEst);
  171. }
  172. else if (type == GTF_lockHF) {
  173. /* Find the number of lines in vSync + back porch */
  174. vSyncBP = round((c.minVSyncBP * hFreq) / 1000);
  175. }
  176. /* Find the number of lines in the V back porch alone */
  177. vBackPorch = vSyncBP - c.vSyncRqd;
  178. /* Find the total number of lines in the vertical period */
  179. vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP
  180. + interlace + c.minPorch;
  181. if (type == GTF_lockVF) {
  182. /* Estimate the vertical frequency */
  183. vFieldRateEst = 1000000 / (hPeriodEst * vTotalLines);
  184. /* Find the actual horizontal period */
  185. hPeriod = (hPeriodEst * vFieldRateEst) / vFieldRate;
  186. /* Find the actual vertical field frequency */
  187. vFieldRate = 1000000 / (hPeriod * vTotalLines);
  188. }
  189. else if (type == GTF_lockHF) {
  190. /* Find the actual vertical field frequency */
  191. vFieldRate = (hFreq / vTotalLines) * 1000;
  192. }
  193. }
  194. /* Find the number of pixels in the left and right margins */
  195. if (wantMargins) {
  196. leftMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran);
  197. rightMarginPixels = round(hPixels * c.margin) / (100 * c.cellGran);
  198. }
  199. else {
  200. leftMarginPixels = 0;
  201. rightMarginPixels = 0;
  202. }
  203. /* Find the total number of active pixels in image + margins */
  204. hTotalActivePixels = hPixels + leftMarginPixels + rightMarginPixels;
  205. if (type == GTF_lockVF) {
  206. /* Find the ideal blanking duty cycle */
  207. idealDutyCycle = c.c - ((c.m * hPeriod) / 1000);
  208. }
  209. else if (type == GTF_lockHF) {
  210. /* Find the ideal blanking duty cycle */
  211. idealDutyCycle = c.c - (c.m / hFreq);
  212. }
  213. else if (type == GTF_lockPF) {
  214. /* Find ideal horizontal period from blanking duty cycle formula */
  215. idealHPeriod = (((c.c - 100) + (sqrt((pow(100-c.c,2)) +
  216. (0.4 * c.m * (hTotalActivePixels + rightMarginPixels +
  217. leftMarginPixels) / dotClock)))) / (2 * c.m)) * 1000;
  218. /* Find the ideal blanking duty cycle */
  219. idealDutyCycle = c.c - ((c.m * idealHPeriod) / 1000);
  220. }
  221. /* Find the number of pixels in blanking time */
  222. hBlankPixels = round((hTotalActivePixels * idealDutyCycle) /
  223. ((100 - idealDutyCycle) * c.cellGran)) * c.cellGran;
  224. /* Find the total number of pixels */
  225. hTotalPixels = hTotalActivePixels + hBlankPixels;
  226. /* Find the horizontal back porch */
  227. hBackPorch = round((hBlankPixels / 2) / c.cellGran) * c.cellGran;
  228. /* Find the horizontal sync width */
  229. hSyncWidth = round(((c.hSync/100) * hTotalPixels) / c.cellGran) * c.cellGran;
  230. /* Find the horizontal sync + back porch */
  231. hSyncBP = hBackPorch + hSyncWidth;
  232. if (type == GTF_lockPF) {
  233. /* Find the horizontal frequency */
  234. hFreq = (dotClock / hTotalPixels) * 1000;
  235. /* Find the number of lines in vSync + back porch */
  236. vSyncBP = round((c.minVSyncBP * hFreq) / 1000);
  237. /* Find the number of lines in the V back porch alone */
  238. vBackPorch = vSyncBP - c.vSyncRqd;
  239. /* Find the total number of lines in the vertical period */
  240. vTotalLines = vLines + topMarginLines + botMarginLines + vSyncBP
  241. + interlace + c.minPorch;
  242. /* Find the actual vertical field frequency */
  243. vFieldRate = (hFreq / vTotalLines) * 1000;
  244. }
  245. else {
  246. if (type == GTF_lockVF) {
  247. /* Find the horizontal frequency */
  248. hFreq = 1000 / hPeriod;
  249. }
  250. else if (type == GTF_lockHF) {
  251. /* Find the horizontal frequency */
  252. hPeriod = 1000 / hFreq;
  253. }
  254. /* Find the pixel clock frequency */
  255. dotClock = hTotalPixels / hPeriod;
  256. }
  257. /* Return the computed frequencies */
  258. t->vFreq = vFieldRate;
  259. t->hFreq = hFreq;
  260. t->dotClock = dotClock;
  261. /* Determine the vertical timing parameters */
  262. t->h.hTotal = (int)hTotalPixels;
  263. t->h.hDisp = (int)hTotalActivePixels;
  264. t->h.hSyncStart = t->h.hTotal - (int)hSyncBP;
  265. t->h.hSyncEnd = t->h.hTotal - (int)hBackPorch;
  266. t->h.hFrontPorch = t->h.hSyncStart - t->h.hDisp;
  267. t->h.hSyncWidth = (int)hSyncWidth;
  268. t->h.hBackPorch = (int)hBackPorch;
  269. /* Determine the vertical timing parameters */
  270. t->v.vTotal = (int)vTotalLines;
  271. t->v.vDisp = (int)vLines;
  272. t->v.vSyncStart = t->v.vTotal - (int)vSyncBP;
  273. t->v.vSyncEnd = t->v.vTotal - (int)vBackPorch;
  274. t->v.vFrontPorch = t->v.vSyncStart - t->v.vDisp;
  275. t->v.vSyncWidth = (int)c.vSyncRqd;
  276. t->v.vBackPorch = (int)vBackPorch;
  277. if (wantInterlace) {
  278. /* Halve the timings for interlaced modes */
  279. t->v.vTotal /= 2;
  280. t->v.vDisp /= 2;
  281. t->v.vSyncStart /= 2;
  282. t->v.vSyncEnd /= 2;
  283. t->v.vFrontPorch /= 2;
  284. t->v.vSyncWidth /= 2;
  285. t->v.vBackPorch /= 2;
  286. t->dotClock /= 2;
  287. }
  288. /* Mark as GTF timing using the sync polarities */
  289. t->interlace = (wantInterlace) ? 'I' : 'N';
  290. t->hSyncPol = '-';
  291. t->vSyncPol = '+';
  292. }
  293. void GTF_getConstants(GTF_constants *constants)
  294. { *constants = GC; }
  295. void GTF_setConstants(GTF_constants *constants)
  296. { GC = *constants; }
  297. #ifdef TESTING_GTF
  298. void main(int argc,char *argv[])
  299. {
  300. FILE *f;
  301. double xPixels,yPixels,freq;
  302. ibool interlace;
  303. GTF_timings t;
  304. if (argc != 5 && argc != 6) {
  305. printf("Usage: GTFCALC <xPixels> <yPixels> <freq> [[Hz] [KHz] [MHz]] [I]\n");
  306. printf("\n");
  307. printf("where <xPixels> is the horizontal resolution of the mode, <yPixels> is the\n");
  308. printf("vertical resolution of the mode. The <freq> value will be the frequency to\n");
  309. printf("drive the calculations, and will be either the vertical frequency (in Hz)\n");
  310. printf("the horizontal frequency (in KHz) or the dot clock (in MHz). To generate\n");
  311. printf("timings for an interlaced mode, add 'I' to the end of the command line.\n");
  312. printf("\n");
  313. printf("For example to generate timings for 640x480 at 60Hz vertical:\n");
  314. printf("\n");
  315. printf(" GTFCALC 640 480 60 Hz\n");
  316. printf("\n");
  317. printf("For example to generate timings for 640x480 at 31.5KHz horizontal:\n");
  318. printf("\n");
  319. printf(" GTFCALC 640 480 31.5 KHz\n");
  320. printf("\n");
  321. printf("For example to generate timings for 640x480 with a 25.175Mhz dot clock:\n");
  322. printf("\n");
  323. printf(" GTFCALC 640 480 25.175 MHz\n");
  324. printf("\n");
  325. printf("GTFCALC will print a summary of the results found, and dump the CRTC\n");
  326. printf("values to the UVCONFIG.CRT file in the format used by SciTech Display Doctor.\n");
  327. exit(1);
  328. }
  329. /* Get values from command line */
  330. xPixels = atof(argv[1]);
  331. yPixels = atof(argv[2]);
  332. freq = atof(argv[3]);
  333. interlace = ((argc == 6) && (argv[5][0] == 'I'));
  334. /* Compute the CRTC timings */
  335. if (toupper(argv[4][0]) == 'H')
  336. GTF_calcTimings(xPixels,yPixels,freq,GTF_lockVF,false,interlace,&t);
  337. else if (toupper(argv[4][0]) == 'K')
  338. GTF_calcTimings(xPixels,yPixels,freq,GTF_lockHF,false,interlace,&t);
  339. else if (toupper(argv[4][0]) == 'M')
  340. GTF_calcTimings(xPixels,yPixels,freq,GTF_lockPF,false,interlace,&t);
  341. else {
  342. printf("Unknown command line!\n");
  343. exit(1);
  344. }
  345. /* Dump summary info to standard output */
  346. printf("CRTC values for %.0fx%.0f @ %.2f %s\n", xPixels, yPixels, freq, argv[4]);
  347. printf("\n");
  348. printf(" hTotal = %-4d vTotal = %-4d\n",
  349. t.h.hTotal, t.v.vTotal);
  350. printf(" hDisp = %-4d vDisp = %-4d\n",
  351. t.h.hDisp, t.v.vDisp);
  352. printf(" hSyncStart = %-4d vSyncStart = %-4d\n",
  353. t.h.hSyncStart, t.v.vSyncStart);
  354. printf(" hSyncEnd = %-4d vSyncEnd = %-4d\n",
  355. t.h.hSyncEnd, t.v.vSyncEnd);
  356. printf(" hFrontPorch = %-4d vFrontPorch = %-4d\n",
  357. t.h.hFrontPorch, t.v.vFrontPorch);
  358. printf(" hSyncWidth = %-4d vSyncWidth = %-4d\n",
  359. t.h.hSyncWidth, t.v.vSyncWidth);
  360. printf(" hBackPorch = %-4d vBackPorch = %-4d\n",
  361. t.h.hBackPorch, t.v.vBackPorch);
  362. printf("\n");
  363. printf(" Interlaced = %s\n", (t.interlace == 'I') ? "Yes" : "No");
  364. printf(" H sync pol = %c\n", t.hSyncPol);
  365. printf(" V sync pol = %c\n", t.vSyncPol);
  366. printf("\n");
  367. printf(" Vert freq = %.2f Hz\n", t.vFreq);
  368. printf(" Horiz freq = %.2f KHz\n", t.hFreq);
  369. printf(" Dot Clock = %.2f Mhz\n", t.dotClock);
  370. /* Dump to file in format used by SciTech Display Doctor */
  371. if ((f = fopen("UVCONFIG.CRT","w")) != NULL) {
  372. fprintf(f, "[%.0f %.0f]\n", xPixels, yPixels);
  373. fprintf(f, "%d %d %d %d '%c' %s\n",
  374. t.h.hTotal, t.h.hDisp,
  375. t.h.hSyncStart, t.h.hSyncEnd,
  376. t.hSyncPol, (t.interlace == 'I') ? "I" : "NI");
  377. fprintf(f, "%d %d %d %d '%c'\n",
  378. t.v.vTotal, t.v.vDisp,
  379. t.v.vSyncStart, t.v.vSyncEnd,
  380. t.vSyncPol);
  381. fprintf(f, "%.2f\n", t.dotClock);
  382. fclose(f);
  383. }
  384. }
  385. #endif /* TESTING */