home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / VGADOC4B.ZIP / DEFVGA.PAS < prev    next >
Pascal/Delphi Source File  |  1995-09-29  |  31KB  |  1,212 lines

  1.  
  2. type
  3.   str10 = string[10];
  4.  
  5. const
  6.  
  7.   hx:array[0..15] of char='0123456789ABCDEF';
  8.  
  9.   Debug:boolean=false;      {If set step through video tests one by one}
  10.   Auto_test:boolean=false;  {If set run tests automatically}
  11.  
  12.  
  13.   {Keys:}
  14.   Ch_Cr       =  $0D;
  15.   Ch_Esc      =  $1B;
  16.   Ch_F1       = $13B;
  17.   Ch_F2       = $13C;
  18.   Ch_F3       = $13D;
  19.   Ch_F4       = $13E;
  20.   Ch_F5       = $13F;
  21.   Ch_F6       = $140;
  22.   Ch_F7       = $141;
  23.   Ch_F8       = $142;
  24.   Ch_Home     = $147;
  25.   Ch_ArUp     = $148;
  26.   Ch_PgUp     = $149;
  27.   Ch_ArLeft   = $14B;
  28.   Ch_ArRight  = $14D;
  29.   Ch_End      = $14F;
  30.   Ch_ArDown   = $150;
  31.   Ch_PgDn     = $151;
  32.   Ch_Ins      = $152;
  33.   Ch_Del      = $153;
  34.  
  35.  
  36.     {Standard segment defines}
  37.   Seg0000 = $0000;    {Interupt table}
  38.   Seg0040 = $0040;    {BIOS data segment}
  39.   SegA000 = $A000;    {Graphics Video buffer}
  40.   SegA800 = $A800;    {Graphics Video buffer - upper half}
  41.   SegB000 = $B000;    {Mono Text mode buffer}
  42.   SegB800 = $B800;    {Color Text mode buffer}
  43.   SegC000 = $C000;    {BIOS ROM segment}
  44.  
  45.   {Gamma correction types}
  46.   GAM_None  =  0;    {No Gamma correction}
  47.   GAM_CanDo =  1;    {}
  48.   GAM_LeftJ =  2;    {left justify Red&Blue 1bit each}
  49.   GAM_Left8 =  4;    {Left justify to 8bits}
  50.   GAM_8bit  =  8;    {DAC Gamma registers are 8bit (not 6)}
  51.  
  52. type
  53.   CursorType=Array[0..31] of longint;  {32 lines of 32 pixels}
  54.   charr =array[1..255] of char;
  55.   chptr =^charr;
  56.  
  57.  
  58. var
  59.   rp:registers;
  60.  
  61.   video:string[20];
  62.   _crt:string[20];
  63.   secondary:string[20];
  64.  
  65.   planes:word;     {number of video planes}
  66.  
  67.  
  68.   dacHWcursor:boolean;   {True if we use the DAC cursor, rather than the VGA one}
  69.  
  70.  
  71.   vseg:word;         {Video buffer base segment}
  72.   biosseg:word;
  73.  
  74.   curmode:word;      {Current mode number}
  75.   memmode:byte;      {current memory mode}
  76.   crtc:word;         {I/O address of CRTC registers}
  77.   pixels:word;       {Pixels in a scanline in current mode}
  78.   lins:word;         {lines in current mode}
  79.   bytes:longint;     {bytes in a scanline}
  80.  
  81.   force_chip:byte;
  82.   force_mm:word;       {Forced memory size in Kbytes}
  83.   force_version:word;  {Forced chip version}
  84.   clocktest:boolean;   {Set false to disable clocktesting.}
  85.  
  86.  
  87.   extpixfact:word;  {The number of times each pixel is shown}
  88.   extlinfact:word;  {The number of times each scan line is shown}
  89.   charwid   :word;  {Character width in pixels}
  90.   charhigh  :word;  {Character height in scanlines}
  91.   calcvseg:word;
  92.   calcpixels,       {Calculated displayed pixels per scanline}
  93.   calclines,        {    "      displayed scanlines}
  94.   calchtot,         {    "      total pixels/scanline}
  95.   calcvtot,         {    "      total lines/frame}
  96.   calchblks,        {    "      Hor. Blanking Start}
  97.   calchblke,        {    "      Hor Blanking End (see hblkmask)}
  98.   calchrtrs,        {    "      Hor Retrace Start}
  99.   calchrtre,        {    "      Hor Retrace End (see hrtrmask)}
  100.   calcvblks,        {    "      Vert Blanking Start}
  101.   calcvblke,        {    "      Vert Blanking End (see vblkmask)}
  102.   calcvrtrs,        {    "      Vert Retrace Start}
  103.   calcvrtre,        {    "      Vert Retrace End (see vrtrmask)}
  104.   hblkmask,         {    "      }
  105.   hrtrmask,         {    "      }
  106.   vblkmask,         {    "      }
  107.   vrtrmask,         {    "      }
  108.   calcbytes:word;
  109.   calcmmode:byte;
  110.  
  111.  
  112.   vclk,hclk,fclk:longint;  {Pixel (kHz), Line (Hz) & Frame (mHz) clocks}
  113.   ilace:boolean;
  114.  
  115.  
  116.   daccomm:word;      {The result of the last dac2comm}
  117.  
  118.  
  119.   BWlow,BWhigh:longint;  {Bandwidth requirement - low & high in Kbytes/sec}
  120.  
  121.  
  122.   (* Interface declarations for functions. In DEFVGA.PAS *)
  123.  
  124.  
  125.   (* Utility & User interfrace functions*)
  126. procedure disable; {Disable interupts}
  127.  
  128. procedure enable;  {Enable interrupts}
  129.  
  130. function gtstr(var cp:char):string;
  131.  
  132. function getkey:word;              {Waits for a key, and returns the keyID}
  133.  
  134. function peekkey:word;             {Checks for a key, and returns the keyID}
  135.  
  136. procedure pushkey(k:word);         {Simulates a keystroke}
  137.  
  138.   {Pretend the last key was pushed again}
  139. procedure repeatkey;
  140.  
  141. function strip(s:string):string;   {strip leading and trailing spaces}
  142.  
  143. function upstr(s:string):string;   {convert a string to upper case}
  144.  
  145. function istr(w:longint):str10;    {convert number to string}
  146.  
  147. function dehex(s:string):longint;  {Hex string to number}
  148.  
  149. function hex2(w:word):str10;       {convert number to 2digit hex string}
  150.  
  151. function hex4(w:word):str10;       {convert number to 4digit hex string}
  152.  
  153. function hex8(w:longint):str10;       {convert number to 4digit hex string}
  154.  
  155. procedure swapbyte(var a,b:byte);  {Swap the 2 bytes}
  156.  
  157. function clipstr(var s:string):string;   {Cuts & returns the first non-space
  158.                                           substring from s}
  159.  
  160.   {BIOS & lowlevel I/O functions}
  161.  
  162. procedure vio(ax:word);         {INT 10h reg ax=AX. other reg. set from RP
  163.                                  on return rp.ax=reg AX}
  164.  
  165. procedure viop(ax,bx,cx,dx:word;p:pointer);
  166.                                 {INT 10h reg AX-DX, ES:DI = p}
  167.  
  168. function inp(reg:word):byte;      {Reads a byte from I/O port REG}
  169.  
  170. function inpw(reg:word):word;     {Reads a word from I/O port REG}
  171.  
  172. function inpl(reg:word):longint;  {Reads a DWORD from I/O port REG}
  173.  
  174. procedure outp(reg,val:word);    {Write the low byte of VAL to I/O port REG}
  175.  
  176. procedure outpw(reg,val:word);    {Write the word byte of VAL to I/O port REG}
  177.  
  178. procedure outpl(reg:word;val:longint);    {Write the word byte of VAL to I/O port REG}
  179.  
  180.   {Outputs a 32bit value as a single OUT DX,EAX - requires 386 or better}
  181. procedure outplong(reg:word;val:longint);
  182.  
  183.   {Inputs a 32bit value as a single IN EAX,DX - requires 386 or better}
  184. function inplong(reg:word):longint;
  185.  
  186.  
  187. function rdinx(pt,inx:word):word;       {read register PT index INX}
  188.  
  189. procedure wrinx(pt,inx,val:word);       {write VAL to register PT index INX}
  190.  
  191. procedure wrinx2(pt,inx,val:word);       {write VAL to register PT index INX}
  192.  
  193. procedure wrinx2m(pt,inx,val:word);       {write VAL to register PT index INX}
  194.  
  195. procedure wrinx3(pt,inx:word;val:longint);       {write VAL to register PT index INX}
  196.  
  197. procedure wrinx3m(pt,inx:word;val:longint);       {write VAL to register PT index INX}
  198.  
  199. procedure modinx(pt,inx,mask,nwv:word);  {In register PT index INX sets
  200.                                           the bits in MASK as in NWV
  201.                                           the other are left unchanged}
  202.  
  203. procedure setinx(pt,inx,val:word);
  204.  
  205. procedure clrinx(pt,inx,val:word);
  206.  
  207. procedure modreg(reg,mask,nwv:word);  {In register PT index INX sets
  208.                                           the bits in MASK as in NWV
  209.                                           the other are left unchanged}
  210.  
  211. procedure setreg(reg,val:word);
  212.  
  213. procedure clrreg(reg,val:word);
  214.  
  215. procedure modregw(reg,mask,nwv:word);  {In register PT index INX sets
  216.                                           the bits in MASK as in NWV
  217.                                           the other are left unchanged}
  218.  
  219. procedure setregw(reg,val:word);
  220.  
  221. procedure clrregw(reg,val:word);
  222.  
  223.   {Lowlevel DAC stuff}
  224. function trigdac:word;  {Reads $3C6 4 times}
  225.  
  226. procedure setDACstd;
  227. procedure setdac8(on:boolean);
  228. function setdac15:boolean;
  229. function setdac16:boolean;
  230. function setdac24:boolean;
  231. function setdac32:boolean;
  232.  
  233. function setDACgamma(on:boolean):word;
  234.  
  235.  
  236. function setDACpage(index:word):word;
  237.  
  238. procedure clearDACpage;
  239.  
  240. function rdDACreg(index:word):word;
  241.  
  242. procedure wrDACreg(index,val:word);
  243.  
  244. procedure clrDACreg(index,val:word);
  245.  
  246. procedure setDACreg(index,val:word);
  247.  
  248. procedure modDACreg(index,msk,val:word);
  249.  
  250.  
  251. function getdaccomm:word;
  252.  
  253. procedure dac2comm;
  254.  
  255. procedure dac2pel;
  256.  
  257.  
  258.   {Probe clocks, should really be in IDVGA ??}
  259. procedure findclocks;
  260.  
  261.  
  262.   {The LOG functions writes output data to both the screen and the file
  263.    WHATVGA.TXT, to provide a log in case of lockup}
  264.  
  265. procedure openlog(scr:boolean);
  266.  
  267. procedure wrlog(s:string);
  268.  
  269. procedure closelog;
  270.  
  271.  
  272.  
  273.  
  274.  
  275.   (* HW cursor, BitBLT, linedraw and clock function in BITBLT.PAS *)
  276.  
  277. procedure setHWcurmap(VAR map:CursorType);
  278.  
  279. procedure HWcuronoff(on:boolean);
  280.  
  281. procedure setHWcurpos(X,Y:word);
  282.  
  283. procedure setHWcurcol(fgcol,bkcol:longint);
  284.  
  285.  
  286. procedure setZoomWindow(Xs,Ys,Xe,Ye:word);
  287.  
  288. procedure setZoomAdr(AdrX,AdrY:word);
  289.  
  290. procedure ZoomOnOff(On:boolean);
  291.  
  292. procedure setZoomFactor(Fx,Fy:word);
  293.  
  294. procedure vesamodeinfo(md:word;var vbedata);
  295.  
  296.  
  297. procedure fillrect(xst,yst,dx,dy:word;col:longint);
  298.  
  299. procedure copyrect(srcX,srcY,dstX,dstY,dx,dy:word);
  300.  
  301. procedure line(x0,y0,x1,y1:integer;col:longint);
  302.  
  303. procedure setclk(Nbr,divi:word);
  304.  
  305. function getclk(var divisor,divid:word):word;
  306.  
  307. function getClockFreq:longint;    {Effective pixel clock in kHz}
  308.  
  309.  
  310.  
  311.  
  312.   (* Bank, mode and Vstart rutines, in SUPERVGA.PAS *)
  313.  
  314. procedure setbank(bank:word);
  315.  
  316. procedure setRbank(bank:word);
  317.  
  318. procedure setvstart(x,y:word);       {Set the display start to (x,y)}
  319.  
  320. function setmode(md:word;clear:boolean):boolean;
  321.  
  322. procedure SetTextMode;
  323.  
  324.  
  325.  
  326. procedure SetRGBPal(inx,r,g,b:word);
  327.  
  328. procedure SelectVideo(Item:word);
  329.  
  330. function rgb(r,g,b:word):longint;    {Converts RGB values to pixel in the
  331.                                       current pixelformat }
  332.  
  333.   {Returns the pixel BIT address}
  334. function pixeladdress(x,y:word):longint;
  335.  
  336. implementation
  337. uses idvga;
  338.  
  339.  
  340. var
  341.  
  342.   clocktbl:array[0..31] of longint;
  343.  
  344.  
  345. procedure disable; (* Disable interupts *)
  346. begin
  347.   inline($fa);  (* CLI instruction *)
  348. end;
  349.  
  350.  
  351. procedure enable;  (* Enable interrupts *)
  352. begin
  353.   inline($fb);  (* STI instruction *)
  354. end;
  355.  
  356.  
  357. function gtstr(var cp:char):string;
  358. var x:word;
  359.   s:string;
  360.   str:chptr;
  361. begin
  362.   str:=chptr(@cp);
  363.   s:='';x:=1;
  364.   if str<>NIL then
  365.     while (x<255) and (str^[x]<>#0) do
  366.     begin
  367.       if str^[x]<>#7 then s:=s+str^[x];
  368.       inc(x);
  369.     end;
  370.   gtstr:=s;
  371. end;
  372.  
  373. const
  374.   key_stack:word=0;    {Stored key stroke 0=none}
  375.   lastkey:word=0;
  376.  
  377. function getkey:word;
  378. var c:char;
  379. begin
  380.   if key_stack<>0 then
  381.   begin
  382.     lastkey:=key_stack;
  383.     key_stack:=0;
  384.   end
  385.   else begin
  386.     c:=readkey;
  387.     if c=#0 then lastkey:=$100+ord(readkey)
  388.             else lastkey:=ord(c);
  389.   end;
  390.   getkey:=lastkey;
  391. end;
  392.  
  393. function peekkey:word;
  394. begin
  395.   if (key_stack=0) and not keypressed then peekkey:=0
  396.                                       else peekkey:=getkey;
  397. end;
  398.  
  399. procedure pushkey(k:word);  {Simulates a key stroke}
  400. var ch:char;
  401. begin
  402.   key_stack:=k;
  403.   while keypressed do ch:=readkey;
  404. end;
  405.  
  406.   {Pretend the last key was pushed again}
  407. procedure repeatkey;
  408. begin
  409.   pushkey(lastkey);
  410. end;
  411.  
  412.   {Swap the 2 bytes}
  413. procedure swapbyte(var a,b:byte);
  414. var c:byte;
  415. begin
  416.   c:=a;
  417.   a:=b;
  418.   b:=c;
  419. end;
  420.  
  421.  
  422. function strip(s:string):string;       {strip leading and trailing spaces}
  423. begin
  424.   while s[length(s)]=' ' do dec(s[0]);
  425.   while copy(s,1,1)=' ' do delete(s,1,1);
  426.   strip:=s;
  427. end;
  428.  
  429. function upstr(s:string):string;       {convert a string to upper case}
  430. var x:word;
  431. begin
  432.   for x:=1 to length(s) do
  433.     s[x]:=upcase(s[x]);
  434.   upstr:=s;
  435. end;
  436.  
  437. function istr(w:longint):str10;
  438. var s:str10;
  439. begin
  440.   str(w,s);
  441.   istr:=s;
  442. end;
  443.  
  444.  
  445. function hex2(w:word):str10;
  446. begin
  447.   hex2:=hx[(w shr 4) and 15]+hx[w and 15];
  448. end;
  449.  
  450. function hex4(w:word):str10;
  451. begin
  452.   hex4:=hex2(hi(w))+hex2(lo(w));
  453. end;
  454.  
  455. function hex8(w:longint):str10;
  456. begin
  457.   hex8:=hex4(w shr 16)+hex4(w);
  458. end;
  459.  
  460. function dehex(s:string):longint;
  461. var x:word;
  462.     l:longint;
  463.     c:char;
  464. begin
  465.   l:=0;
  466.   for x:=1 to length(s) do
  467.   begin
  468.     c:=s[x];
  469.     case c of
  470.       '0'..'9':l:=(l shl 4)+(ord(c) and 15);
  471.       'a'..'f','A'..'F':
  472.                l:=(l shl 4)+(ord(c) and 15 +9);
  473.     end;
  474.   end;
  475.   dehex:=l;
  476. end;
  477.  
  478. function clipstr(var s:string):string;   {Cuts & returns the first non-space
  479.                                           substring from s}
  480. var
  481.   i:integer;
  482. begin
  483.   i:=0;
  484.   while s[i+1]=' ' do inc(i);
  485.   delete(s,1,i);
  486.   i:=0;
  487.   while (i<length(s)) and (s[i+1]>' ') do inc(i);
  488.   clipstr:=copy(s,1,i);
  489.   delete(s,1,i);
  490. end;
  491.  
  492.  
  493. procedure vio(ax:word);         {INT 10h reg ax=AX. other reg. set from RP
  494.                                  on return rp.ax=reg AX}
  495. begin
  496.   rp.ax:=ax;
  497.   intr($10,rp);
  498. end;
  499.  
  500. procedure viop(ax,bx,cx,dx:word;p:pointer);
  501. begin                            {INT 10h reg AX-DX, ES:DI = p}
  502.   rp.ax:=ax;
  503.   rp.bx:=bx;
  504.   rp.cx:=cx;
  505.   rp.dx:=dx;
  506.   rp.di:=ofs(p^);
  507.   rp.es:=seg(p^);
  508.   intr($10,rp);
  509. end;
  510.  
  511. function inp(reg:word):byte;     {Reads a byte from I/O port REG}
  512. begin
  513.   reg:=port[reg];
  514.   inp:=reg;
  515. end;
  516.  
  517.  
  518. function inpw(reg:word):word;    {Reads a word from I/O port REG}
  519. begin
  520.   reg:=portw[reg];
  521.   inpw:=reg;
  522. end;
  523.  
  524. function inpl(reg:word):longint;    {Reads a word from I/O port REG}
  525. var l:longint;
  526. begin
  527.   l:=portw[reg];
  528.   inpl:=l+(longint(portw[reg+2]) shl 16);
  529. end;
  530.  
  531.   {Inputs a 32bit value as a single IN EAX,DX - requires 386 or better}
  532. function inplong(reg:word):longint;
  533. var l:longint;
  534. begin
  535.   inline($8B/$56/<reg/$66/$ED/$66/$89/$46/<l);
  536.   inplong:=l;
  537. end;
  538.  
  539. procedure outp(reg,val:word);    {Write the low byte of VAL to I/O port REG}
  540. begin
  541.   port[reg]:=val;
  542. end;
  543.  
  544. procedure outpw(reg,val:word);
  545. begin
  546.   portw[reg]:=val;
  547. end;
  548.  
  549. procedure outpl(reg:word;val:longint);    {Write the Dword of VAL to I/O port REG}
  550. begin
  551.   portw[reg]  :=val;
  552.   portw[reg+2]:=val shr 16;
  553. end;
  554.  
  555.   {Outputs a 32bit value as a single OUT DX,EAX - requires 386 or better}
  556. procedure outplong(reg:word;val:longint);
  557. begin
  558.     {mov dx,[BP+reg] mov eax,[BP+val]  out dx,eax}
  559.   inline($8B/$56/<reg/$66/$8B/$46/<val/$66/$EF);
  560. end;
  561.  
  562.  
  563. function rdinx(pt,inx:word):word;       {read register PT index INX}
  564. var x:word;
  565. begin
  566.   if pt=$3C0 then
  567.   begin
  568.     x:=inp(CRTC+6);    {Reset Attribute Data/Address Flip-Flop}
  569.     outp($3C0,inx and $DF);    {Clear bit 5 of index}
  570.     for x:=1 to 10 do;
  571.     rdinx:=inp($3C1);    {delay}
  572.     x:=inp(CRTC+6);    {Reset Attribute Data/Address Flip-Flop}
  573.     for x:=1 to 10 do;   {delay}
  574.     outp($3C0,$20);    {Set index bit 5 to keep display alive}
  575.     x:=inp(CRTC+6);    {Reset Attribute Data/Address Flip-Flop}
  576.   end
  577.   else begin
  578.     outp(pt,inx);
  579.     rdinx:=inp(pt+1);
  580.   end;
  581. end;
  582.  
  583. procedure wrinx(pt,inx,val:word);       {write VAL to register PT index INX}
  584. var x:word;
  585. begin
  586.   if pt=$3C0 then
  587.   begin
  588.     x:=inp(CRTC+6);
  589.     outp($3C0,inx and $DF);
  590.     outp($3C0,val);
  591.     x:=inp(CRTC+6);    {If Attribute Register then reset Flip-Flop}
  592.     outp($3C0,$20);
  593.     x:=inp(CRTC+6);
  594.   end
  595.   else begin
  596.     outp(pt,inx);
  597.     outp(pt+1,val);
  598.   end;
  599. end;
  600.  
  601. procedure wrinx2(pt,inx,val:word);
  602. begin
  603.   wrinx(pt,inx,lo(val));
  604.   wrinx(pt,inx+1,hi(val));
  605. end;
  606.  
  607. procedure wrinx3(pt,inx:word;val:longint);
  608. begin
  609.   wrinx(pt,inx,lo(val));
  610.   wrinx(pt,inx+1,hi(val));
  611.   wrinx(pt,inx+2,val shr 16);
  612. end;
  613.  
  614. procedure wrinx2m(pt,inx,val:word); {Write VAL to the index pair (INX,INX+1)}
  615. begin                               {in motorola (big endian) format}
  616.   wrinx(pt,inx,hi(val));
  617.   wrinx(pt,inx+1,lo(val));
  618. end;
  619.  
  620. procedure wrinx3m(pt,inx:word;val:longint);
  621. begin
  622.   wrinx(pt,inx+2,lo(val));
  623.   wrinx(pt,inx+1,hi(val));
  624.   wrinx(pt,inx,val shr 16);
  625. end;
  626.  
  627. procedure modinx(pt,inx,mask,nwv:word);  {In register PT index INX sets
  628.                                           the bits in MASK as in NWV
  629.                                           the other are left unchanged}
  630. var temp:word;
  631. begin
  632.   temp:=(rdinx(pt,inx) and (not mask))+(nwv and mask);
  633.   wrinx(pt,inx,temp);
  634. end;
  635.  
  636. procedure modreg(reg,mask,nwv:word);  {In register REG sets the bits in
  637.                                        MASK as in NWV other are left unchanged}
  638. var temp:word;
  639. begin
  640.   temp:=(inp(reg) and (not mask))+(nwv and mask);
  641.   outp(reg,temp);
  642. end;
  643.  
  644.  
  645. procedure setinx(pt,inx,val:word);
  646. var x:word;
  647. begin
  648.   x:=rdinx(pt,inx);
  649.   wrinx(pt,inx,x or val);
  650. end;
  651.  
  652. procedure clrinx(pt,inx,val:word);
  653. var x:word;
  654. begin
  655.   x:=rdinx(pt,inx);
  656.   wrinx(pt,inx,x and (not val));
  657. end;
  658.  
  659. procedure setreg(reg,val:word);
  660. begin
  661.   outp(reg,inp(reg) or val);
  662. end;
  663.  
  664. procedure clrreg(reg,val:word);
  665. begin
  666.   outp(reg,inp(reg) and (not val));
  667. end;
  668.  
  669. procedure modregw(reg,mask,nwv:word);  {In register REG sets the bits in
  670.                                        MASK as in NWV other are left unchanged}
  671. var temp:word;
  672. begin
  673.   temp:=(inpw(reg) and (not mask))+(nwv and mask);
  674.   outpw(reg,temp);
  675. end;
  676.  
  677. procedure setregw(reg,val:word);
  678. begin
  679.   outpw(reg,inpw(reg) or val);
  680. end;
  681.  
  682. procedure clrregw(reg,val:word);
  683. begin
  684.   outpw(reg,inpw(reg) and (not val));
  685. end;
  686.  
  687.  
  688.   {The LOG functions writes output data to both the screen and the file
  689.    WHATVGA.TXT, to provide a log in case of lockup}
  690. var
  691.   logfile:text;
  692.   wrscr:boolean;
  693.  
  694. procedure openlog(scr:boolean);
  695. begin
  696.   assign(logfile,'whatvga.txt');
  697.   rewrite(logfile);
  698.   wrscr:=scr;
  699.   if scr then SetTextMode;
  700. end;
  701.  
  702. procedure wrlog(s:string);
  703. begin
  704.   if wrscr then writeln(s);
  705.   writeln(logfile,s);
  706. end;
  707.  
  708. procedure closelog;
  709. begin
  710.   close(logfile);
  711. end;
  712.  
  713.  
  714.  
  715.  
  716.   {Select the mode to use for the clock test, preferable a 25.175MHz one!
  717.    Returns the frequency (in kHz for the base freq}
  718. function setstdmode:longint;
  719. var md:integer;
  720. begin
  721.   setstdmode:=25175;
  722.   case cv.chip of
  723.     __Mach32:md:=$321;
  724.     __Mach64:begin
  725.                md:=$1292;
  726.                setstdmode:=28322;
  727.              end;
  728.   {  __Compaq:if cv.version>=CPQ_QV then md:=$32
  729.                                    else md:=$12; }
  730.        __AGX:begin
  731.                md:=$64;
  732.                setstdmode:=44900;
  733.              end;
  734.   else md:=$12;
  735.   end;
  736.   if setmode(md,false) then;
  737. end;
  738.  
  739.  
  740. function Vretrace:boolean;
  741. begin
  742.   case cv.chip of
  743.     __Mach64:VRetrace:=memw[cv.Xseg:$12]>=memw[cv.Xseg:$0A];
  744.     __Mach32:VRetrace:=inpw($CEEE)>=inpw($CAEE);   {Hm!!}
  745.        __AGX:if (inp(cv.IOadr+5) and 1)>0 then
  746.              begin
  747.                outp(cv.IOadr+5,1);  {Reset blanking flag}
  748.                VRetrace:=true;
  749.              end
  750.              else Vretrace:=false;
  751.   else
  752.     VRetrace:=(inp(crtc+6) and 8)>0;     {3D4h/3B4h}
  753.   end;
  754. end;
  755.  
  756.  
  757. function getticks:longint;
  758. var cnt,stp:longint;
  759.     stat,x:word;
  760. begin
  761.   stat:=crtc+6;
  762.   disable;
  763.   stp:=200000;
  764.   cnt:=0;
  765.  
  766.   while not VRetrace and (stp>0) do dec(stp);
  767.   while VRetrace and (stp>0) do dec(stp);
  768.   while not VRetrace and (stp>0) do dec(stp);
  769.  
  770.   if stp>0 then
  771.     for x:=1 to 5 do
  772.     begin
  773.       while VRetrace and (cnt<1000000) do inc(cnt);
  774.       while not VRetrace and (cnt<1000000) do inc(cnt);
  775.     end;
  776.  
  777.   enable;
  778.   getticks:=cnt;
  779. end;
  780.  
  781.  
  782. procedure progICD2061reg(clk:longint);
  783. const
  784.   ser_clk=4;
  785.   ser_dta=8;
  786. var
  787.   old,dta,bit:word;
  788. procedure setbits(bits:word);
  789. begin
  790.   outp($3C2,bits);
  791.   for bits:=1 to 5 do;   {delay}
  792. end;
  793.  
  794. begin
  795.   if cv.chip=__S3 then  {Needs to enable the ICD for the STB Pegasus...}
  796.   begin
  797.     outpw(crtc,$4838);
  798.     outpw(crtc,$A539);    {Enable S3 Ext}
  799.     modinx(crtc,$42,$F,3);
  800.   end;
  801.   old:=inp($3CC);
  802.   outpw(SEQ,$100);
  803.   dta:=(old and $F3)+ser_dta;
  804.   for bit:=1 to 6 do
  805.   begin
  806.     setbits(dta+ser_clk);
  807.     setbits(dta);
  808.   end;
  809.   dta:=dta and $F3;
  810.   setbits(dta);
  811.   setbits(dta+ser_clk);
  812.   setbits(dta);
  813.   setbits(dta+ser_clk);
  814.  
  815.   for bit:=1 to 24 do
  816.   begin
  817.     dta:=dta and $F3;
  818.     if (clk and 1)=0 then dta:=dta+ser_dta;
  819.     setbits(dta+ser_clk);
  820.     setbits(dta);
  821.     dta:=dta xor ser_dta;
  822.     setbits(dta);
  823.     setbits(dta+ser_clk);
  824.     clk:=clk shr 1;
  825.   end;
  826.   dta:=dta or ser_dta;
  827.   setbits(dta+ser_clk);
  828.   setbits(dta);
  829.   setbits(dta+ser_clk);
  830.   setbits(dta);
  831.   outp($3C2,old);
  832.   if cv.chip=__S3 then
  833.   begin
  834.     modinx(crtc,$5C,3,2);
  835.     outpw(crtc,$5A39);    {Disable S3 Ext}
  836.     outpw(crtc,$38);
  837.   end;
  838.   outpw(SEQ,$300);
  839.   delay(15);
  840. end;
  841.  
  842.  
  843. const
  844.   clkperm:integer=0;
  845.  
  846. function ClockPermission:boolean;
  847. begin
  848.   if clkperm=0 then
  849.   begin
  850.     settextmode;
  851.     writeln('WHATVGA is about to test the clock chip or crystals on your');
  852.     writeln('board. This can cause strange behavior on the display.');
  853.     writeln('If your monitor is fixed-frequency (MDA, CGA, EGA or original');
  854.     writeln('VGA, in fact anything that can''t handle at least 800x600) this');
  855.     writeln('could in extreme situations potentionally hurt your monitor.');
  856.     writeln('Press Y to continue clock testing, any other key to skip it:');
  857.     if (getkey and $DF)=ord('Y') then clkperm:=1
  858.                                  else clkperm:=2;
  859.   end;
  860.   ClockPermission:=clkperm=1;
  861. end;
  862.  
  863. procedure findclocks;
  864. var clks,x,y,divi,divid:word;
  865.   basefreq,baselevel,l,l0,l1:longint;
  866.   progcheck:boolean;    {Should we check for programmable clocks??}
  867. begin
  868.   if (inp($3CC) and 1)>0 then crtc:=$3D4 else crtc:=$3B4;
  869.   progcheck:=true;
  870.   clks:=4;
  871.   case cv.clktype of
  872.      clk_ext3:clks:=8;
  873.      clk_ext4:clks:=16;
  874.      clk_ext5:clks:=32;
  875.      clk_ext6:clks:=64;
  876.      clk_sdac:progcheck:=false;
  877.   clk_TVP302x:begin
  878.                 progcheck:=false;
  879.                 clks:=0;
  880.               end;
  881.   end;
  882.  
  883.   if (clks>0) and ClockPermission then
  884.   begin
  885.     memmode:=_PL4;
  886.     basefreq:=SetStdMode;   {Usually mode 12h, but...}
  887.     y:=getclk(divi,divid);
  888.     baselevel:=getticks;
  889.     if baselevel>0 then
  890.       for x:=0 to clks-1 do
  891.       begin
  892.         if (x=8) and (cv.chip=__compaq) and (cv.version>=CPQ_QV) then
  893.            vio($32); {Hack to get at last 8 clock of QVision}
  894.         setclk(x,divid);
  895.         delay(50);   {Let clock settle}
  896.         l:=getticks;
  897.         if l>0 then cv.clks[x]:=((basefreq*baselevel) div l)*(divi div 12);
  898.       end;
  899.     setclk(y,divid);
  900.   end;
  901.   if progcheck and ClockPermission then
  902.   begin
  903.     outp($3C2,(inp($3CC) and $F3) or $8);   {Clk 2}
  904.     delay(150);
  905.     progICD2061reg($C00000);
  906.     progICD2061reg($41A83C);  {14.318MHz* 2 * 109/62 = 50.35 MHz}
  907.     l0:=getticks;
  908.     progICD2061reg($41A8BC);  {14.318MHz* 2/2 * 109/62 = 25.175 MHz}
  909.     l1:=getticks;
  910.  
  911.     if (l0<>0) and (abs(l1-l0*2)<25) then
  912.     begin                    {Found an ICD2061}
  913.       cv.clktype:=clk_ICD2061;
  914.       progICD2061reg($C04000);  {Set prescale bit to *4}
  915.       progICD2061reg($59A8BC);  {14.318MHz* 4/2 * 109/62 = 50.35 MHz}
  916.       l:=getticks;
  917.       if abs(l1-l*2)<25 then  {Prescale bit exists = ICD2061A}
  918.         cv.clktype:=clk_ICD2061A;
  919.       progICD2061reg($C00000);  {Restore ?}
  920.     end;
  921.     setclk(y,divid);
  922.   end;
  923.  
  924. end;
  925.  
  926.  
  927. procedure SelectVideo(item:word);
  928. begin
  929.   cv:=vid[item];
  930.   loadmodes;
  931.   video:=header[cv.chip];
  932.   settextmode;
  933. end;
  934.  
  935.  
  936. procedure dac2pel;    {Force DAC back to PEL mode}
  937. begin
  938.   if inp($3c8)=0 then;
  939. end;
  940.  
  941. function trigdac:word;  {Reads $3C6 4 times}
  942. var x:word;
  943. begin
  944.   x:=inp($3c6);
  945.   x:=inp($3c6);
  946.   x:=inp($3c6);
  947.   if (cv.dactype=_dacMU1880) then x:=inp($3C6);
  948.   trigdac:=inp($3c6);
  949. end;
  950.  
  951. procedure dac2comm;    {Enter command mode of HiColor DACs}
  952. begin
  953.   dac2pel;
  954.   daccomm:=trigdac;
  955. end;
  956.  
  957. function getdaccomm:word;
  958. begin
  959.   {if cv.DAC_RS2<>0 then getdaccomm:=inp($3C6+cv.DAC_RS2)
  960.   else} begin
  961.     dac2comm;
  962.     getdaccomm:=inp($3C6);
  963.     dac2pel;
  964.   end;
  965. end;
  966.  
  967. const
  968.   SavedDACpage:word=0;  {DAC page state saved by SaveDACpage, reset by clearDACpage}
  969.  
  970. procedure SaveDACpage;
  971. begin
  972.   SavedDACpage:=0;   {default}
  973.   if (cv.flags and FLG_ExtDAC)>0 then   {RS2/3 addressing ?}
  974.     case cv.chip of
  975.       __S3:begin
  976.              outpw(crtc,$4838);  {Unlock S3 regs}
  977.              outpw(crtc,$A539);
  978.              SavedDACpage:=(rdinx(crtc,$43) and 2) shl 1;
  979.              if (cv.version>S3_924) and (SavedDACpage=0) then
  980.                SavedDACpage:=(rdinx(crtc,$55) and 3) shl 2;
  981.              if (rdinx(crtc,$5C) and $20)>0 then inc(SavedDACpage,16);
  982.              outpw(crtc,$5A39);
  983.              outpw(crtc,$38);  {Lock S3 regs}
  984.            end;
  985.     end;
  986. end;
  987.  
  988.  
  989. const
  990.   DACpage:boolean=false;  {Set if DAC registers enabled (MGA,Weitek..)}
  991.  
  992.   {Returns the address of the DAC register selected by index (0..3
  993.    for standard DACs, 0..7 or 0..15 for advanced DACs), and sets
  994.    any necessary flags. }
  995. function setDACpage(index:word):word;
  996. const
  997.   DACadr:array[0..3] of word=($3C8,$3C9,$3C6,$3C7);
  998.   M32DACadr:array[0..3] of word=($2EC,$2ED,$2EA,$2EB);
  999. var ret,x:word;
  1000.     found:boolean;
  1001. begin
  1002.   found:=true;
  1003.   ret:=DACadr[index and 3];
  1004.   if cv.chip=__AGX then outp(cv.IOadr,1);   {Enable VGA regs}
  1005.   if (cv.flags and FLG_ExtDAC)>0 then   {RS2/3 addressing ?}
  1006.     case cv.chip of
  1007.        __AGX:begin
  1008.                if index>7 then ret:=cv.spcreg+(index and 3);
  1009.                if (index and 4)>0 then outp(cv.IOadr+10,$51)
  1010.                                   else outp(cv.IOadr+10,0);
  1011.              end;
  1012.        __ATI:if cv.Version<ATI_GUP_3 then found:=false
  1013.              else modinx(cv.IOadr,$A0,$60,index shl 3);
  1014.     __Compaq:begin
  1015.                if (index and 4)>0 then inc(ret,$8000);
  1016.                if (index and 8)>0 then inc(ret,$1000);
  1017.              end;
  1018.     __Mach32:begin
  1019.               { modinx(cv.IOadr,$A0,$60,index shl 3);}
  1020.                x:=inp($8EEF) and $CF;
  1021.                outp($7AEF,x+((index and $C) shl 2));
  1022.                ret:=ret-$DC;   {3C8 -> 2EC}
  1023.              end;
  1024.     __Mach64:begin
  1025.                outp($62EC,index shr 2);
  1026.                ret:=$5EEC+(index and 3);
  1027.              end;
  1028.        __MGA:begin
  1029.                if (not DACpage) and (cv.PCIid>0) then
  1030.                begin
  1031.                  wPCIlong($10,$AC000);  {Map ACC regs at AC000h}
  1032.                  cv.Xseg:=$AC00;
  1033.                  DACpage:=true;
  1034.                end;
  1035.                ret:=0;
  1036.              end;
  1037.        __NCR:ret:=ret+((index and 4) shl 13);    {A15 = $8000}
  1038.         __S3:begin
  1039.                outpw(crtc,$4838);  {Unlock S3 regs}
  1040.                outpw(crtc,$A539);
  1041.                if cv.version>S3_924 then
  1042.                begin
  1043.                  clrinx(crtc,$43,2);    {Just in case}
  1044.                  modinx(crtc,$55,3,index shr 2);
  1045.                  modinx(crtc,$5C,$20,index shl 1);   {TVP3025 control}
  1046.                end
  1047.                else modinx(crtc,$43,2,index shr 1);
  1048.                outpw(crtc,$5A39);
  1049.                outpw(crtc,$38);  {Lock S3 regs}
  1050.              end;
  1051.      __Tseng:begin
  1052.                outp($3BF,3);
  1053.                outp(crtc+4,$A0);
  1054.                modinx(crtc,$31,$40,index shl 4);   {Chrontel DAC}
  1055.              end;
  1056.             {Diamond Viper w/ OAK }
  1057.        __OAK:ret:=ret+(index and $C) shl 12;
  1058.     __Weitek,__WeitekP9:
  1059.              if (cv.version<WT_P9100) and (cv.PCIid=0) then
  1060.                ret:=ret+(index and $C) shl 12  {Non-PCI P9000s}
  1061.              else begin
  1062.                if not DACpage then
  1063.                begin
  1064.                  outp($9100,$41);
  1065.                  x:=inp($9104);
  1066.                  outp($9100,$41);
  1067.                  outp($9104,(x and $F3) or 4);   {Enable Acc regs at A000h}
  1068.                  DACpage:=true;
  1069.                end;
  1070.                ret:=0;
  1071.              end;
  1072.     else found:=false;
  1073.     end
  1074.   else found:=false;
  1075.   if not found and (index=dacHIcmd) then dac2comm;
  1076.   setDACpage:=ret;
  1077. end;
  1078.  
  1079.   {Clears any bits set by setDACpage. Should be used after a sequence
  1080.    of extended DAC register accesses to avoid problems with accessess
  1081.    to the standard DAC registers}
  1082. procedure clearDACpage;
  1083. var x:word;
  1084. begin
  1085.   if cv.chip=__AGX then outp(cv.IOadr,4);   {Disable VGA regs}
  1086.   if SavedDACpage>0 then
  1087.     x:=setDACpage(SavedDACpage)
  1088.   else begin
  1089.   if (cv.flags and FLG_ExtDAC)>0 then   {RS2/3 addressing ?}
  1090.     case cv.chip of
  1091.        __AGX:outp(cv.IOadr+10,0);
  1092.        __ATI:clrinx(cv.IOadr,$A0,$60);
  1093.     __Mach64:outp($62EC,0);
  1094.        __MGA:if DACpage then
  1095.                wPCIlong($10,PCIrec[cv.PCIid].l[4]);
  1096.         __S3:begin
  1097.                outpw(crtc,$4838);  {Unlock S3 regs}
  1098.                outpw(crtc,$A539);
  1099.                if cv.version>S3_924 then clrinx(crtc,$55,3);
  1100.                clrinx(crtc,$43,2);
  1101.                outpw(crtc,$5A39);
  1102.                outpw(crtc,$38);  {Lock S3 regs}
  1103.              end;
  1104.      __Tseng:begin
  1105.                outp($3BF,3);
  1106.                outp(crtc+4,$A0);
  1107.                clrinx(crtc,$31,$40);   {Chrontel DAC}
  1108.              end;
  1109.     __Weitek,__WeitekP9:
  1110.              if DACpage then
  1111.              begin
  1112.                outp($9100,$41);
  1113.                x:=inp($9104);
  1114.                outp($9100,$41);
  1115.                outp($9104,x and $F3);  {Disable Acc regs at A000h}
  1116.              end;
  1117.     else dac2pel;
  1118.     end
  1119.   else dac2pel;
  1120.   end;
  1121.   DACpage:=false;
  1122. end;
  1123.  
  1124.  
  1125.  
  1126. function rdDACreg(index:word):word;
  1127. var inx:word;
  1128. begin
  1129.   inx:=SetDACpage(index);
  1130.   if inx=0 then
  1131.     case cv.chip of
  1132.       __MGA:rdDACreg:=mem[cv.Xseg:$3C00+index*4];
  1133.       __Weitek,__WeitekP9:
  1134.             begin
  1135.               if mem[SegA000:$198]=0 then;    {Wait ?}
  1136.               rdDACreg:=mem[SegA000:$200+4*index];
  1137.             end;
  1138.     end
  1139.   else rdDACreg:=inp(inx);
  1140. end;
  1141.  
  1142. procedure wrDACreg(index,val:word);
  1143. var inx:word;
  1144. begin
  1145.   inx:=SetDACpage(index);
  1146.   if inx=0 then
  1147.     case cv.chip of
  1148.       __MGA:mem[cv.Xseg:$3C00+index*4]:=val;
  1149.       __Weitek,__WeitekP9:
  1150.             mem[SegA000:$200+4*index]:=val;
  1151.     end
  1152.   else outp(inx,val);
  1153. end;
  1154.  
  1155.  
  1156. procedure clrDACreg(index,val:word);
  1157. begin
  1158.   wrDACreg(index,rdDACreg(index) and not val);
  1159. end;
  1160.  
  1161. procedure setDACreg(index,val:word);
  1162. begin
  1163.   wrDACreg(index,rdDACreg(index) or val);
  1164. end;
  1165.  
  1166. procedure modDACreg(index,msk,val:word);
  1167. begin
  1168.   wrDACreg(index,(rdDACreg(index) and not msk) or (msk and val));
  1169. end;
  1170.  
  1171.  
  1172. function rgb(r,g,b:word):longint;
  1173. begin
  1174.   r:=lo(r);g:=lo(g);b:=lo(b);
  1175.   case memmode of
  1176.        _PL1,_PL1E,_CGA1:
  1177.             rgb:=r and 1;
  1178.        _PL2,_CGA2:
  1179.             rgb:=r and 3;
  1180.   _PL4,_PK4:rgb:=r and 15;
  1181.         _P8:rgb:=r;
  1182.        _P15:rgb:=((r shr 3) shl 5+(g shr 3)) shl 5+(b shr 3);
  1183.        _P16:rgb:=((r shr 3) shl 6+(g shr 2)) shl 5+(b shr 3);
  1184.   _P24,_P32:rgb:=(longint(r) shl 8+g) shl 8 +b;
  1185. _P24b,_P32b:rgb:=(longint(b) shl 8+g) shl 8 +r;
  1186.       _p32c:rgb:=((longint(r) shl 8+g) shl 8 +b) shl 8;
  1187.       _P32d:rgb:=((longint(b) shl 8+g) shl 8 +r) shl 8;
  1188.   end;
  1189. end;
  1190.  
  1191.  
  1192.   {Writes a 32bit value to a DWORD at offset ADR in Xseg}
  1193. procedure write32(adr:word;val:longint);
  1194. var w:word;
  1195. begin
  1196.   w:=cv.Xseg;
  1197.     {mov es,[cv.Xseg]  mov di,[BP+adr]  mov eax,[BP+val]  mov es:[di],eax}
  1198.   inline($8E/$46/<w/$8B/$7E/<adr/$66/$8B/$46/<val/$66/$26/$89/5);
  1199. end;
  1200.  
  1201.   {Writes a two 16bit values to a DWORD at offset ADR in Xseg as one MOVL}
  1202. procedure write32w(adr:word;hiw,low:word);
  1203. var w:word;
  1204.   l:longint;
  1205. begin
  1206.   l:=(longint(hiw) shl 16)+low;
  1207.   w:=cv.Xseg;
  1208.     {mov es,[cv.Xseg]  mov di,[BP+adr]  mov eax,[BP+l]  mov es:[di],eax}
  1209.   inline($8E/$46/<w/$8B/$7E/<adr/$66/$8B/$46/<l/$66/$26/$89/5);
  1210. end;
  1211.  
  1212.