home *** CD-ROM | disk | FTP | other *** search
- PROGRAM FastWrite;
- {
- FASTWR.PAS contains two fast, snow-and-flicker-free routines for writing
- directly to the video memory of IBM PC/XT/AT's and close compatibles. The
- notes below are mostly for those familiar with the older program of the same
- name, written by Marshall Brain. If you're not, you can skip over them. The
- demonstration program included here should give you a good idea of how to use
- both of the *new* FastWrite routines. By the way, if you need help with
- video attributes, see my FWATTR.INC, in data library 1 of the Borland SIG on
- CompuServe.
-
- Notes:
- This began as a minor revision to the original FastWrite, a terrific routine
- that unfortunately had a couple of bugs in it. But the new FASTWR.PAS now
- differs radically from the old, in more ways than I care to enumerate. What
- follows is a brief list of the more notable differences:
- 1. The new version no longer leaves interrupts disabled on exit, as the
- earlier one did when writing to color displays.
- 2. The new version clears the CH register, avoiding the old one's
- compatibility problem when used in conjunction with Turbo Extender
- (a product of Turbo Power Software).
- 3. The new version should be compatible with more PC clones than the
- old one, since it uses a more reliable method for determining the
- base address of video memory.
- 4. The new version accepts Row and Column parameters in Turbo Pascal
- format, rather than DOS format (1..25 and 1..80, rather than 0..24
- and 0..79). (If you wish, you can change this by deleting the
- code--it's labeled--that makes the conversion. Look for "DEC AX"
- and "DEC BX".)
- 5. The new version gives you the option of bypassing snow prevention
- (you have to figure out for yourself when to do so, however).
- 6. The new version should run faster on many machines than the old
- one did, *particularly* when snow prevention is disabled. (Do
- note that, if you ran benchmark tests on a machine with a color
- display, the old one would always come out ahead, since it
- disabled the timer tick interrupt.)
- 7. The new FASTWR.PAS includes a second routine, FastWriteV, to be
- used only with string variables. It can provide, maybe, a 5-30%
- speed increase (that's an educated guess), over the regular
- FastWrite, depending on the length of the string. (The extra
- speed is due to Turbo's not having to put the whole string on the
- stack, just an address; it has nothing to do with FastWriteV.)
- 8. This one comes with fully documented source code!
-
- Effusive thanks are due to Bela Lubkin and Kim Kokkonen, without whose
- help I'd still be at square one. But don't blame them if you find a
- problem with the routines here. Address all comments, complaints, etc.
- to Brian Foley, CompuServe ID # [76317,3247].
- }
-
- TYPE
- String80 = String[ 80 ];
- Registers = Record
- CASE Integer Of
- 1 : ( AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : Integer );
- 2 : ( AL,AH,BL,BH,CL,CH,DL,DH : Byte );
- END;
- VAR
- I : Byte; { Needed only for demo. }
- Bullet : String80; { ditto }
-
- Regs : Registers;
- WaitForRetrace : Boolean; { If False, FastWrite will use the faster
- "Mono" routine, regardless of display type. }
- BaseOfScreen : Integer; { Base address of screen memory. Note: Making
- this a typed constant will screw things up!
- FastWrite expects this to be a global variable
- located in the data segment. The same applies
- to WaitForRetrace. }
-
- PROCEDURE GetVideoMode;
- { Video mode of 7 indicates mono display; all other modes are for color
- displays. }
- BEGIN
- Regs.AH := $0F;
- Intr( $10, Regs );
- IF Regs.AL = 7 THEN BaseOfScreen := $B000 { Mono }
- ELSE BaseOfScreen := $B800; { Color }
- WaitForRetrace := ( BaseOfScreen = $B800 );
- { You may want to use some other, more sophisticated means to determine
- the value here, or you could allow the user to decide whether he wants
- to forego snow prevention in favor of faster screen updates. But...
- *VERY IMPORTANT* WaitForRetrace MUST be false if BaseOfScreen equals
- $B000. }
- END;
-
- PROCEDURE FastWrite( St : String80; Row, Col, Attr : Byte );
- {InLine code was assembled with Dave Baldwin's INLINE.COM, and uses its
- notation.}
- BEGIN
- Inline(
- $1E { PUSH DS ;Save DS}
- /$8B/$46/<Row { MOV AX,[BP+<Row] ;AX = Row}
- /$48 { DEC AX ;Row to 0..24 range}
- /$B9/$04/$00 { MOV CX,$0004 ;CL = 4; CH = 0}
- /$D3/$E0 { SHL AX,CL ;AX = Row * 16}
- /$89/$C3 { MOV BX,AX ;Store in BX}
- /$D1/$E0 { SHL AX,1 ;AX = Row * 32}
- /$D1/$E0 { SHL AX,1 ;AX = Row * 64}
- /$01/$D8 { ADD AX,BX ;AX = (Row * 64) + (Row * 16)}
- { ; = Row * 80}
- /$8B/$5E/<Col { MOV BX,[BP+<Col] ;BX = Column}
- /$4B { DEC BX ;Col to 0..79 range}
- /$01/$D8 { ADD AX,BX ;AX = (Row * 80) + Col}
- /$D1/$E0 { SHL AX,1 ;Account for attribute bytes}
- /$89/$C7 { MOV DI,AX ;Move result into DI}
- /$8D/$76/<St { LEA SI,[BP+<St] ;DS:SI will point to St[0]}
- /$8B/$16/>BaseOfScreen { MOV DX,[>BaseOfScreen] ;DX = Base address of screen}
- /$8E/$C2 { MOV ES,DX ;ES:DI points to Base:Row,Col}
- /$A0/>WaitForRetrace { MOV AL,[<WaitForRetrace] ;Grab this before changing DS}
- /$8C/$D2 { MOV DX,SS ;Move SS...}
- /$8E/$DA { MOV DS,DX ; into DS}
- /$8A/$0C { MOV CL,[SI] ;CL = Length(St)}
- /$E3/$29 { JCXZ Exit ;If string empty, Exit}
- /$46 { INC SI ;DS:SI points to St[1]}
- /$8A/$66/<Attr { MOV AH,[BP+<Attr] ;AH = Attribute}
- /$FC { CLD ;Set direction to forward}
- /$D0/$D8 { RCR AL,1 ;If WaitForRetrace is False...}
- /$73/$1C { JNC Mono ; use "Mono" routine}
- {; ** Color routine (used only when WaitForRetrace is True) **}
- /$BA/$DA/$03 { MOV DX,$03DA ;Point DX to CGA status port}
- /$AC {GetNext: LODSB ;Load next character into AL}
- { ; AH already has Attr}
- /$89/$C3 { MOV BX,AX ;Store video word in BX}
- /$B4/$09 { MOV AH,$09 ;Move horizontal & vertical}
- { ; retrace mask into AH}
- /$FA { CLI ;No interrupts now}
- /$EC {WaitH: IN AL,DX ;Get 6845 status}
- /$D0/$D8 { RCR AL,1 ;Wait for horizontal}
- /$72/$FB { JC WaitH ; retrace}
- /$EC {WaitV: IN AL,DX ;Get 6845 status again}
- /$20/$E0 { AND AL,AH ;Wait for vertical}
- /$74/$FB { JZ WaitV ; retrace}
- /$89/$D8 { MOV AX,BX ;Move word back to AX...}
- /$AB { STOSW ; and then to screen}
- /$FB { STI ;Allow interrupts!}
- /$E2/$EA { LOOP GetNext ;Get next character}
- /$E9/$04/$00 { JMP Exit ;Done}
- {; ** Mono routine (used whenever WaitForRetrace is False) **}
- /$AC {Mono: LODSB ;Load next character into AL}
- { ; AH already has Attr}
- /$AB { STOSW ;Move video word into place}
- /$E2/$FC { LOOP Mono ;Get next character}
- /$1F {Exit: POP DS ;Restore DS}
- );
- END;
-
-
- PROCEDURE FastWriteV( VAR St : String80; Row, Col, Attr : Byte );
- BEGIN
- Inline(
- $1E { PUSH DS}
- /$8B/$46/<Row { MOV AX,[BP+<Row]}
- /$48 { DEC AX}
- /$B9/$04/$00 { MOV CX,$0004}
- /$D3/$E0 { SHL AX,CL}
- /$89/$C3 { MOV BX,AX}
- /$D1/$E0 { SHL AX,1}
- /$D1/$E0 { SHL AX,1}
- /$01/$D8 { ADD AX,BX}
- /$8B/$5E/<Col { MOV BX,[BP+<Col]}
- /$4B { DEC BX}
- /$01/$D8 { ADD AX,BX}
- /$D1/$E0 { SHL AX,1}
- /$89/$C7 { MOV DI,AX}
- /$8B/$16/>BaseOfScreen { MOV DX,[>BaseOfScreen]}
- /$8E/$C2 { MOV ES,DX}
- /$A0/>WaitForRetrace { MOV AL,[<WaitForRetrace]}
- /$C5/$76/<St { LDS SI,[BP+<St] ;DS:SI points to St[0]}
- /$8A/$0C { MOV CL,[SI]}
- /$E3/$29 { JCXZ Exit}
- /$46 { INC SI}
- /$8A/$66/<Attr { MOV AH,[BP+<Attr]}
- /$FC { CLD}
- /$D0/$D8 { RCR AL,1}
- /$73/$1C { JNC Mono}
- /$BA/$DA/$03 { MOV DX,$03DA}
- /$AC {GetNext: LODSB}
- /$89/$C3 { MOV BX,AX}
- /$B4/$09 { MOV AH,$09}
- /$FA { CLI}
- /$EC {WaitH: IN AL,DX}
- /$D0/$D8 { RCR AL,1}
- /$72/$FB { JC WaitH}
- /$EC {WaitV: IN AL,DX}
- /$20/$E0 { AND AL,AH}
- /$74/$FB { JZ WaitV}
- /$89/$D8 { MOV AX,BX}
- /$AB { STOSW}
- /$FB { STI}
- /$E2/$EA { LOOP GetNext}
- /$E9/$04/$00 { JMP Exit}
- /$AC {Mono: LODSB}
- /$AB { STOSW}
- /$E2/$FC { LOOP Mono}
- /$1F {Exit: POP DS}
- );
- END;
-
-
- { Demonstration program. Delete next line to enable. }
- (*
- BEGIN
- ClrScr;
- Bullet := '* FASTER THAN A SPEEDING BULLET! *';
- GetVideoMode; { This MUST be executed before FastWrite is called. }
- FastWrite( 'FastWriting is still....', 6, 28, $0F );
- Delay( 1000 );
- FastWrite( '**********************************', 9, 23, $07 );
- FOR I := 10 TO 20 DO
- FastWriteV( Bullet, I, 23, $07 );
- FastWrite( '**********************************', 21, 23, $07 );
- END.
- (**)