home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / FASTWR.ZIP / FASTWR.PAS
Encoding:
Pascal/Delphi Source File  |  1987-01-26  |  23.4 KB  |  486 lines

  1. (*
  2.                         FASTWR.PAS 2.0
  3.  
  4.  FASTWR.PAS contains six fast, snow-and-flicker-free routines for writing
  5.  directly to (or reading from) the video memory of IBM PC/XT/AT's and close
  6.  compatibles.
  7.  
  8.                      CHANGES TO FASTWR.PAS
  9.  
  10.  New routines:
  11.  -------------
  12.  Attribute : Given Foreground and BackGround colors, Attribute will return
  13.    a properly coded video attribute, with the blink bit masked out.
  14.  EGAInstalled : Returns a Boolean result indicating whether an EGA is
  15.    installed or not.
  16.  ChangeAttribute : Changes the video attribute in the specified region of
  17.    the screen, leaving the characters untouched. I use this in moving bar
  18.    menus, myself.
  19.  FastWriteNA : By popular request, a version of FastWrite that uses the
  20.    existing screen attributes, so that you don't have to specify one.
  21.    NA stands for No Attribute.
  22.  MoveToScreen, MoveFromScreen : These are slightly optimized versions of
  23.    Bela Lubkin's routines of the same name. They differ in several minor
  24.    respects, most notably (a) the Length parameter asks for the number of
  25.    WORDS (integers) to move rather than BYTES and (b) they are a bit
  26.    faster with snow prevention off. If you haven't grabbed it already,
  27.    be sure to get Bela's WINDOW.PAS, which has several handy routines for
  28.    handling windows. My versions of MoveToScreen and MoveFromScreen can
  29.    be plugged in in place of his, but be sure to eliminate the "Shl 1"
  30.    instructions that go with the Length parameters in all his calls to
  31.    these routines.
  32.  
  33.   Changes to old routines (FastWrite, FastWriteV, GetVideoMode):
  34.   --------------------------------------------------------------
  35.   The first two have been further optimized for speed. FastWriteV is up to
  36.   40% faster than the previous version; FastWrite is faster too, but
  37.   proportionately the difference isn't so great. The most significant change
  38.   is in the algorithm used to determine when to write to the screen on a
  39.   CGA. This improvement was suggested to me by Bela. A slight optimization
  40.   in the calculation of offsets from BaseOfScreen (based on Row and Column
  41.   coordinates) is owed to Jim LeMay. The other improvements are minor, but
  42.   together they all make a difference.
  43.  
  44.   If you don't like the order of the parameters, change them. (Please don't
  45.   send me messages telling me that your preferred order is right and mine
  46.   is wrong.) In the previous version of FASTWR the paramaters were harder
  47.   to change/rearrange; now there should be no problems.
  48.  
  49.   GetVideoMode now uses inline code to get the current video mode from the
  50.   BIOS. It also sets WaitForRetrace to False if an EGA is being used.
  51.  
  52.   General notes:
  53.   --------------
  54.   FASTWR.PAS is designed to make it easily used as an $Include file.  The
  55.   demo program below is commented out -- delete the indicated line to run
  56.   it.
  57.  
  58.   The Inline code in EGAInstalled and GetVideoMode isn't there for speed, but
  59.   rather to avoid declaring any more global types and variables than were
  60.   necessary.
  61.  
  62.   In a vain attempt to keep this file small, I have cut out many of the
  63.   comments within the inline code. FastWrite is fully commented, though,
  64.   and anything that isn't commented in the other routines is duplicating
  65.   code in FastWrite. (Or, in the case of MoveToScreen, the code in
  66.   MoveFromScreen.)
  67.  
  68.   InLine code was assembled with Dave Baldwin's INLINE.COM, and uses its
  69.   notation.
  70.  
  71.   Please read all warnings that appear in the comments! In particular,
  72.   read everything about GetVideoMode, WaitForRetrace, and BaseOfScreen.
  73.  
  74.   Copyright (c) 1986 by Brian Foley
  75.   These routines may be freely used and distributed, for both private
  76.   and commercial use, so long as the routines themselves are not sold for
  77.   profit.
  78.  
  79.   Brian Foley [76317,3247]
  80.   TurboPower Software
  81. *)
  82.  
  83. {---------------------- begin FASTWR.INC -----------}
  84.  
  85. TYPE
  86.    String80 = String[ 80 ];
  87. VAR
  88.    WaitForRetrace : Boolean; { If False, FastWrite et al. will use the faster
  89.                                "Mono" routine, regardless of display type. }
  90.    BaseOfScreen   : Integer; { Base address of screen memory.  Note: Making
  91.                                this a typed constant will screw things up!
  92.                                FastWrite expects this to be a global variable
  93.                                located in the data segment. The same applies
  94.                                to WaitForRetrace. }
  95.  
  96. FUNCTION Attribute(Foreground, Background : Byte) : Byte;
  97.   {-Translates foreground and background colors into video attributes.
  98.     "And 127" masks out the blink bit. Add 128 to the result to set it.}
  99. BEGIN
  100.    Attribute := ((Background Shl 4) + Foreground) And 127;
  101. END;
  102.  
  103. FUNCTION EgaInstalled : Boolean;
  104.   {-Test for presence of the EGA. I have little idea how this works, but
  105.     it does.}
  106. BEGIN
  107. Inline(
  108.   $B8/$00/$12      {      MOV AX,$1200}
  109.   /$BB/$10/$00     {      MOV BX,$10}
  110.   /$B9/$FF/$FF     {      MOV CX,$FFFF}
  111.   /$CD/$10         {      INT $10}
  112.   /$31/$C0         {      XOR AX,AX}
  113.   /$81/$F9/$FF/$FF {      CMP CX,$FFFF}
  114.   /$74/$01         {      JE DONE}
  115.   /$40             {      INC AX}
  116.   /$88/$46/$04     {DONE: MOV [BP+$04],AL}
  117. );
  118. END;
  119.  
  120. PROCEDURE GetVideoMode;
  121.   {-Video mode of 7 indicates mono display; all other modes are for color
  122.     displays. This routine MUST be called before any of the screen writing
  123.     routines are used!}
  124. VAR
  125.      Mode : Integer;
  126. BEGIN
  127.      Inline(
  128.        $B4/$0F        {MOV AH,$F}
  129.        /$CD/$10       {INT $10}
  130.        /$30/$E4       {XOR AH,AH}
  131.        /$89/$46/<Mode {MOV [BP+<Mode],AX}
  132.      );
  133.      IF Mode = 7 THEN BaseOfScreen := $B000  { Mono }
  134.                  ELSE BaseOfScreen := $B800; { Color }
  135.      WaitForRetrace := (BaseOfScreen = $B800) And Not EgaInstalled;
  136.      { If WaitForRetrace is True, you may want to allow the user to decide
  137.        whether to forego snow prevention in favor of faster screen updates.
  138.        *VERY IMPORTANT*  WaitForRetrace MUST be false if BaseOfScreen = $B000. }
  139. END;
  140.  
  141. PROCEDURE FastWrite( St : String80; Row, Col, Attr : Byte );
  142.   {-Write St directly to video memory, without snow.}
  143. BEGIN
  144. Inline(
  145.   $1E                    {         PUSH DS                  ;Save DS}
  146.   /$31/$C0               {         XOR AX,AX                ;AX = 0}
  147.   /$88/$C1               {         MOV CL,AL                ;CL = 0}
  148.   /$8A/$AE/>Row          {         MOV CH,[BP+>Row]         ;CX = Row * 256}
  149.   /$FE/$CD               {         DEC CH                   ;Row to 0..24 range}
  150.   /$D1/$E9               {         SHR CX,1                 ;CX = Row * 128}
  151.   /$89/$CF               {         MOV DI,CX                ;Store in DI}
  152.   /$D1/$EF               {         SHR DI,1                 ;DI = Row * 64}
  153.   /$D1/$EF               {         SHR DI,1                 ;DI = Row * 32}
  154.   /$01/$CF               {         ADD DI,CX                ;DI = (Row * 160)}
  155.   /$8B/$8E/>Col          {         MOV CX,[BP+>Col]         ;CX = Column}
  156.   /$49                   {         DEC CX                   ;Col to 0..79 range}
  157.   /$D1/$E1               {         SHL CX,1                 ;Account for attribute bytes}
  158.   /$01/$CF               {         ADD DI,CX                ;DI = (Row * 160) + (Col * 2)}
  159.   /$8E/$06/>BaseOfScreen {         MOV ES,[>BaseOfScreen]   ;ES:DI points to Base:Row,Col}
  160.   /$8A/$0E/>WaitForRetrace{        MOV CL,[>WaitForRetrace] ;Grab this before changing DS}
  161.   /$8C/$D2               {         MOV DX,SS                ;Move SS...}
  162.   /$8E/$DA               {         MOV DS,DX                ; into DS}
  163.   /$8D/$B6/>St           {         LEA SI,[BP+>St]          ;DS:SI points to St[0]}
  164.   /$AC                   {         LODSB                    ;AX = Length(St); DS:SI -> St[1]}
  165.   /$91                   {         XCHG AX,CX               ;CX = Length; AL = Wait}
  166.   /$E3/$2A               {         JCXZ Exit                ;If string empty, Exit}
  167.   /$8A/$A6/>Attr         {         MOV AH,[BP+>Attr]        ;AH = Attribute}
  168.   /$FC                   {         CLD                      ;Set direction to forward}
  169.   /$D0/$D8               {         RCR AL,1                 ;If WaitForRetrace is False...}
  170.   /$73/$1D               {         JNC NoWait               ; use NoWait routine}
  171.   /$BA/$DA/$03           {         MOV DX,$03DA             ;Point DX to CGA status port}
  172.   /$AC                   {Next:    LODSB                    ;Load next character into AL}
  173.                          {                                  ; AH already has Attr}
  174.   /$89/$C3               {         MOV BX,AX                ;Store video word in BX}
  175.   /$FA                   {         CLI                      ;No interrupts now}
  176.   /$EC                   {WaitNoH: IN AL,DX                 ;Get 6845 status}
  177.   /$A8/$08               {         TEST AL,8                ;Check for vertical retrace}
  178.   /$75/$09               {         JNZ Store                ; In progress? go}
  179.   /$D0/$D8               {         RCR AL,1                 ;Else, wait for end of}
  180.   /$72/$F7               {         JC WaitNoH               ; horizontal retrace}
  181.   /$EC                   {WaitH:   IN AL,DX                 ;Get 6845 status again}
  182.   /$D0/$D8               {         RCR AL,1                 ;Wait for horizontal}
  183.   /$73/$FB               {         JNC WaitH                ; retrace}
  184.   /$89/$D8               {Store:   MOV AX,BX                ;Move word back to AX...}
  185.   /$AB                   {         STOSW                    ; and then to screen}
  186.   /$FB                   {         STI                      ;Allow interrupts}
  187.   /$E2/$E8               {         LOOP Next                ;Get next character}
  188.   /$EB/$04               {         JMP SHORT Exit           ;Done}
  189.   /$AC                   {NoWait:  LODSB                    ;Load next character into AL}
  190.                          {                                  ; AH already has Attr}
  191.   /$AB                   {         STOSW                    ;Move video word into place}
  192.   /$E2/$FC               {         LOOP NoWait              ;Get next character}
  193.   /$1F                   {Exit:    POP DS                   ;Restore DS}
  194. );
  195. END;
  196.  
  197.  
  198. PROCEDURE FastWriteV( VAR St; Row, Col, Attr : Byte );
  199.   {-Works with string variables ONLY. (I made St an untyped parameter
  200.     only to make this easier to use when type checking is on.) This is
  201.     just FastWrite optimized for use with string Variables, for times
  202.     when speed really matters.}
  203. BEGIN
  204. Inline(
  205.   $1E                    {         PUSH DS}
  206.   /$31/$C0               {         XOR AX,AX}
  207.   /$88/$C1               {         MOV CL,AL}
  208.   /$8A/$6E/<Row          {         MOV CH,[BP+<Row]}
  209.   /$FE/$CD               {         DEC CH}
  210.   /$D1/$E9               {         SHR CX,1}
  211.   /$89/$CF               {         MOV DI,CX}
  212.   /$D1/$EF               {         SHR DI,1}
  213.   /$D1/$EF               {         SHR DI,1}
  214.   /$01/$CF               {         ADD DI,CX}
  215.   /$8B/$4E/<Col          {         MOV CX,[BP+<Col]}
  216.   /$49                   {         DEC CX}
  217.   /$D1/$E1               {         SHL CX,1}
  218.   /$01/$CF               {         ADD DI,CX}
  219.   /$8E/$06/>BaseOfScreen {         MOV ES,[>BaseOfScreen]}
  220.   /$8A/$0E/>WaitForRetrace{        MOV CL,[>WaitForRetrace]}
  221.   /$C5/$76/<St           {         LDS SI,[BP+<St]          ;DS:SI points to St[0]}
  222.   /$AC                   {         LODSB}
  223.   /$91                   {         XCHG AX,CX}
  224.   /$E3/$29               {         JCXZ Exit}
  225.   /$8A/$66/<Attr         {         MOV AH,[BP+<Attr]}
  226.   /$FC                   {         CLD}
  227.   /$D0/$D8               {         RCR AL,1}
  228.   /$73/$1D               {         JNC NoWait}
  229.   /$BA/$DA/$03           {         MOV DX,$03DA}
  230.   /$AC                   {Next:    LODSB}
  231.   /$89/$C3               {         MOV BX,AX}
  232.   /$FA                   {         CLI}
  233.   /$EC                   {WaitNoH: IN AL,DX}
  234.   /$A8/$08               {         TEST AL,8}
  235.   /$75/$09               {         JNZ Store}
  236.   /$D0/$D8               {         RCR AL,1}
  237.   /$72/$F7               {         JC WaitNoH}
  238.   /$EC                   {WaitH:   IN AL,DX}
  239.   /$D0/$D8               {         RCR AL,1}
  240.   /$73/$FB               {         JNC WaitH}
  241.   /$89/$D8               {Store:   MOV AX,BX}
  242.   /$AB                   {         STOSW}
  243.   /$FB                   {         STI}
  244.   /$E2/$E8               {         LOOP Next}
  245.   /$EB/$04               {         JMP SHORT Exit}
  246.   /$AC                   {NoWait:  LODSB}
  247.   /$AB                   {         STOSW}
  248.   /$E2/$FC               {         LOOP NoWait}
  249.   /$1F                   {Exit:    POP DS}
  250. );
  251. END;
  252.  
  253. PROCEDURE FastWriteNA( St : String80; Row, Col : Byte );
  254.   {-Same as FastWrite, but no attribute byte paramater. String appears
  255.     in whatever attribute(s) was/were there to begin with.}
  256. BEGIN
  257. Inline(
  258.   $8C/$DB                {         MOV BX,DS                ;Save DS in BX}
  259.   /$31/$C0               {         XOR AX,AX}
  260.   /$88/$C1               {         MOV CL,AL}
  261.   /$8A/$AE/>Row          {         MOV CH,[BP+>Row]}
  262.   /$FE/$CD               {         DEC CH}
  263.   /$D1/$E9               {         SHR CX,1}
  264.   /$89/$CF               {         MOV DI,CX}
  265.   /$D1/$EF               {         SHR DI,1}
  266.   /$D1/$EF               {         SHR DI,1}
  267.   /$01/$CF               {         ADD DI,CX}
  268.   /$8B/$8E/>Col          {         MOV CX,[BP+>Col]}
  269.   /$49                   {         DEC CX}
  270.   /$D1/$E1               {         SHL CX,1}
  271.   /$01/$CF               {         ADD DI,CX}
  272.   /$8E/$06/>BaseOfScreen {         MOV ES,[>BaseOfScreen]}
  273.   /$8A/$0E/>WaitForRetrace{        MOV CL,[>WaitForRetrace]}
  274.   /$8C/$D2               {         MOV DX,SS}
  275.   /$8E/$DA               {         MOV DS,DX}
  276.   /$8D/$B6/>St           {         LEA SI,[BP+>St]}
  277.   /$AC                   {         LODSB}
  278.   /$91                   {         XCHG AX,CX}
  279.   /$E3/$27               {         JCXZ Exit}
  280.   /$FC                   {         CLD}
  281.   /$D0/$D8               {         RCR AL,1}
  282.   /$73/$1E               {         JNC NoWait}
  283.   /$BA/$DA/$03           {         MOV DX,$03DA}
  284.   /$AC                   {Next:    LODSB}
  285.   /$88/$C4               {         MOV AH,AL                ;Store char in AH}
  286.   /$FA                   {         CLI}
  287.   /$EC                   {WaitNoH: IN AL,DX}
  288.   /$A8/$08               {         TEST AL,8}
  289.   /$75/$09               {         JNZ Store}
  290.   /$D0/$D8               {         RCR AL,1}
  291.   /$72/$F7               {         JC WaitNoH}
  292.   /$EC                   {WaitH:   IN AL,DX}
  293.   /$D0/$D8               {         RCR AL,1}
  294.   /$73/$FB               {         JNC WaitH}
  295.   /$88/$E0               {Store:   MOV AL,AH                ;Move char back to AL...}
  296.   /$AA                   {         STOSB                    ; and then to screen}
  297.   /$FB                   {         STI}
  298.   /$47                   {         INC DI}
  299.   /$E2/$E7               {         LOOP Next}
  300.   /$EB/$04               {         JMP SHORT Exit}
  301.   /$A4                   {NoWait:  MOVSB                    ;Move character to screen}
  302.   /$47                   {         INC DI                   ;Skip attribute bytes}
  303.   /$E2/$FC               {         LOOP NoWait}
  304.   /$8E/$DB               {Exit:    MOV DS,BX                ;Restore DS from BX}
  305. );
  306. END;
  307.  
  308.  
  309. PROCEDURE ChangeAttribute( Number : Integer; Row, Col, Attr : Byte );
  310.   {-Number is the number of attribute bytes to change. Row and Col
  311.     indicate where to start changing video attributes. Attr is the
  312.     video attribute to use.}
  313. BEGIN
  314. Inline(
  315.   $8B/$4E/<Number        {         MOV CX,[BP+<Number]      ;CX = Number to change}
  316.   /$E3/$49               {         JCXZ Exit                ;If zero, Exit}
  317.   /$31/$C0               {         XOR AX,AX}
  318.   /$8A/$66/<Row          {         MOV AH,[BP+<Row]         ;AX = Row * 256}
  319.   /$FE/$CC               {         DEC AH                   ;Row to 0..24 range}
  320.   /$D1/$E8               {         SHR AX,1                 ;AX = Row * 128}
  321.   /$89/$C7               {         MOV DI,AX                ;Store in DI}
  322.   /$D1/$EF               {         SHR DI,1                 ;DI = Row * 64}
  323.   /$D1/$EF               {         SHR DI,1                 ;DI = Row * 32}
  324.   /$01/$C7               {         ADD DI,AX                ;DI = (Row * 160)}
  325.   /$8B/$46/<Col          {         MOV AX,[BP+<Col]         ;AX = Column}
  326.   /$D1/$E0               {         SHL AX,1                 ;Account for attribute bytes}
  327.   /$01/$C7               {         ADD DI,AX                ;DI = (Row*160) + ((Col+1)*2)}
  328.   /$4F                   {         DEC DI                   ;Adjust Col (-2), skip char (+1)}
  329.   /$8E/$06/>BaseOfScreen {         MOV ES,[>BaseOfScreen]}
  330.   /$8A/$46/<Attr         {         MOV AL,[BP+<Attr]        ;AL = Attribute}
  331.   /$FC                   {         CLD}
  332.   /$80/$3E/>WaitForRetrace/$01{    CMP Byte [>WaitForRetrace],1 ;Get wait state}
  333.   /$75/$1D               {         JNE  NoWait              ;If WaitForRetrace is False}
  334.                          {                                  ; use NoWait routine}
  335.   /$88/$C4               {         MOV AH,AL                ;Store attribute in AH}
  336.   /$BA/$DA/$03           {         MOV DX,$03DA}
  337.   /$FA                   {Next:    CLI}
  338.   /$EC                   {WaitNoH: IN AL,DX}
  339.   /$A8/$08               {         TEST AL,8}
  340.   /$75/$09               {         JNZ Store}
  341.   /$D0/$D8               {         RCR AL,1}
  342.   /$72/$F7               {         JC WaitNoH}
  343.   /$EC                   {WaitH:   IN AL,DX}
  344.   /$D0/$D8               {         RCR AL,1}
  345.   /$73/$FB               {         JNC WaitH}
  346.   /$88/$E0               {Store:   MOV AL,AH                ;Move attr back to AL...}
  347.   /$AA                   {         STOSB                    ; and then to screen}
  348.   /$FB                   {         STI}
  349.   /$47                   {         INC DI                   ;Skip characters}
  350.   /$E2/$EA               {         LOOP Next}
  351.   /$EB/$04               {         JMP SHORT Exit}
  352.   /$AA                   {NoWait:  STOSB                    ;Change the attribute}
  353.   /$47                   {         INC DI                   ;Skip characters}
  354.   /$E2/$FC               {         LOOP NoWait              ;Get next character}
  355.                          {Exit:                             ;Next instruction}
  356. );
  357. END;
  358.  
  359. PROCEDURE MoveFromScreen(VAR Source, Dest; Length : Integer);
  360.  {-Length = number of WORDS to move from video memory (source) to
  361.    dest.}
  362. BEGIN
  363.  Inline(
  364.   $8C/$DB              {         MOV BX,DS                ;Save DS in BX}
  365.   /$A0/>WaitForRetrace {         MOV AL,[>WaitForRetrace] ;Grab before changing DS}
  366.   /$C4/$7E/<Dest       {         LES DI,[BP+<Dest]        ;ES:DI points to Dest}
  367.   /$C5/$76/<Source     {         LDS SI,[BP+<Source]      ;DS:SI points to Source}
  368.   /$8B/$4E/<Length     {         MOV CX,[BP+<Length]      ;CX = Length}
  369.   /$FC                 {         CLD}
  370.   /$D0/$D8             {         RCR AL,1}
  371.   /$73/$19             {         JNC NoWait}
  372.   /$BA/$DA/$03         {         MOV DX,$03DA}
  373.   /$FA                 {Next:    CLI}
  374.   /$EC                 {WaitNoH: IN AL,DX}
  375.   /$A8/$08             {         TEST AL,8}
  376.   /$75/$09             {         JNZ Store}
  377.   /$D0/$D8             {         RCR AL,1}
  378.   /$72/$F7             {         JC WaitNoH}
  379.   /$EC                 {WaitH:   IN AL,DX}
  380.   /$D0/$D8             {         RCR AL,1}
  381.   /$73/$FB             {         JNC WaitH}
  382.   /$AD                 {Store:   LODSW                    ;Load next video word into AX}
  383.   /$FB                 {         STI                      ;Allow interrupts}
  384.   /$AB                 {         STOSW                    ;Store video word in Dest}
  385.   /$E2/$EC             {         LOOP Next}
  386.   /$EB/$02             {         JMP SHORT Exit}
  387.   /$F2/$A5             {NoWait:  REP MOVSW                ;That's it!}
  388.   /$8E/$DB             {Exit:    MOV DS,BX                ;Restore DS}
  389.  );
  390. END;
  391.  
  392. PROCEDURE MoveToScreen(VAR Source, Dest; Length : Integer);
  393.   {-Length = number of WORDS to move to video memory (dest) from source}
  394. BEGIN
  395.  Inline(
  396.   $1E                  {         PUSH DS                  ;Save DS}
  397.   /$A0/>WaitForRetrace {         MOV AL,[>WaitForRetrace]}
  398.   /$C4/$7E/<Dest       {         LES DI,[BP+<Dest]}
  399.   /$C5/$76/<Source     {         LDS SI,[BP+<Source]}
  400.   /$8B/$4E/<Length     {         MOV CX,[BP+<Length]}
  401.   /$FC                 {         CLD}
  402.   /$D0/$D8             {         RCR AL,1}
  403.   /$73/$1D             {         JNC NoWait}
  404.   /$BA/$DA/$03         {         MOV DX,$03DA}
  405.   /$AD                 {Next:    LODSW                    ;Load next video word into AX}
  406.   /$89/$C3             {         MOV BX,AX                ;Store video word in BX}
  407.   /$FA                 {         CLI}
  408.   /$EC                 {WaitNoH: IN AL,DX}
  409.   /$A8/$08             {         TEST AL,8}
  410.   /$75/$09             {         JNZ Store}
  411.   /$D0/$D8             {         RCR AL,1}
  412.   /$72/$F7             {         JC WaitNoH}
  413.   /$EC                 {WaitH:   IN AL,DX}
  414.   /$D0/$D8             {         RCR AL,1}
  415.   /$73/$FB             {         JNC WaitH}
  416.   /$89/$D8             {Store:   MOV AX,BX                ;Move word back to AX...}
  417.   /$AB                 {         STOSW                    ; and then to screen}
  418.   /$FB                 {         STI                      ;Allow interrupts}
  419.   /$E2/$E8             {         LOOP Next}
  420.   /$EB/$02             {         JMP SHORT Exit}
  421.   /$F2/$A5             {NoWait:  REP MOVSW}
  422.   /$1F                 {Exit:    POP DS                   ;Restore DS}
  423. );
  424. END;
  425. {---------------------- end of FASTWR.INC -----------}
  426.  
  427. { Demonstration program.  Delete next line to enable. }
  428. (*
  429. VAR
  430.    Fore, Back,
  431.    I, Attr        : Byte;
  432.    ScreenBuffer   : Array[1..2000] of Integer;
  433.    N : Integer;
  434.    C : Char;
  435. CONST
  436.    Bullet : String80 = '* FASTER THAN A SPEEDING BULLET! *';
  437. BEGIN
  438.      GetVideoMode;
  439.      IF WaitForRetrace THEN BEGIN
  440.         Write('Does your screen generate snow? ');
  441.         Read(KBD, C);
  442.         WaitForRetrace := (UpCase(C) = 'Y');
  443.      END;
  444.      IF BaseOfScreen = $B000 THEN BEGIN
  445.         Fore := White;
  446.         Back := Black;
  447.      END
  448.      ELSE BEGIN
  449.         Fore := White; { make these whatever you want }
  450.         Back := Magenta;
  451.      END;
  452.      Attr := Attribute( Fore, Back );
  453.      TextColor( Fore );
  454.      TextBackground( Back );
  455.      ClrScr;
  456.      FastWrite(   'FastWriting is still even...', 6, 26, Attr );
  457.      Delay( 2000 );
  458.      FastWrite( '**********************************', 9, 23, Attr );
  459.      FOR I := 10 TO 20 DO
  460.          FastWriteV( Bullet, I, 23, Attr );
  461.      FastWrite( '**********************************', 21, 23, Attr );
  462.      { now save the entire screen }
  463.      MoveFromScreen( Mem[BaseOfScreen:0], ScreenBuffer, 2000 );
  464.      { now let's play with the saved screen, setting blink bits }
  465.      FOR N := 1 TO 2000 DO
  466.           ScreenBuffer[N] := ScreenBuffer[N] Xor $8000;
  467.      Delay( 2000 );
  468.      FastWrite(   'Changing attribute bytes....', 6, 26, Attr );
  469.      Delay( 2000 );
  470.      Attr := Attribute( Back, Fore );
  471.      { now some reverse video }
  472.      ChangeAttribute( 2000, 1, 1, Attr );
  473.      FOR I := 10 TO 20 DO
  474.          FastWrite( 'IS PRETTY DARNED FAST NOW TOO!', I, 25, Attr );
  475.      Delay( 2000 );
  476.      FastWrite( 'But who says you need to....', 6, 26, Attr );
  477.      Delay( 2000 );
  478.      { now write fast without messing with attributes }
  479.      FOR I := 10 TO 20 DO
  480.          FastWriteNA( 'MESS WITH THE ATTRIBUTE BYTES?', I, 25 );
  481.      Delay( 2000 );
  482.      { now restore the blinking version of the screen we saved }
  483.      MoveToScreen( ScreenBuffer, Mem[BaseOfScreen:0], 2000 );
  484. END.
  485. (**)
  486.