[comp.graphics] IBM CGA, using Stack Pushes to Screen Memory

alf@edstip.EDS.COM (John Hamill) (07/15/89)

I am writing a MASM program for the IBM PC CGA monitor.  I am setting the
stack pointer to the screen memory and using PUSHes to move data to this
area of the screen.  This works fine for the whole screen, but when I
do a small rectangle area there is a problem.  The problem is:  I think
the computer is doing an interupt and pushing and poping from the stack,
which is the screen, so now there is garbage on the screen.  This doesn't
happen when I do the whole screen becouse I write over the whole screen and
this writes over the garbage.  Is there a way to make the computer not do
any interupts while I'm doing this screen push?  Any other comments would
be helpful.  I am doing this form of screen update becouse it is very very
fast, and I don't want to see the screen being painted, I want the screen
to snap to a new image.
-- 
 /~~|  |\  |\    John W. Hamill, EDS `""""""" UUCP: ...!uunet!edsews!edstip!alf 
 |  |  |/  |/    1400 N. Woodward Ave (. (. >       alf@edstip.EDS.COM          
 \__\_/^\_/|\_/  Bloomfield Hills,            Voice:(313)645-4524  Fax:645-4824 
           \/    MI 48013  * The above are my views only!!             

wiml@blake.acs.washington.edu (William Lewis) (07/15/89)

In article <313@edstip.EDS.COM> alf@edstip.EDS.COM (John Hamill) writes:
>I am writing a MASM program for the IBM PC CGA monitor.  I am setting the
>stack pointer to the screen memory and using PUSHes to move data to this
>area of the screen.  This works fine for the whole screen, but when I
>do a small rectangle area there is a problem.  The problem is:  I think
>the computer is doing an interupt and pushing and poping from the stack,
>which is the screen, so now there is garbage on the screen.  This doesn't
>happen when I do the whole screen becouse I write over the whole screen and
>this writes over the garbage.  Is there a way to make the computer not do
>any interupts while I'm doing this screen push?  Any other comments would
>be helpful.  I am doing this form of screen update becouse it is very very
>fast, and I don't want to see the screen being painted, I want the screen
>to snap to a new image.


    I've seen this question several times just recently. It makes me
wonder how well people read manuals. There are two ways around this problem
that just spring to mind.
    The first way is just enlarging on the kludge of PUSHing to screen memory.
(Ugh!). "Is there a way to make the computer not do any interrupts while
I'm doing this screen push?". Yes: turn off the interrupts!  This is done with
the "CLI" instruction. But remember to turn 'em back on with "STI". (Those
are CLear Interrupt flag, and STart Interrupts.) 
    The second way is what you should have done in the first place. Use
a REP MOVSB (or REP MOVSW or...) instruction. Not only is this instruction
uninterruptible (on mostm processors), but it is also faster. Not only
that, but you are using "the right opcode for the job", which tends
to get better results. 
    
    setflame(0);   /* end of message clean-up */

    --- phelliax
        "<incoherent>"

chasm@attctc.DALLAS.TX.US (Charles Marslett) (07/17/89)

In article <2820@blake.acs.washington.edu>, wiml@blake.acs.washington.edu (William Lewis) writes:
>     The first way is just enlarging on the kludge of PUSHing to screen memory.
> (Ugh!). "Is there a way to make the computer not do any interrupts while
> I'm doing this screen push?". Yes: turn off the interrupts!  This is done with
> the "CLI" instruction. But remember to turn 'em back on with "STI". (Those
> are CLear Interrupt flag, and STart Interrupts.) 
>     The second way is what you should have done in the first place. Use
> a REP MOVSB (or REP MOVSW or...) instruction. Not only is this instruction
> uninterruptible (on mostm processors), but it is also faster. Not only
> that, but you are using "the right opcode for the job", which tends
> to get better results. 

"Read the manual" applies to this comment as well.  See page 17-140 in the
386 Programmer's Ref. Manual from intel.  (I don't have the 8088 or 286 books
handy, but I believe they have identical, or at least equivalent, language
describing interrupts and the REP instructions.

To do a REP STOSB or REP MOVSB with interrupts off you had better bracket
it with a CLI and an STI just like the code above.  On the other hand,
interrupts don't modify the memory pointed to by ES:DI (usually ;^).

One final point, the CLI disables normal interrupts, not NMIs.  If you have
an odd computer that uses NMI for any normal operation, you may need to go
through some gyrations to disable and reenable them too.  (IBM's micro-
channel computers and Tandy's old 1000 are two cases that come to mind.)

>     --- phelliax

Charles Marslett
chasm@attctc.dallas.tx.us

cliff@ficc.uu.net (cliff click) (07/17/89)

In article <2820@blake.acs.washington.edu>, wiml@blake.acs.washington.edu (William Lewis) writes:
> [...] a REP MOVSB (or REP MOVSW or...) instruction. Not only is this 
> instruction uninterruptible (on most processors), [...]

Actually it *IS* interruptable on all processors that have it (i.e. i80x86),
however the return from interrupt will pick the block move back up where
it left off - it works just fine in the presence of interrupts.

-- 
Cliff Click, Software Contractor at Large
Business: uunet.uu.net!ficc!cliff, cliff@ficc.uu.net, +1 713 274 5368 (w).
Disclaimer: lost in the vortices of nilspace...       +1 713 568 3460 (h).

buck@siswat.UUCP (A. Lester Buck) (07/18/89)

In article <2820@blake.acs.washington.edu>, wiml@blake.acs.washington.edu (William Lewis) writes:
>
>     I've seen this question several times just recently. It makes me
> wonder how well people read manuals. There are two ways around this problem
> that just spring to mind.
>
>     The second way is what you should have done in the first place. Use
> a REP MOVSB (or REP MOVSW or...) instruction. Not only is this instruction
> uninterruptible (on mostm processors), but it is also faster.

You obviously don't read the manual yourself.

From iAPX86/88, 186/188 User's Manual, Hardware Reference, p 3-31:

"Repeated string sequences are interruptable; the processor recognizes
the interrupt before processing the next string element.  System interrupt
processing is not affected in any way.  Upon return from the interrupt,
the repeated operation is resumed from the point of interruption."

An interrupt is not recognized between the REP prefix and the MOVSB,
of course.

-- 
A. Lester Buck		...!texbell!moray!siswat!buck

d88-eli@nada.kth.se (Erik Liljencrantz) (07/18/89)

About the REP MOVSW: It is interuptable, and it does resume after an
interrupt accured, but don't use a segment override prefix!

It works fine to move from DS:[SI] to ES:[DI], and it's possible to
override a single MOVSW to use CS, ES or SS as it's sourcesegment, but
never use both REP and segment override! The segment prefix are forgotten
if an interrupt occurs!

BTW: The destination segment is always ES. Can't be overridden.

Perhaps this discussion has gone a little beside the point in comp.graphics.

Erik Liljencrantz		| "No silly quotes!"
d88-eli@nada.kth.se		|	Emraquel Tuta

mcripps@mtuxo.att.com (XMP12-M.CRIPPS) (07/21/89)

In article <313@edstip.EDS.COM>, alf@edstip.EDS.COM (John Hamill) writes:
> I am writing a MASM program for the IBM PC CGA monitor.  I am setting the
> stack pointer to the screen memory and using PUSHes to move data to this
> area of the screen.  This works fine for the whole screen, but when I
> do a small rectangle area there is a problem.  The problem is:  I think
> the computer is doing an interupt and pushing and poping from the stack,
> which is the screen, so now there is garbage on the screen.  This doesn't
> happen when I do the whole screen becouse I write over the whole screen and
> this writes over the garbage.  Is there a way to make the computer not do
> any interupts while I'm doing this screen push?  Any other comments would
> be helpful.  I am doing this form of screen update becouse it is very very
> fast, and I don't want to see the screen being painted, I want the screen
> to snap to a new image.

Well, you could disable interrupts in your routine (CLI instruction) and
reenable them when you are done (STI).  Unfortunately, this won't stop a
non-maskable interrupt.

Why don't you use the STOSB or STOSW instructions instead of PUSH.  These
instructions will store a value and increment the destination pointer
all in one.  With the REP prefix, they will do a whole loop, such as:

	MOV CX,WIDTH		; number of words horizontally
	MOV DI,ADDRESS		; location on screen
	MOV AX,VALUE		; value to store
    REP MOVSW

This will write WIDTH words of VALUE starting at ADDRESS.  I know PUSH is
fast, but I question whether:

	MOV CX,WIDTH
	MOV AX,VALUE
	MOV SP,ADDRESS
 here:	PUSH AX
	LOOP here

is any faster than using MOVSW.

Mike Cripps
mtuxo!mcripps
AT&T Bell Labs
Lincroft, NJ
(when used with REP) all in one

jxh@cup.portal.com (Jim - Hickstein) (07/27/89)

> Perhaps this discussion has gone a little beside the point in comp.graphics.
Notwithstanding that, I can't resist:

> About the REP MOVSW: It is interuptable, and it does resume after an
> interrupt accured, but don't use a segment override prefix!

> It works fine to move from DS:[SI] to ES:[DI], and it's possible to
> override a single MOVSW to use CS, ES or SS as it's sourcesegment, but
> never use both REP and segment override! The segment prefix are forgotten
> if an interrupt occurs!

Actually, you *can* write it so it will work on all 80x86 CPUs, to wit:
On 8086/8088 (and maybe '18x) the instruction will be restarted after an
interrupt at the last prefix byte, normally the REP.  On '286 and '386,
the entire sequence of prefix bytes is restarted.  This simply means that
if you use both a segment override and REP, you must put the segment override
last, so you can check for CX=0 and loop back, thus:

AGAIN:
	REP
	DS:	; I know this isn't MASM, but it's clearer for this example.
	STOSW
	LOOP	AGAIN		; finish interrupted REP

On the early machines, this will catch a premature exit of the REP owing to
an interrupt that restarted at the DS: prefix; on later machines, it will
never take the jump.  This is all explained in the 1979 "PRELIMINARY" 8086
Family User's Manual.  Don't they teach this stuff in school any more? :-)
Actually, the Family Manual says only that this should be avoided or run
with interrupts disabled, but that applies only when other fun prefixes
like LOCK are needed.  The extra check with LOOP is the conventional wisdom
among those who ought to know, but I have never actually tried it.
THEORETICALLY, the restarted string instruction fails to decrement CX (since
REP does that), and the LOOP compensates for this.  Perhaps someone may
know something about a later machine that makes this stop working.  That would
be just like Intel.

DO NOT disable interrupts during this operation unless it is ABSOLUTELY
necessary, as this can take quite a while to complete, in relative terms.

P.S. Beware the CX=0 nasty!  On early machines this means REPeat 10000h times,
on the newer ones 0 means 0.  How about that? :-)


-Jim Hickstein
Hanger-on Emeritus, 8086 Old-Timers' Home
jxh@cup.portal.com
...!sun!portal!cup.portal.com!jxh
"Egad!  This stuff is TEN YEARS OLD!"