News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Animation with int 21h ah=2ch

Started by amrac, December 29, 2009, 04:33:21 PM

Previous topic - Next topic

amrac

I have a little program that paints a little pixel on the screen and each time the user presses a key the pixel moves down. I want to move the pixel down but I want to do it within a certain interval of time, say 500 milliseconds. How can I do that? I know that I have to use int 21h that puts milliseconds in ah, but I don´t know how to start. Here goes my code:
STACK SEGMENT PARA STACK
   DB   64 DUP ('MYSTACK ')
STACK ENDS

MYCODE SEGMENT PARA 'CODE'
MYPROC PROC FAR
   ASSUME CS:MYCODE,SS:STACK
      PUSH DS
      SUB AX,AX
      PUSH AX
      
      MOV AH, 00h
      MOV AL, 04h
      INT 10h
      
      ; MOV AH, 11
      ; MOV BH, 00
      ; MOV BL, 01
      ; INT 10h
      
      MOV AH, 11
      MOV BH, 01
      MOV BL, 00
      INT 10h
      
      MOV DX, 64h
      MOV CX,20
      
Game:
      PUSH CX
      MOV AL, 02      ;pixel cor vermelha
      MOV AH, 12
      MOV CX, 9Eh
      INT 10h
      
      MOV ah, 01
      INT 21h      ;espera por uma tecla
      
      MOV AL, 00      ;pixel cor preto
      MOV AH, 12
      MOV CX, 9Eh
      INT 10h
      
      INC DX
      POP CX
      Loop Game
      
      MOV ah, 01
      INT 21h
      
      MOV AH, 00h
      MOV AL, 02h
      INT 10h
      
      RET
MYPROC ENDP
MYCODE ENDS

   END

dedndave

i would use BIOS INT 1Ah, function 0

;===================================================================

DELAY   PROC    NEAR
;
;time delay
;
;AX = tick count to wait, 0 to 255 (0 to 14 seconds)
;
;----------------------------------------

        OR      AX,AX
        JNZ     EXECUTE_DELAY

        RET                       ;if AX = 0, exit immediately

EXECUTE_DELAY:
        PUSH    CX
        PUSH    DX
        PUSH    BX
        PUSH    AX
        OR      AH,AH
        JZ      UNDER_LIMIT

        MOV     AX,0FFh           ;max limit = 255 ticks (~14 seconds)

UNDER_LIMIT:
        PUSH    AX
        INT     1Ah               ;CX:DX = tick count
        POP     AX
        SUB     BX,BX             ;BX:AX = wait tick count

        ADD     AX,DX
        ADC     BX,CX             ;BX:AX = timeout value

        MOV     DX,0B0h
        MOV     CX,18h            ;CX:DX = midnight rollover value

        SUB     AX,DX
        SBB     BX,CX             ;subtract rollover
        JS      OVERFLOW_ADJUST

        PUSH    BX
        PUSH    AX

ROLLOVER_LOOP:
        MOV     AH,0
        INT     1Ah
        JCXZ    ROLLOVER_ENTRY

        JMP     ROLLOVER_LOOP

OVERFLOW_ADJUST:
        ADD     AX,DX
        ADC     BX,CX

WAIT_LOOP:
        PUSH    BX
        PUSH    AX
        MOV     AH,0
        INT     1Ah

ROLLOVER_ENTRY:
        POP     AX
        POP     BX
        CMP     BX,CX
        JB      DELAY_EXIT

        JA      WAIT_LOOP

        CMP     AX,DX
        JA      WAIT_LOOP

DELAY_EXIT:
        POP     AX
        POP     BX
        POP     DX
        POP     CX
        RET

DELAY   ENDP

;===================================================================

amrac

What I don´t understand is how can I interoperate this routine with my code.

dedndave

each clock tick is ~55 ms
500 ms is about 9 ticks, so...

        mov     ax,9
        call    DELAY

EDIT there are better ways to get a more repeatable delay
that involves revectoring one of the timer interrupts
this is a simple delay - it won't be exactly 500 ms everytime you call it

amrac

Well I discovered that it has to be faster but it works just fine. Thanks!!

amrac

I´ve putten the smallest delay. Is there some code in the procedure that I can change to make the delay smaller? Here goes "my" code:
STACK SEGMENT PARA STACK
   DB   64 DUP ('MYSTACK ')
STACK ENDS

MYCODE SEGMENT PARA 'CODE'
MYPROC PROC FAR
   ASSUME CS:MYCODE,SS:STACK
   
      PUSH DS
      SUB AX,AX
      PUSH AX
      
      MOV AH, 00h
      MOV AL, 04h
      INT 10h
      
      ; MOV AH, 11
      ; MOV BH, 00
      ; MOV BL, 01
      ; INT 10h
      
      MOV AH, 11
      MOV BH, 01
      MOV BL, 00
      INT 10h
      
      mov dx,10h      ;selecciona a linha 100
      mov cx,9eh       ; seleciona a coluna 158
   
      
      ;MOV DX, 64h
      MOV CX,180
      
Game:
      PUSH CX
      MOV AL, 02      ;pixel cor vermelha
      MOV AH, 12
      MOV CX, 9Eh
      INT 10h
      
      ;MOV ah, 01
      ;INT 21h      ;espera por uma tecla

      mov     ax, 1      ;-------------------------------------------------------------------------------------------------<<<<<HERE IS THE SMALLER DELAY THAT I COULD MAKE
                call    DELAY
      
      MOV AL, 00      ;pixel cor preto
      MOV AH, 12
      MOV CX, 9Eh
      INT 10h
      
      INC DX
      POP CX
      Loop Game
      
      MOV ah, 01
      INT 21h
      
      MOV AH, 00h
      MOV AL, 02h
      INT 10h
      
      RET
MYPROC ENDP
DELAY   PROC    NEAR
;
;time delay
;
;AX = tick count to wait, 0 to 255 (0 to 14 seconds)
;
;----------------------------------------

        OR      AX,AX
        JNZ     EXECUTE_DELAY

        RET                       ;if AX = 0, exit immediately

EXECUTE_DELAY:
        PUSH    CX
        PUSH    DX
        PUSH    BX
        PUSH    AX
        OR      AH,AH
        JZ      UNDER_LIMIT

        MOV     AX,0FFh           ;max limit = 255 ticks (~14 seconds)

UNDER_LIMIT:
        PUSH    AX
        INT     1Ah               ;CX:DX = tick count
        POP     AX
        SUB     BX,BX             ;BX:AX = wait tick count

        ADD     AX,DX
        ADC     BX,CX             ;BX:AX = timeout value

        MOV     DX,0B0h
        MOV     CX,18h            ;CX:DX = midnight rollover value

        SUB     AX,DX
        SBB     BX,CX             ;subtract rollover
        JS      OVERFLOW_ADJUST

        PUSH    BX
        PUSH    AX

ROLLOVER_LOOP:
        MOV     AH,0
        INT     1Ah
        JCXZ    ROLLOVER_ENTRY

        JMP     ROLLOVER_LOOP

OVERFLOW_ADJUST:
        ADD     AX,DX
        ADC     BX,CX

WAIT_LOOP:
        PUSH    BX
        PUSH    AX
        MOV     AH,0
        INT     1Ah

ROLLOVER_ENTRY:
        POP     AX
        POP     BX
        CMP     BX,CX
        JB      DELAY_EXIT

        JA      WAIT_LOOP

        CMP     AX,DX
        JA      WAIT_LOOP

DELAY_EXIT:
        POP     AX
        POP     BX
        POP     DX
        POP     CX
        RET

DELAY   ENDP
MYCODE ENDS

   END

dedndave

for very small delays, you can just use a loop
the value you place into CX will deteremine how long the loop takes

        mov     cx,DelayCount       ;this can be a constant

Delay0: loop    Delay0

here is another example where i place a loop inside another loop
it can create somewhat longer delays

        mov     cx,DelayCount       ;this can be a constant

Delay0: push    cx
        xor     cx,cx

Delay1: loop    Delay1

        pop     cx
        loop    Delay0

the problem with these kinds of delay loops is - they run at different speeds on different machines

a more complicated approach is to use one of the counter/timers
it takes a bit more programming, but will yield the same results on most machines

FORTRANS

Hi,

   Depending on your system, INT 15H function 86H in a
wait function.  See Ralf Brown's Interrupt List (RBIL).


AH = 86H
CX:DX = 32 bit count in microseconds (resolution is 976 us)
INT 15H


   It did not work on my Windows 2000 system, but someone
mentioned a service pack may have changed that.  Instead
of the 18.2 times a second the INT 1CH gives you (55
millisecond wait), you get about a millisecond wait.

   You should be able to read the timer counting down as well
as it generates the 18.2 per second interrupts.  That could
give you very short delays.  That is the ports from 40H to
43H.  Again see RIBL.


Port  (data from "Undocumented DOS")

40H = Timer 0, system ticks
41H = Timer 1, DRAM refresh
42H = Timer 2, general use
43H = Tomers 0 - 2 mode control


Regards,

Steve N.

amrac

Thanks once again for your reply. Is there a way in which I can freeze the process of making the little pixel fall? I need to have that functionality in my game. I mean the pixel is falling but when the user presses a key the pixel stops.

MichaelW

Here is another delay procedure.

; -----------------------------------------------------------
; This proc delays for the specified number of milliseconds.
; It does this by counting memory refresh requests, which
; for AT-class systems are generated by system timer 1,
; normally programmed by the BIOS to generate an output once
; every 18/1193182 = 15.09 microseconds. Each request toggles
; bit 4 of I/O port 61h. We are counting full cycles of the
; bit, with two toggles per cycle, so each cycle takes 30.18
; microseconds and we count 34 cycles for each millisecond.
;
; Call with the number of milliseconds in AX.
;
; Preserves all registers other than AX.
;
; Note that the delay will be much shorter when running
; under the NT versions of Windows.
; -----------------------------------------------------------

MsDelay proc
    push cx

    mov cx, ax            ; load msLoop count
  msLoop:
    push cx               ; preserve msLoop counter
    mov cx, 34            ; load repeat count
  wait1:
    in  al, 61h           ; read byte from port
    test al, 10h          ; test bit 4
    jz  wait1             ; jump if bit clear
  wait2:
    in  al, 61h           ; read byte from port
    test al, 10h          ; test bit 4
    jnz wait2             ; jump if bit not clear
    dec cx                ; decrement repeat count
    jnz wait1             ; jump if count not zero
    pop cx                ; recover msLoop counter
    dec cx                ; decrement msLoop count
    jnz msLoop            ; jump if count not zero

    pop cx
    ret
MsDelay endp

eschew obfuscation

dedndave

lol - that is some old-timie stuff, Michael
how old are you, anyways ?

amrac

I don´t understand. Does this mean that the second procedure permits me to stop at any moment the pixel from falling and the first procedure doesn't?

amrac

I tried the second procedure and it runs much faster. But can I stop the pixel from moving. I tried putting the value in ax to zero but it still moves from times to times.

dedndave

well - stopping the pixel should not be dependant on a delay routine
that is more of a program flow issue

FORTRANS

Hi,

   Looks good Michael.  Will check it out on some different
systems.  Do you have a correction for the "NT versions"?

Regards,

Steve N.