home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / turbopas / fastwr.pas < prev    next >
Pascal/Delphi Source File  |  1994-03-05  |  12KB  |  214 lines

  1. PROGRAM FastWrite;
  2. {
  3.  FASTWR.PAS contains two fast, snow-and-flicker-free routines for writing
  4.  directly to the video memory of IBM PC/XT/AT's and close compatibles.  The
  5.  notes below are mostly for those familiar with the older program of the same
  6.  name, written by Marshall Brain.  If you're not, you can skip over them.  The
  7.  demonstration program included here should give you a good idea of how to use
  8.  both of the *new* FastWrite routines.  By the way, if you need help with
  9.  video attributes, see my FWATTR.INC, in data library 1 of the Borland SIG on
  10.  CompuServe.
  11.  
  12.  Notes:
  13.  This began as a minor revision to the original FastWrite, a terrific routine
  14.  that unfortunately had a couple of bugs in it.  But the new FASTWR.PAS now
  15.  differs radically from the old, in more ways than I care to enumerate.  What
  16.  follows is a brief list of the more notable differences:
  17.       1.  The new version no longer leaves interrupts disabled on exit, as the
  18.           earlier one did when writing to color displays.
  19.       2.  The new version clears the CH register, avoiding the old one's
  20.           compatibility problem when used in conjunction with Turbo Extender
  21.           (a product of Turbo Power Software).
  22.       3.  The new version should be compatible with more PC clones than the
  23.           old one, since it uses a more reliable method for determining the
  24.           base address of video memory.
  25.       4.  The new version accepts Row and Column parameters in Turbo Pascal
  26.           format, rather than DOS format (1..25 and 1..80, rather than 0..24
  27.           and 0..79). (If you wish, you can change this by deleting the
  28.           code--it's labeled--that makes the conversion. Look for "DEC AX"
  29.           and "DEC BX".)
  30.       5.  The new version gives you the option of bypassing snow prevention
  31.           (you have to figure out for yourself when to do so, however).
  32.       6.  The new version should run faster on many machines than the old
  33.           one did, *particularly* when snow prevention is disabled.  (Do
  34.           note that, if you ran benchmark tests on a machine with a color
  35.           display, the old one would always come out ahead, since it
  36.           disabled the timer tick interrupt.)
  37.       7.  The new FASTWR.PAS includes a second routine, FastWriteV, to be
  38.           used only with string variables.  It can provide, maybe, a 5-30%
  39.           speed increase (that's an educated guess), over the regular
  40.           FastWrite, depending on the length of the string.  (The extra
  41.           speed is due to Turbo's not having to put the whole string on the
  42.           stack, just an address; it has nothing to do with FastWriteV.)
  43.       8.  This one comes with fully documented source code!
  44.  
  45.     Effusive thanks are due to Bela Lubkin and Kim Kokkonen, without whose
  46.     help I'd still be at square one.  But don't blame them if you find a
  47.     problem with the routines here.  Address all comments, complaints, etc.
  48.     to Brian Foley, CompuServe ID # [76317,3247].
  49. }
  50.  
  51. TYPE
  52.      String80   = String[ 80 ];
  53.      Registers  = Record
  54.                     CASE Integer Of
  55.                        1 : ( AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : Integer );
  56.                        2 : ( AL,AH,BL,BH,CL,CH,DL,DH : Byte );
  57.                     END;
  58. VAR
  59.    I              : Byte;     { Needed only for demo. }
  60.    Bullet         : String80; { ditto }
  61.  
  62.    Regs           : Registers;
  63.    WaitForRetrace : Boolean; { If False, FastWrite will use the faster
  64.                                "Mono" routine, regardless of display type. }
  65.    BaseOfScreen   : Integer; { Base address of screen memory.  Note: Making
  66.                                this a typed constant will screw things up!
  67.                                FastWrite expects this to be a global variable
  68.                                located in the data segment. The same applies
  69.                                to WaitForRetrace. }
  70.  
  71. PROCEDURE GetVideoMode;
  72.   { Video mode of 7 indicates mono display; all other modes are for color
  73.     displays. }
  74. BEGIN
  75.      Regs.AH := $0F;
  76.      Intr( $10, Regs );
  77.      IF Regs.AL = 7 THEN BaseOfScreen := $B000  { Mono }
  78.                     ELSE BaseOfScreen := $B800; { Color }
  79.      WaitForRetrace := ( BaseOfScreen = $B800 );
  80.      { You may want to use some other, more sophisticated means to determine
  81.        the value here, or you could allow the user to decide whether he wants
  82.        to forego snow prevention in favor of faster screen updates.  But...
  83.        *VERY IMPORTANT*  WaitForRetrace MUST be false if BaseOfScreen equals
  84.        $B000. }
  85. END;
  86.  
  87. PROCEDURE FastWrite( St : String80; Row, Col, Attr : Byte );
  88.     {InLine code was assembled with Dave Baldwin's INLINE.COM, and uses its
  89.      notation.}
  90. BEGIN
  91.  Inline(
  92.   $1E                    {         PUSH DS                  ;Save DS}
  93.   /$8B/$46/<Row          {         MOV AX,[BP+<Row]         ;AX = Row}
  94.   /$48                   {         DEC AX                   ;Row to 0..24 range}
  95.   /$B9/$04/$00           {         MOV CX,$0004             ;CL = 4; CH = 0}
  96.   /$D3/$E0               {         SHL AX,CL                ;AX = Row * 16}
  97.   /$89/$C3               {         MOV BX,AX                ;Store in BX}
  98.   /$D1/$E0               {         SHL AX,1                 ;AX = Row * 32}
  99.   /$D1/$E0               {         SHL AX,1                 ;AX = Row * 64}
  100.   /$01/$D8               {         ADD AX,BX                ;AX = (Row * 64) + (Row * 16)}
  101.                          {                                  ;   = Row * 80}
  102.   /$8B/$5E/<Col          {         MOV BX,[BP+<Col]         ;BX = Column}
  103.   /$4B                   {         DEC BX                   ;Col to 0..79 range}
  104.   /$01/$D8               {         ADD AX,BX                ;AX = (Row * 80) + Col}
  105.   /$D1/$E0               {         SHL AX,1                 ;Account for attribute bytes}
  106.   /$89/$C7               {         MOV DI,AX                ;Move result into DI}
  107.   /$8D/$76/<St           {         LEA SI,[BP+<St]          ;DS:SI will point to St[0]}
  108.   /$8B/$16/>BaseOfScreen {         MOV DX,[>BaseOfScreen]   ;DX = Base address of screen}
  109.   /$8E/$C2               {         MOV ES,DX                ;ES:DI points to Base:Row,Col}
  110.   /$A0/>WaitForRetrace   {         MOV AL,[<WaitForRetrace] ;Grab this before changing DS}
  111.   /$8C/$D2               {         MOV DX,SS                ;Move SS...}
  112.   /$8E/$DA               {         MOV DS,DX                ; into DS}
  113.   /$8A/$0C               {         MOV CL,[SI]              ;CL = Length(St)}
  114.   /$E3/$29               {         JCXZ Exit                ;If string empty, Exit}
  115.   /$46                   {         INC SI                   ;DS:SI points to St[1]}
  116.   /$8A/$66/<Attr         {         MOV AH,[BP+<Attr]        ;AH = Attribute}
  117.   /$FC                   {         CLD                      ;Set direction to forward}
  118.   /$D0/$D8               {         RCR AL,1                 ;If WaitForRetrace is False...}
  119.   /$73/$1C               {         JNC Mono                 ; use "Mono" routine}
  120.                          {; ** Color routine (used only when WaitForRetrace is True) **}
  121.   /$BA/$DA/$03           {         MOV DX,$03DA             ;Point DX to CGA status port}
  122.   /$AC                   {GetNext: LODSB                    ;Load next character into AL}
  123.                          {                                  ; AH already has Attr}
  124.   /$89/$C3               {         MOV BX,AX                ;Store video word in BX}
  125.   /$B4/$09               {         MOV AH,$09               ;Move horizontal & vertical}
  126.                          {                                  ; retrace mask into AH}
  127.   /$FA                   {         CLI                      ;No interrupts now}
  128.   /$EC                   {WaitH:   IN AL,DX                 ;Get 6845 status}
  129.   /$D0/$D8               {         RCR AL,1                 ;Wait for horizontal}
  130.   /$72/$FB               {         JC WaitH                 ; retrace}
  131.   /$EC                   {WaitV:   IN AL,DX                 ;Get 6845 status again}
  132.   /$20/$E0               {         AND AL,AH                ;Wait for vertical}
  133.   /$74/$FB               {         JZ WaitV                 ; retrace}
  134.   /$89/$D8               {         MOV AX,BX                ;Move word back to AX...}
  135.   /$AB                   {         STOSW                    ; and then to screen}
  136.   /$FB                   {         STI                      ;Allow interrupts!}
  137.   /$E2/$EA               {         LOOP GetNext             ;Get next character}
  138.   /$E9/$04/$00           {         JMP Exit                 ;Done}
  139.                          {; ** Mono routine (used whenever WaitForRetrace is False) **}
  140.   /$AC                   {Mono:    LODSB                    ;Load next character into AL}
  141.                          {                                  ; AH already has Attr}
  142.   /$AB                   {         STOSW                    ;Move video word into place}
  143.   /$E2/$FC               {         LOOP Mono                ;Get next character}
  144.   /$1F                   {Exit:    POP DS                   ;Restore DS}
  145. );
  146. END;
  147.  
  148.  
  149. PROCEDURE FastWriteV( VAR St : String80; Row, Col, Attr : Byte );
  150. BEGIN
  151. Inline(
  152.   $1E                    {         PUSH DS}
  153.   /$8B/$46/<Row          {         MOV AX,[BP+<Row]}
  154.   /$48                   {         DEC AX}
  155.   /$B9/$04/$00           {         MOV CX,$0004}
  156.   /$D3/$E0               {         SHL AX,CL}
  157.   /$89/$C3               {         MOV BX,AX}
  158.   /$D1/$E0               {         SHL AX,1}
  159.   /$D1/$E0               {         SHL AX,1}
  160.   /$01/$D8               {         ADD AX,BX}
  161.   /$8B/$5E/<Col          {         MOV BX,[BP+<Col]}
  162.   /$4B                   {         DEC BX}
  163.   /$01/$D8               {         ADD AX,BX}
  164.   /$D1/$E0               {         SHL AX,1}
  165.   /$89/$C7               {         MOV DI,AX}
  166.   /$8B/$16/>BaseOfScreen {         MOV DX,[>BaseOfScreen]}
  167.   /$8E/$C2               {         MOV ES,DX}
  168.   /$A0/>WaitForRetrace   {         MOV AL,[<WaitForRetrace]}
  169.   /$C5/$76/<St           {         LDS SI,[BP+<St]          ;DS:SI points to St[0]}
  170.   /$8A/$0C               {         MOV CL,[SI]}
  171.   /$E3/$29               {         JCXZ Exit}
  172.   /$46                   {         INC SI}
  173.   /$8A/$66/<Attr         {         MOV AH,[BP+<Attr]}
  174.   /$FC                   {         CLD}
  175.   /$D0/$D8               {         RCR AL,1}
  176.   /$73/$1C               {         JNC Mono}
  177.   /$BA/$DA/$03           {         MOV DX,$03DA}
  178.   /$AC                   {GetNext: LODSB}
  179.   /$89/$C3               {         MOV BX,AX}
  180.   /$B4/$09               {         MOV AH,$09}
  181.   /$FA                   {         CLI}
  182.   /$EC                   {WaitH:   IN AL,DX}
  183.   /$D0/$D8               {         RCR AL,1}
  184.   /$72/$FB               {         JC WaitH}
  185.   /$EC                   {WaitV:   IN AL,DX}
  186.   /$20/$E0               {         AND AL,AH}
  187.   /$74/$FB               {         JZ WaitV}
  188.   /$89/$D8               {         MOV AX,BX}
  189.   /$AB                   {         STOSW}
  190.   /$FB                   {         STI}
  191.   /$E2/$EA               {         LOOP GetNext}
  192.   /$E9/$04/$00           {         JMP Exit}
  193.   /$AC                   {Mono:    LODSB}
  194.   /$AB                   {         STOSW}
  195.   /$E2/$FC               {         LOOP Mono}
  196.   /$1F                   {Exit:    POP DS}
  197. );
  198. END;
  199.  
  200.  
  201. { Demonstration program.  Delete next line to enable. }
  202. (*
  203.  BEGIN
  204.      ClrScr;
  205.      Bullet := '* FASTER THAN A SPEEDING BULLET! *';
  206.      GetVideoMode; { This MUST be executed before FastWrite is called. }
  207.      FastWrite( 'FastWriting is still....', 6, 28, $0F );
  208.      Delay( 1000 );
  209.      FastWrite( '**********************************', 9, 23, $07 );
  210.      FOR I := 10 TO 20 DO
  211.          FastWriteV( Bullet, I, 23, $07 );
  212.      FastWrite( '**********************************', 21, 23, $07 );
  213.  END.
  214. (**)