home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
PROGRAM
/
MISCPAS.ZIP
/
FASTWR.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-06-23
|
12KB
|
214 lines
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.
(**)