The MASM Forum Archive 2004 to 2012

Project Support Forums => MASM32 => Topic started by: rkhb on April 27, 2012, 06:57:19 PM

Title: wait_key.asm
Post by: rkhb on April 27, 2012, 06:57:19 PM
Hi there,

I had a look at \masm32\m32lib\wait_key.asm and I wonder for what purpose the crt__kbhit loop is used. The function crt__getch waits for a keystroke already and I see no change with or without the loop.

viele grüße
ralph
Title: Re: wait_key.asm
Post by: dedndave on April 27, 2012, 07:05:29 PM
that's a good question, Ralph   :bg
Title: Re: wait_key.asm
Post by: jj2007 on April 27, 2012, 08:12:26 PM
Warum einfach wenn's auch umständlich geht :bg
Title: Re: wait_key.asm
Post by: MichaelW on April 28, 2012, 02:14:58 AM
I think the kbhit loop was an attempt to limit the CPU utilization while waiting, based on the apparently incorrect (as tested under Windows 2000) assumption that getch would not limit the CPU utilization. Perhaps earlier versions of MSVCRT do not.
Title: Re: wait_key.asm
Post by: hutch-- on April 28, 2012, 02:25:36 AM
If this is the version you are talking about,



; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

    invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)

  @@:
    invoke Sleep, 1
    call crt__kbhit
    test eax, eax
    jz @B

    call crt__getch     ; recover the character in the keyboard
                        ; buffer and return it in EAX
    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


Its actually a "Sleep" API loop to ensure the idle loop yields while waiting for a keystroke.
Title: Re: wait_key.asm
Post by: dedndave on April 28, 2012, 02:55:53 AM
now, if we could only come up with a 16-bit version that wasn't a CPU hog   :P
if you let NTVDM wait for a key - no problem
but if you try to do other stuff, there is no way to block execution
Title: Re: wait_key.asm
Post by: MichaelW on April 28, 2012, 06:05:13 AM
In 16-bit code calling the MS-DOS Idle Handler from the wait loop might be worth a try. I seem to recall testing this at some point, under NTVDM I think, but I don't recall what the results were.
Title: Re: wait_key.asm
Post by: jj2007 on April 28, 2012, 06:43:23 AM
Quote from: hutch-- on April 28, 2012, 02:25:36 AM
Its actually a "Sleep" API loop to ensure the idle loop yields while waiting for a keystroke.

What the OP and Michael indicate is that crt__getch does yield even without the loop. And indeed the CPU stays put at 0% while waiting for the keystroke, so we can send the loop into retirement :wink
Title: Re: wait_key.asm
Post by: dedndave on April 28, 2012, 07:10:50 AM
Quote from: MichaelW on April 28, 2012, 06:05:13 AM
In 16-bit code calling the MS-DOS Idle Handler from the wait loop might be worth a try. I seem
to recall testing this at some point, under NTVDM I think, but I don't recall what the results were.

any idea how to do that ?
i didn't know there was such a thing
Title: Re: wait_key.asm
Post by: Neil on April 28, 2012, 07:50:00 AM
Dave if you remember when I was having problems with that text adventure you came up with the idea of using crt__kbhit to check whether a keypress was in the keyboard buffer, if there was then use crt__getch to extract the key value, otherwise carry on with other code before looping back to check crt__kbhit again.
Title: Re: wait_key.asm
Post by: MichaelW on April 28, 2012, 10:53:24 AM
Dave,

To call the Idle Handler you simply issue an Interrupt 28h. The Microsoft MS-DOS Programmer's Reference, version 5, recommends also issuing an MS-DOS Idle Call (Interrupt 2Fh, Function 1680h).
Title: Re: wait_key.asm
Post by: dedndave on April 28, 2012, 06:56:18 PM
thanks, Michael   :U

Neil - yah - that is a valid use of crt__kbhit - we wanted to do something else if the keyboard was idle
but - we need something similar for 16-bit programs
it's really easy to write a CPU hog in 16-bit
Title: Re: wait_key.asm
Post by: Neil on April 29, 2012, 07:05:47 AM
For 16 bit programs this is what I used :-

PUSH ES                        ;Save segment.
SUB AX,AX                     ;Get bottom
MOV ES,AX                     ;of memory.
MOV AL,ES:[041A]           ;Get head pointer.
MOV AH,ES:[041C]           ;Get tail pointer.
POP ES                           ;Restore segment.
CMP AH,AL                      ;Are they equal ?
JNE GETKEY                    ;No, get keyboard input.
Do other code then Loop again
Title: Re: wait_key.asm
Post by: sinsi on April 29, 2012, 07:19:55 AM

again:  mov ah,1
        int 16h
        jnz gotkey
        int 28h
        jmp again
gotkey:

For running DOS in a VM I setup a new int 28h

int28:  sti
        hlt
        jmp old28

CPU usage afterward is 0 instead of one core.
Title: Re: wait_key.asm
Post by: MichaelW on April 29, 2012, 05:34:31 PM
Running this code under NTVDM, only the MS-DOS Idle Call (Interrupt 2Fh, Function 1680h) drops the NTVDM CPU usage to 0. The other attempts left the usage at 99%.

.model small
.386
.stack
.data
.code
.startup
  @@:
    ;hlt
    ;int 28h
    mov ax, 1680h
    int 2Fh
    jmp @B
.exit
end

Title: Re: wait_key.asm
Post by: dedndave on April 29, 2012, 06:24:00 PM
yah - did some reading
you have to install your own INT 28h handler - something like sinsi did - it is initially just an IRET
the multiplex interrupt might be the way to go - provided the OS is recent enough to support it
Title: Re: wait_key.asm
Post by: FORTRANS on April 29, 2012, 09:26:23 PM
Quote from: dedndave on April 29, 2012, 06:24:00 PM
yah - did some reading
you have to install your own INT 28h handler - something like sinsi did - it is initially just an IRET
the multiplex interrupt might be the way to go - provided the OS is recent enough to support it

Hi,

   Int 28H and Int 2FH were introduced in MS-DOS 2.0 to support
the PRINT command.  That was to allow PRINT to operate in the
background.  To limit CPU usage in some of my code I use something
similar to what sinsi posted.  I just put a HLT in the test for a key
loop.  That was done to reduce power usage on the HP 200LX
palmtop.

Regards,

Steve N.
Title: Re: wait_key.asm
Post by: MichaelW on April 29, 2012, 10:41:28 PM
Running on a P3, HLT in a loop had no apprent effect under NTVDM.
Title: Re: wait_key.asm
Post by: dedndave on April 29, 2012, 11:07:34 PM
yah - that's what i was afraid of   :P
NTVDM probably ignores HLT instructions altogether
Title: Re: wait_key.asm
Post by: FORTRANS on April 30, 2012, 01:00:19 PM
Hi,

   Well a quick test of HLT shows no effect with a Win2k NTVDM
or an OS/2 VDM on my P-III.  Using the graphical CPU meters
of each.  Got a way to measure CPU usage under plain DOS?

   With the MS-DOS 5.0 on the 200LX I used an amp meter.
But I can't find what the actual numbers were anymore...

Regards,

Steve N.
Title: Re: wait_key.asm
Post by: hutch-- on April 30, 2012, 01:19:07 PM
Illuminate me here, with a non-re-entrant OS like MS-DOS, what is the point of looking for a wait instruction/sequence/interrupt when only one task is running ? Surely you just shove a test in the polling loop for something like a keystroke or mouse event (if I vagely remember int 33h correctly) and let the processor ping its heart out ?
Title: Re: wait_key.asm
Post by: sinsi on April 30, 2012, 01:25:35 PM
From the Intel docs
QuoteThe HLT instruction is a privileged instruction. When the processor is running in
protected or virtual-8086 mode, the privilege level of a program or procedure must
be 0 to execute the HLT instruction.
Makes sense I suppose. You don't want a DOS program to halt everything, especially in a single CPU case...
Title: Re: wait_key.asm
Post by: dedndave on April 30, 2012, 01:38:20 PM
as i remember, it didn't actually halt anything under DOS, either - lol
the first hardware interrupt that came along caused execution to continue
when you issued a HLT instruction on a 4004 or 8008, the world stopped spinning   :P
Title: Re: wait_key.asm
Post by: sinsi on April 30, 2012, 01:43:25 PM
>the first hardware interrupt that came along caused execution to continue
That's the point. This is how you nowadays stop a core that's not needed.
The BSP will send an interrupt to the AP when needed and off it goes.
Title: Re: wait_key.asm
Post by: FORTRANS on April 30, 2012, 02:08:47 PM
Quote from: hutch-- on April 30, 2012, 01:19:07 PM
Illuminate me here, with a non-re-entrant OS like MS-DOS, what is the point of looking for a wait instruction/sequence/interrupt when only one task is running ? Surely you just shove a test in the polling loop for something like a keystroke or mouse event (if I vagely remember int 33h correctly) and let the processor ping its heart out ?

Hi,

   Well in this case, the HP 200LX is a palmtop that can be running
on 2 AA batteries.  So reducing CPU usage prolongs the time between
chargings.

   Thanks for the Intel quote sinsi.  Makes some sense.  Though the
PM OS should process the exception.  But it could possibly wait before
returning to the RM/V86 program.  Seems that these don't.

Regards,

Steve N.
Title: Re: wait_key.asm
Post by: sinsi on April 30, 2012, 02:31:55 PM
>Though the PM OS should process the exception.
"Processes it" as in "ignores it" I guess. It does throw an exception.
Title: Re: wait_key.asm
Post by: MichaelW on April 30, 2012, 09:02:34 PM
For those running heavily overclocked Pentiums under DOS, it might be useful to keep the CPU from frying, while waiting at maximum speed :toothy

Come to think of it, when I used to routinely run DOS apps I sometimes had problems with the NTVDM CPU usage being so high that everything else slowed to a crawl. Periodic calls to the MS-DOS Idle Call function could have solved this problem, and done right, with no perceptible effect on the speed of the DOS app.