Solved

1 sec. delay loop

Posted on 2004-04-14
20
2,236 Views
Last Modified: 2012-06-21
Hello Experts ! I need very quick help to my very easy :) question. How can I write a loop to delay appx. 1 second on a moderate Pentium IV PC. I have been searching in the forum and googling a couple of hours but couldn't find an appropriate code, or my Assembler (NASM) is not willing to compile it ! Please help.. Thanx in advance..
0
Comment
Question by:SADIK
  • 6
  • 3
  • 3
  • +5
20 Comments
 
LVL 6

Expert Comment

by:joghurt
ID: 10823399
What kind of operating system is your target? Can you handle the timer tick interrupt?
0
 
LVL 22

Expert Comment

by:grg99
ID: 10824410
;  for approx 1 second


        mov    ax,1000  ; adjust this constant up or down as needed to get closer to 1 second

wta:     mov    cx,65000

wt:    nop
        loop   wt

         dec   ax
         jnz   wta




0
 
LVL 6

Expert Comment

by:joghurt
ID: 10826952
grg99, do you believe this will work on a P4 (as asked in the original question)? P4s have very nice stuff to optimize this.

Furthermore, this kind of looping is VERY processor-dependent: It may give you a 1 second wait on a P4 1.5 GHz, but will give you less than 450 milliseconds on a P4 3.4 GHz. Even more, on variable-speed CPUs (SpeedStep, LongRun, etc.) used in mobile computers, this loop may take 5 seconds or more because this simple loop enables the CPU to stay in the low-speed mode. [These all presume you have a loop that is not optimized off by the CPU which is clearly not the case with the above code.]

If this code runs in a multi-tasking environment, the delay may also be lengthened.

All in all, I believe that knowing the target OS we can supply him/her with a much better solution.
0
 
LVL 22

Expert Comment

by:grg99
ID: 10827176
yes, I know.

On a DOS thru Windows NT system, from a 16-bit program, he can peek at $40:$6C which is a longint that (mostly) increments about 18.2 times a second.

In Windows, there's API's like GetTickCount that return milliseconds since bootup.

There's always RDTSC, which counts CPU clock cycles, but to get a second you have to know the CPU frequency.

something like:

Million EQU 1000000

CPUCYCLESPERSECOND     EQU      450*Million

       RDTSC
       add EAX,CPUCYCLESPERSECOND   ;  target
       adc  EDX,0                                  ; carry
      mov   ESI,EAX
      mov   EDI,EDX

LP:    RDTSC
        cmp    EDX,EDI     ; are high 32 bits right yet?
        JNE    LP              ; no

        cmp     EAX,ESI    ; hi correct, how about low
        JB      LP              ; not yet





0
 
LVL 6

Expert Comment

by:joghurt
ID: 10827228
grg99, this is exactly why I've asked for the OS in my first comment. :-) But he/she seems to forget about his/her question.
0
 
LVL 10

Expert Comment

by:Mercantilum
ID: 10829666
If you have to write a loop in Aseembly language, i.e. not in high level language and not using timer, what I would do for convenience is

- on any other PC with same processor frequency, using linux or windows

- write a command line tool doing a loop, and evaluating time using system calls (not interrupted by windowing system)
   (the only difference will be the task switching time, insignificant if this is the only active application)

#include <sys/time.h>
struct timeval tt;

void start() {   gettimeofday(&tt, NULL);  }
unsigned long end() {  struct timeval t;  gettimeofday (&t, NULL);  return (t.tv_sec*1000 + t.tv_usec/1000) - (tt.tv_sec*1000 + tt.tv_usec/1000); }

     int i,z;
     start ();
     for (i=z=0 ; i<10000000 ; i++) z += i;
     printf ("Took %ld ms\n", end());

Affine the 100000000 to get 1000 ms.

- once you are ok, if you used gcc to compile your program do

    gcc -S myprog.c

to get myprog.s (assembly)

E.g. on my pc it gave exactly 1000 ms. (have to ensure stack adressing is ok :)

        movl    $0, -8(%ebp)
        movl    $0, -4(%ebp)
L4:
        cmpl    $99999999, -4(%ebp)
        jle     L7
        jmp     L5
L7:
        movl    -4(%ebp), %eax
        leal    -8(%ebp), %edx
        addl    %eax, (%edx)
        leal    -4(%ebp), %eax
        incl    (%eax)
        jmp     L4
L5:
0
 

Author Comment

by:SADIK
ID: 10830761
Well, thank you for those quick responses.. they were really quicker than I expected.. My OS is W2K Server which will be a stand alone server running only IIS and the small program that will send some sort of signal to the parallel port by 1 sec delays.. I am quite a beginner so if you can help to write a processor free code, it'll help a lot.. I don't know how to use time ticker.. Pls. be clear and concise.. Thanx again..
0
 
LVL 6

Expert Comment

by:joghurt
ID: 10831325
Must it be in assembly?

Btw, you can call the Sleep system function from assembly. You have to link your call to "_Sleep@4", pass the desired value in ECX (the wait time in microseconds) and call into kernel32.dll. (The same applies to the "sleep" C runtime function within msvcrt.dll)
If you like this idea, we can supply you with the code.

And as another option, if you think you've find a suitable code while Googling, we can help you to get it compiled with NASM.
0
 
LVL 22

Expert Comment

by:grg99
ID: 10832088
Then the best way is to call Sleep() as joghurt has suggested.

0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 

Author Comment

by:SADIK
ID: 10833238
Yes joghurt can you write down the code you mentioned ? Please make it clear for me to understand.. My current code is like this :

       PUSH DX
       MOV DX,0378H
       MOV AL,01H
       OUT DX,AL
      CALL Delay1     ;One second delay
       MOV AL,02H
       OUT DX,AL
      CALL Delay1     ;One second delay
       MOV AL,04H
       OUT DX,AL
      CALL Delay1     ;One second delay
       MOV AL,08H
       OUT DX,AL
       POP DX
       RET
       NOP

; This will loop for 1 Sec
Delay1:    ????
               ????
               ????

P.S. joghurt, do u think NASM is a good compiler? If not can u suggest an other one?
0
 
LVL 6

Expert Comment

by:joghurt
ID: 10836114
I use a commercial compiler so it's not the question of being better. (But anyways, it's better than NASM, I think.) If you are interested in free compilers only, you can find some out there, such as Go-Asm, or versions of GCC. However, I personally don't have much experience with them, except gcc on Linux. But you can find many questions here on EE asking about the best (free) compiler.
0
 

Author Comment

by:SADIK
ID: 10840721
Thanks joghurt.. So what about my code ??
0
 
LVL 6

Accepted Solution

by:
joghurt earned 100 total points
ID: 10845542
There's a tutorial about calling WinAPI functions from assembly:
http://www.acm.uiuc.edu/sigwin/workshops/winasmtut.pdf
You can also get some help from here:
http://win32assembly.online.fr/tut2.html
http://win32assembly.online.fr/tut26.html
(They are for MASM but I think you can get the idea from there for NASM).

The function you need to call is "Sleep" and it's in kernel32.dll.
0
 
LVL 49

Assisted Solution

by:DanRollins
DanRollins earned 100 total points
ID: 10973897
>>   MOV DX,0378H
>>   MOV AL,01H
>>   OUT DX,AL

Have you tried this?  With Windows, the OUT instruction is a protected opcode.  Generally, only device drivers talk directly to the hardware this way.

From that code, it appears that you are sending data to the LPT1 printer port.  It may make more sense to avoid ASM altogether and use C++ code to access Win32 API functions to do that.

-- Dan
0
 
LVL 1

Assisted Solution

by:FST
FST earned 100 total points
ID: 11023833
If you want a delay, dont use the loops by counting up to some number because delay always changes with speed of the processor.
Use the system time:

mov bx,0
mov ah,2ch
int 21h
mov cl,dh
L1:
push cx
mov ah,2ch
int 21h
pop cx
dec dh
cmp dh,cl
jng L1

Ok this routine always delays 1~2 sec.
If you delete the line "dec dh", then it waits 0~1 sec.
Hope you find it usable..
(Bu arada Türkiye'den misin?) :)

0
 
LVL 9

Expert Comment

by:keteracel
ID: 11060171
Can you not just call the following?

pushl      $1
call      sleep

you can change the amount of time by changing the value you push onto stack...
0
 
LVL 9

Assisted Solution

by:keteracel
keteracel earned 100 total points
ID: 11060766
in windows you'll need to push the number of milliseconds you want e.g.

pushl      $1000
call         sleep
0
 
LVL 3

Assisted Solution

by:Dawaffleman
Dawaffleman earned 100 total points
ID: 11064786
i wrote a program for this just the other day....this uses the system clock so it should be pretty accurate
i used tasm 5.1 (i think) to assemble this, it should be realitivly easy to convert:

.model medium
.386                      ;80386 instruction set
.stack 100h            ;256 bytes
.data                     ;Data segment same as:  segment para public 'data'

timer        dw  ?      ;hold initial time
time         dw  1h     ;time= 1 second
time18      dw  ?       ; this holds the computed seconds which have been translated into ticks
ticks         dw  0h      ; ticks-can be used to time less than a second, normally 18.2 ticks in a second

.code                       ; segment para public 'code'

;--------Time delay procedure-----------

    ;Purpose:  waits specified time in seconds + ticks
    ;IN:          TIME variable with time in seconds
    ;              TICKS variable with ticks (18.2 ticks per second)
    ;OUT:       Nothing

timedelay proc

mov  ax,time                 ;load ax with time in seconds
mov  cx,18                    ;get ready to multiply ax by cx
mul   cx                        ;ax now = time * 18
mov   time18,ax            ;put in appropriatly named variable
cmp   ticks,0h                ;this will add ticks to seconds if there is any
jne    settick                  ;small jump and back if we need to add ticks in
getinit:
xor    ax,ax                    ;ax=0
int     1ah                      ;TIMER intterupt- gets time elapsed since midnight stores them to  cx:dx
mov   timer,dx               ;put initial time into timer variable (we only need dx cause its a short time measure)
timeit:
xor     ax,ax                   ;ax=0  just precautions
xor     dx,dx                   ;dx=0
xor     cx,cx                   ;cx=0
int      1ah                     ;TIMER intterupt- gets time elapsed since midnight stores them to  cx:dx
sub     dx,[timer]           ;has the new time in dx and sees it original time-new time = time you want to wait
cmp    dx,[time18]         ;compares total elapsed ticks to your wanted time
jne     timeit                  ;if its not equal then loop back and wait till it is
jmp    endtimedelay       ;if it is equal jump to exit procedure

settick:
add     ax,ticks               ;adds ticks to the seconds
mov    time18,ax            ;moves it to appropriate variable
jmp    getinit                 ;jump back to finish timing

endtimedelay:
ret                               ;pop cs:ip and return to code
endp                            ;end procedure
;-----------------------end of time delay procedure-----------------

start:

mov     time,1h             ;move 1 second to the time you want to wait variable
mov     ticks,0h             ;dont need any ticks (you could use 18 ihere nstead of 1 in the seconds variable (TIME)
call      timedelay          ;call procedure to wait timedelay

mov      ax,4c00h          ; get ready to terminate program (dont need this to run time delay proc, only to exit program)
int        21h                  ; call DOS intterupt- terminate program
end      start                 ; the end
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

In this article, you will read about the trends across the human resources departments for the upcoming year. Some of them include improving employee experience, adopting new technologies, using HR software to its full extent, and integrating artifi…
For cloud, the “train has left the station” and in the Microsoft ERP & CRM world, that means the next generation of enterprise software from Microsoft is here: Dynamics 365 is Microsoft’s new integrated business solution that unifies CRM and ERP fun…
This video discusses moving either the default database or any database to a new volume.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now