The MASM Forum Archive 2004 to 2012

Miscellaneous Forums => 16 bit DOS Programming => Topic started by: zak100 on January 04, 2010, 10:13:26 AM

Title: Timer not being displayed
Post by: zak100 on January 04, 2010, 10:13:26 AM
Hi,
I am trying to display a timer in the format:
hh:mm:ss
but its not displaying any of its components. It displays a mesg before coming to timer code.

Can somebody plz help me with this prob.?


.MODEL  TINY

install macro intNum,Newisr_add

  push ax
  mov ax, 0
  push ds
  mov ds,ax
  cli                                      ;disable interrupts for the change
  mov word ptr ds:[intNum*4],Newisr_add
  mov word ptr ds:[intNum*4+2],cs          ;word ptr may not be needed here
  sti
  pop ds
  pop ax
endm


        .CODE

;----------------------------------------------------------------------------------

LoadOfs EQU     0               ;must match the value in the bootloader source file
INT1C   EQU     01CH

;----------------------------------------------------------------------------------

;---------------------- initialize ES segment register

        ORG     0

Start:  push    cs
        pop     ds
       
;-----------clear screen
mov ax, 3
int 10h

   
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
       
        xor di, di
        mov ax, 0B800h
        mov es, ax
        mov si, offset msg0+LoadOfs
       mov ah, 41h; attribute byte
       cld;
msgloop:
        lodsb; loads al with a byte of data pted by ds:si
        or al, al
        jz Timer
        stosw; transfers the contents of al to mem location ptd by es:di
        jmp msgloop
       
;---------------------- done - halt
Timer:install 1Ch, INT1Ch

        xor di, di
        mov ax, 0B820h
        mov es, ax
        mov si, offset msgA+LoadOfs
       mov ah, 41h; attribute byte
       cld;
msgAloop:
        lodsb; loads al with a byte of data pted by ds:si
        or al, al
        jz Halt0
        stosw; transfers the contents of al to mem location ptd by es:di
        jmp msgAloop

Halt0: hlt
jmp     Halt0

;---------------------- data area in code segment


Msg0    db      "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs  db 0
cnt  db 0; Its value represents the digits of Timer
s    db 0; selector for secs minutes and hrs used in displayCnt

INT1Ch:
  cli    ;not needed at the beginning of an interrupt handler - the interrupt clears that flag automatically

  inc byte ptr [cs:clkcounter]
  cmp byte ptr [cs:clkcounter],18; if clkcounter is 18, it means 1 sec
  jz handle_secs
  sti
  iret
handle_secs:
  mov byte ptr[cs:clkcounter],0
  inc byte ptr[cs:secs]
  cmp byte ptr[cs:secs],60;if secs is 60, it means 1 min
  jz handle_mins
  push Ax
  push BX
  mov bh, byte ptr[cs:secs]
  mov s,0;--------------- selector for sec
  call PrintSMH;--------- displaying seconds
  pop BX
  pop AX
  sti
  iret
handle_mins:
  mov byte ptr[cs:secs],0
  mov s,0;------------------ selector for secs
  call PrintSMH; ----------- displaying seconds
  inc byte ptr[cs:mins]; we are done, now print the number of minutes elapsed
  cmp byte ptr[cs:mins],60
  jz handle_hrs
  mov s,2;------------------selctor for minutes
  call PrintSMH;------------displaying minutes
  sti
  iret
handle_hrs:
  mov byte ptr[cs:mins],0
  mov s,2;-----------------selctor for minutes
  call PrintSMH;------------displaying minutes 
  inc byte ptr[cs:hrs]
  cmp byte ptr[cs:hrs],24
  jz hrsZero
  mov s,4;----------------selctor for hrs
  call PrintSMH;-----------displaying hours
  sti
  iret
hrsZero:
  mov byte ptr[cs:hrs], 0
  mov s,4;-----------------selctor for hrs
  call PrintSMH;----------displaying hours
  sti
  iret
PrintSMH:
  mov ax, 100; For two digits, we have  'subtract' =10^1 and 10^0
  mov bl, 10
NextDigit: Div BL; AL=AX/BL
  mov ah, 0;value of AL would be the value of AX
  cmp AL,0; until 'subtract'=0
  je done
againSub: Sub bh, AL;e.g to print 58,First print 5,58-10-10-10-10-10-10, count=6, digit=count-1=5
                    ;Note after subtraction bh=-2, add back i.e -2+10=8 which is the next digit
                    ;to print 8,8-1-1-1-1-1-1-1-1-1,count=9, digit=count-1=8
          cmp bh,0;when bh=-ve we stop subtraction
          jb NoSub
          inc cnt
          jmp againSub
NoSub: add bh, al; add back
       call DisplayCnt
       inc s
       jmp NextDigit
    done:iret
DisplayCnt:
  cmp s, 0
  je FirstDigitOfSecs
  cmp s, 1
  je SecondDigitOfSecs
  cmp s, 2
  je FirstDigitOfMins
  cmp s, 3
  je SecondDigitOfMins
  cmp s,4
  je FirstDigitofHrs
  cmp s,5
  je SecondDigitofHrs
  iret
FirstDigitOfSecs: cld
    mov ax,0B880h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    iret
SecondDigitOfSecs:cld;----------------- Displaying colon also
    mov ax,0B882h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    mov ax,0B884h
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
    mov cx,2
    rep stosw
    iret
FirstDigitOfMins:cld
    mov ax,0B886h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    iret
SecondDigitOfMins:cld;----------------- Displaying colon also
    mov ax,0B888h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    mov ax,0B88Ah
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
    mov cx,2
    rep stosw
    iret
FirstDigitofHrs:cld
    mov ax,0B88Ch
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    iret
SecondDigitOfHrs:cld
    mov ax,0B88Eh
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    iret   

       
       


;----------------------------------------------------------------------------------

        END     Start




Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 04, 2010, 01:24:40 PM
Zulfi, Zulfi - lol
i see no place where the time is displayed
the string is - not the time, though
and - to display it, it needs to be converted from binary to ASCII numeric

finally, if you count 18 ticks as one second, you will have a fast-running clock
it is much simpler to use the BIOS ticks-since-midnight count and calculate the time from that value
Title: Re: Timer not being displayed
Post by: zak100 on January 04, 2010, 06:19:15 PM
Hi,

The following code is doing the conversion:

           PrintSMH:
  mov ax, 100; For two digits, we have  'subtract' =10^1 and 10^0
  mov bl, 10
NextDigit: Div BL; AL=AX/BL
  mov ah, 0;value of AL would be the value of AX
  cmp AL,0; until 'subtract'=0
  je done
againSub: Sub bh, AL;e.g to print 58,First print 5,58-10-10-10-10-10-10, count=6, digit=count-1=5
                    ;Note after subtraction bh=-2, add back i.e -2+10=8 which is the next digit
                    ;to print 8,8-1-1-1-1-1-1-1-1-1,count=9, digit=count-1=8
          cmp bh,0;when bh=-ve we stop subtraction
          jb NoSub
          inc cnt
          jmp againSub
NoSub: add bh, al; add back
       call DisplayCnt
       inc s
       jmp NextDigit
    done:iret


Following code and its variants like SecondDigitOfSecs, FirstDigitOfMins and so on is doing the printing.

       FirstDigitOfSecs: cld
    mov ax,0B880h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add bh, 30h
    mov al,bh
    mov cx,2
    rep stosw
    iret




Kindly tell me the prob with this code.

Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 04, 2010, 06:58:25 PM
ahhhhhhhhh - lol
i didn't see that code way down there
holy cow - lol
interrupt handlers should be short and sweet
i am not sure i would display anything anything at all during handler execution
i would count the tick, and let the program display the time
in fact, the ticks are already counted for you by BIOS
all you have to do is go get the value and update the display if the count has changed
give me a little time and i will write a little program for you...
Title: Re: Timer not being displayed
Post by: zak100 on January 04, 2010, 06:59:09 PM
Hi,
I have found one mistake in the printing code. Instead of bh, cnt should contain the value to print. But I have replace bh by cnt but its still not printing. Computer becomes very busy as ctrl-alt-del doesnt work and I have to manually reset the system.

Zulfi.
Title: Re: Timer not being displayed
Post by: zak100 on January 04, 2010, 07:03:19 PM
Hi,
I highly appreciate your intentions. It would tell me another approach of solving the problem. Kindly give me some suggestions also to make this code running.

Zulfi.
Title: Re: Timer not being displayed
Post by: MichaelW on January 04, 2010, 10:41:58 PM
Zulfi,

One major problem with your interrupt handler is that it modifies registers without preserving them. This in general is not workable for hardware interrupt handlers, or for software interrupt handlers called by hardware interrupt handlers, as is the case for Interrupt 1Ch. Changing register values in a handler can cause severe problems in the code that was executing when the hardware interrupt was called.

Another major problem is that in your handler you call code that instead of returning to the caller executes an IRET. The call places a return address on the stack, and this will prevent the IRET from returning to the correct address.

Also, an STI before an IRET makes no sense because the IRET will restore the flags to what they were when the interrupt was called.

Title: Re: Timer not being displayed
Post by: dedndave on January 04, 2010, 10:48:19 PM
Zulfi
here is a simple program to get the INT 1Ah tick count and display it in HH:MM:SS.FF format
DOS is not used to display it

in your boot-code, you may have to execute INT 1Ah, function 0Fh to initialize the BIOS tick counter from the RTC

EDIT - oops - found a line missing - lol - fixed it
EDIT - dang - fixed another bug - i was sleepy when i wrote it   :P
Title: Re: Timer not being displayed
Post by: zak100 on January 05, 2010, 04:40:22 AM
Hi Dave,
Thanks ffor this code. I have downloaded it but I cant figure out its logic.

Hi MichealW,
Quote

Another major problem is that in your handler you call code that instead of returning to the caller executes an IRET. The call places a return address on the stack, and this will prevent the IRET from returning to the correct address.



If I dont use the IRET then how to end the procedures?

Zulfi.
Title: Re: Timer not being displayed
Post by: MichaelW on January 05, 2010, 06:14:49 AM
QuoteIf I dont use the IRET then how to end the procedures?

The problem is not the IRET itself, but the state of the stack when the IRET is executed. When the handler receives control, the contents of the stack, relative to SP, are:

[sp+4] value of the flags register at the point the interrupt was called
[sp+2] return CS for the interrupt call
[sp+0] return IP for the interrupt call

The IRET instruction expects the contents of the stack to be as they were when the handler received control, with the return address and flags value at the "top" of the stack, and the instruction will fail if they are not. Here is an example of the problem in your code:

handle_secs:
  mov byte ptr[cs:clkcounter],0
  inc byte ptr[cs:secs]
  cmp byte ptr[cs:secs],60
  jz handle_mins
  push Ax
  push BX
  mov bh, byte ptr[cs:secs]
  mov s,0
  call PrintSMH
...
PrintSMH:
    mov ax, 100
    mov bl, 10
  NextDigit:
    Div BL
    mov ah, 0
    cmp AL,0
    je done         <===========
  againSub:
    Sub bh, AL
    cmp bh,0
    jb NoSub
    inc cnt
    jmp againSub
  NoSub:
    add bh, al; add back
    call DisplayCnt
    inc s
    jmp NextDigit
  done:
    iret            <===========


After the call PrintSMH executes, the contents of the stack, relative to SP, are:

[sp+10] value of the flags register at the point the interrupt was called
[sp+8] return CS for the interrupt call
[sp+6] return IP for the interrupt call
[sp+4] preserved AX
[sp+2] preserved BX
[sp+0] return IP for the near call

Obviously, this will not work, because the IRET will attempt to use the return IP for the near call as the return IP for the interrupt call, the preserved value of BX as the return CS for the interrupt call, etc.

You need to ensure that anything your code places on the stack is removed from the stack before you execute the IRET. And the same concept applies for any code that is CALLed, where the return instruction is expecting the return address to be at the "top" of the stack.


Title: Re: Timer not being displayed
Post by: dedndave on January 05, 2010, 09:08:31 AM
i fixed a mistake in the Time_1Ah code above

here it is, adapted to "Zulfi boot code" ...

        .MODEL  TINY

;---------------------------------------------------------------------------------

LoadOfs EQU     0               ;must match the value in the bootloader source file

;---------------------------------------------------------------------------------

        .CODE

        ORG     0

_main   PROC    FAR

;set video mode 3 - clear screen

        mov     ax,3
        int     10h

;set segment registers

        push    cs
        pop     ds
        mov     ax,0B800h
        mov     es,ax
        cld

;time display loop

TLoop0: mov     ah,0
        int     1Ah
        cmp     dx,TickLo+LoadOfs
        jz      TLoop0

        mov     TickLo+LoadOfs,dx
        mov     si,offset Hours+LoadOfs
        call    UpdCk
        mov     [si+9],ax
        xor     di,di
        call    Dsply
        jmp     TLoop0

_main   ENDP

;---------------------------------------------------------------------------------

UpdCk   PROC    NEAR

;update clock string

;CX:DX = INT 1Ah clock tick
;SI = string address

        shl     dx,1                   ;multiply by 2
        rcl     cx,1
        mov     ax,cx
        xchg    ax,dx
        mov     bx,ax
        shl     ax,1                   ;multiply by 9
        rcl     dx,1
        shl     ax,1
        rcl     dx,1
        shl     ax,1
        rcl     dx,1
        add     ax,bx
        adc     dx,cx
        mov     bx,19663
        div     bx                     ;divide 28314702 max by 19663
        mov     cx,60
        push    dx
        xor     dx,dx
        div     cx                     ;divide 1439 max by 60
        call    UAscii
        mov     [si],ax
        mov     ax,dx
        call    UAscii
        mov     [si+3],ax
        pop     ax
        mov     dx,6000
        mul     dx
        div     bx                     ;divide 117972000 max by 19663
        mov     cl,100
        xor     dx,dx
        div     cx                     ;divide 5999 max by 100
        call    UAscii
        mov     [si+6],ax
        mov     ax,dx

UAscii: aam
        or      ax,3030h
        xchg    al,ah
        ret

UpdCk   ENDP

;---------------------------------------------------------------------------------

Dsply   PROC    NEAR

        mov     ah,0Ah                 ;AH = attribute
        jmp short Dsply1

Dsply0: stosw

Dsply1: lodsb
        or      al,al
        jnz     Dsply0

        ret

Dsply   ENDP

;---------------------------------------------------------------------------------

TickLo  dw 0

Hours   db '00:00:00.00',0

;---------------------------------------------------------------------------------

        END     _main

EDIT - fixed a bug   :bg
Title: Re: Timer not being displayed
Post by: sinsi on January 05, 2010, 09:24:47 AM
Any reason for using int 1a? If you want h:m:s just use the cmos clock - all nicely bcd already.
Title: Re: Timer not being displayed
Post by: dedndave on January 05, 2010, 09:29:33 AM
well - he wanted to use the tick counter, so i stayed with that   :P
i wanted to show him that it could be done without revectoring the 1Ch interrupt
Title: Re: Timer not being displayed
Post by: zak100 on January 05, 2010, 02:20:42 PM
Thanks for removing the data segment. Great work. However I am not able to under your conversion logic. I would try your code and then modify it according to my understanding. In the meantime I have changed my original code somewhat in the light of MichealW and your's comment but still its not printing anything. Somebody kindly help me with this.


.MODEL  TINY

install macro intNum,Newisr_add

  push ax
  mov ax, 0
  push ds
  mov ds,ax
  cli                                      ;disable interrupts for the change
  mov word ptr ds:[intNum*4],Newisr_add
  mov word ptr ds:[intNum*4+2],cs          ;word ptr may not be needed here
  sti
  pop ds
  pop ax
endm


        .CODE

;----------------------------------------------------------------------------------

LoadOfs EQU     0               ;must match the value in the bootloader source file
INT1C   EQU     01CH

;----------------------------------------------------------------------------------

;---------------------- initialize ES segment register

        ORG     0

Start:  push    cs
        pop     ds
       
;-----------clear screen
mov ax, 3
int 10h

   
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
       
        xor di, di
        mov ax, 0B800h
        mov es, ax
        mov si, offset msg0+LoadOfs
       mov ah, 41h; attribute byte
       cld;
msgloop:
        lodsb; loads al with a byte of data pted by ds:si
        or al, al
        jz TimerMesg
        stosw; transfers the contents of al to mem location ptd by es:di
        jmp msgloop
       
;---------------------- done - halt
TimerMesg:

        xor di, di
        mov ax, 0B820h
        mov es, ax
        mov si, offset msgA+LoadOfs
       mov ah, 41h; attribute byte
       cld;
msgAloop:
        lodsb; loads al with a byte of data pted by ds:si
        or al, al
        jz DISPLAY_TIMER
        stosw; transfers the contents of al to mem location ptd by es:di
        jmp msgAloop
        mov cx, 1000
DISPLAY_TIMER:install 1Ch, INT1Ch
        mov bh, byte ptr[cs:secs]
        mov s,0;--------------- selector for sec
        call PrintSMH;--------- displaying seconds/minutes/hours
        mov bh, byte ptr[cs:mins]
        mov s,2;--------------- selector for min
        call PrintSMH;--------- displaying seconds/minutes/hours
        mov bh, byte ptr[cs:hrs]
        mov s,4;--------------- selector for hrs
        call PrintSMH;--------- displaying seconds/minutes/hours
        Loop Display_TIMER
Halt0: hlt
jmp     Halt0

;---------------------- data area in code segment


Msg0    db      "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs  db 0
cnt  db 0; Its value represents the digits of Timer
s    db 0; selector for secs minutes and hrs used in displayCnt

INT1Ch:
  cli    ;not needed at the beginning of an interrupt handler - the interrupt clears that flag automatically

  inc byte ptr [cs:clkcounter]
  cmp byte ptr [cs:clkcounter],18; if clkcounter is 18, it means 1 sec
  jz handle_secs
  sti
  iret
handle_secs:
  mov byte ptr[cs:clkcounter],0
  inc byte ptr[cs:secs]
  cmp byte ptr[cs:secs],60;if secs is 60, it means 1 min
  jz handle_mins
  sti
  iret
handle_mins:
  mov byte ptr[cs:secs],0
  inc byte ptr[cs:mins]; we are done, now print the number of minutes elapsed
  cmp byte ptr[cs:mins],60
  jz handle_hrs
  sti
  iret
handle_hrs:
  mov byte ptr[cs:mins],0
  inc byte ptr[cs:hrs]
  cmp byte ptr[cs:hrs],24
  jz hrsZero
  sti
  iret
hrsZero:
  mov byte ptr[cs:hrs], 0
  sti
  iret
PrintSMH:
  mov ax, 100; For two digits, we have  'subtract' =10^1 and 10^0
  mov bl, 10
NextDigit: Div BL; AL=AX/BL
  mov ah, 0;value of AL would be the value of AX
  cmp AL,0; until 'subtract'=0
  je done
againSub: Sub bh, AL;e.g to print 58,First print 5,58-10-10-10-10-10-10, count=6, digit=count-1=5
                    ;Note after subtraction bh=-2, add back i.e -2+10=8 which is the next digit
                    ;to print 8,8-1-1-1-1-1-1-1-1-1,count=9, digit=count-1=8
          cmp bh,0;when bh=-ve we stop subtraction
          jb NoSub
          inc cnt
          jmp againSub
NoSub: add bh, al; add back
       call DisplayCnt
       inc s
       jmp NextDigit
    done:ret
DisplayCnt:
  cmp s, 0
  je FirstDigitOfSecs
  cmp s, 1
  je SecondDigitOfSecs
  cmp s, 2
  je FirstDigitOfMins
  cmp s, 3
  je SecondDigitOfMins
  cmp s,4
  je FirstDigitofHrs
  cmp s,5
  je SecondDigitofHrs
  ret
FirstDigitOfSecs: cld
    mov ax,0B880h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    ret
SecondDigitOfSecs:cld;----------------- Displaying colon also
    mov ax,0B882h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    mov ax,0B884h
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
    mov cx,2
    rep stosw
    ret
FirstDigitOfMins:cld
    mov ax,0B886h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    ret
SecondDigitOfMins:cld;----------------- Displaying colon also
    mov ax,0B888h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    mov ax,0B88Ah
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
    mov cx,2
    rep stosw
    ret
FirstDigitofHrs:cld
    mov ax,0B88Ch
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    ret
SecondDigitOfHrs:cld
    mov ax,0B88Eh
    mov es,ax
    xor di,di
    mov ah,1Fh
    add cnt, 30h
    mov al,bh
    mov cx,2
    rep stosw
    ret 

       
       


;----------------------------------------------------------------------------------

        END     Start




Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 05, 2010, 07:06:27 PM
Zulfi - i fixed a bug in both the posted code and the d/l attachment
the UpdCk routine simply calculates the hours, minutes, seconds, hundredths from the clock tick count value
i may do as Sinsi suggested and write one to get the time from the RTC (it should be faster)

i think you misunderstood much of what Michael said

interrupt handlers need to preserve all registers used, as well as the state of the machine
the flags are saved for you by the interrupt mechanism
when an interrupt occurs, the current flags are pushed onto the stack, then the interrupt flag is cleared (as though CLI)
after that, the CS and IP registers are pushed just like a normal far call
once the critical part of the interrupt handler has executed, you may use STI to enable
other interrupts during execution of the remainder of your handler code

after an interrupt has been handled, the machine needs to return to it's original execution
it must appear as though nothing has changed - i.e. the registers and flags must remain unaltered
it is also important to note that the FPU registers should remain unaltered, unless perhaps, it is an FPU exception handler

go back and re-read what Michael posted - a lot of good info, there   :bg
Title: Re: Timer not being displayed
Post by: FORTRANS on January 05, 2010, 09:06:20 PM
Hi,


; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;    BIOS Time Routines, data source "The Undocumented PC".
; Frank van Gilluwe says that if called during a clock update
; that these will fail.  Therefore check the carry flag before
; using the returned values.  You could do as follows if you
; trust the RTC.

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Time of Day

RTime:
        MOV     AH,2    ; Get CMOS Time
        INT     1AH     ; Real Time Clock Interrupt
        JC      RTime
        MOV     [Hours],CH      ; BCD Hours
        MOV     [Minites],CL    ; BCD Minutes
        MOV     [Seconds],DH    ; BCD Seconds
        MOV     [DST],DL        ; 0 = Disabled, 1 = enabled

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Date

RDate:
        MOV     AH,4    ; Read CMOS Date
        INT     1AH     ; Real Time Clock Interrupt
        JC      RDate
        MOV     [Century],CH    ; BCD 19 or 20
        MOV     [Year],CL       ; BCD 1 to 99
        MOV     [Month],DH      ; BCD 1 to 12
        MOV     [Day],DL        ; BCD 1 to 31

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


HTH,

Steve
Title: Re: Timer not being displayed
Post by: dedndave on January 05, 2010, 10:39:59 PM
that looks pretty simple Steve   :bg
my other code does display hundredths, though (now that i have fixed a couple bugz)
Title: Re: Timer not being displayed
Post by: zak100 on January 06, 2010, 02:53:54 PM
Yes code provided by Steve seems simple. i would check it.

QuoteYou need to ensure that anything your code places on the stack is removed from the stack before you execute the IRET. And the same concept applies for any code that is CALLed, where the return instruction is expecting the return address to be at the "top" of the stack.

I have ensured this by  removing the two push statements. However I am not sure about the second part.

Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 06, 2010, 03:31:08 PM
Zulfi, an interrupt handler typically looks something like this....

INTXX   PROC    FAR

        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    bp

;time-critical code goes here

        sti

;non-time-critical code goes here

        pop     bp
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        iret

INTXX   ENDP

of course, if you do not use all the registers, you do not have to push and pop all of them
you only need to push and pop the ones you use
the stack DOES have to be balanced
for every push, there should be an associated pop to go with it
Title: Re: Timer not being displayed
Post by: zak100 on January 07, 2010, 02:34:29 PM
Thanks for your work. I highly appreciate cooperation of you people in my endeavours. However I am a bit slow. I would try what you people have suggested but it may take sometime.

Zulfi.
Title: Re: Timer not being displayed
Post by: FORTRANS on January 07, 2010, 09:24:56 PM
Quote from: zak100 on January 07, 2010, 02:34:29 PM
Thanks for your work. I highly appreciate cooperation of you people in my endeavours. However I am a bit slow. I would try what you people have suggested but it may take sometime.

Hi Zulfi.

   Um.  Not sure what you mean, but if this might help?
Rather straight forward code.  I hope.  Ask if not for you.

Regards,

Steve


        PAGE ,132
        TITLE Display time and date using BIOS.
        NAME  RTC

        COMMENT *
    Display time and date using BIOS functions.  Note: data saved by
RTime and RDate is not used here.  This is just a display routine to
show functionality.
5-7 January 2010 for MASM32 Forum, SRN.
*
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Stack segment:
STCKSEG SEGMENT STACK
        DB      48 DUP('STACK   ')      ; Stack area, and filler (384 Bytes)
STCKSEG ENDS

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Data segment:
DATASEG SEGMENT PUBLIC

; - - - RTime, 3 BCD Bytes and flag - - -
Hours   DB      0
Minutes DB      0
Seconds DB      0
DST     DB      0

; - - - RDate, 4 BCD Bytes - - -
Century DB      0
Year    DB      0
Month   DB      0
Day     DB      0

; - - - OutBDate - - -
MONTHS  DB      '     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'

DATASEG ENDS

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Code segment:
CODE    SEGMENT PUBLIC
        ASSUME  CS:CODE, DS:DATASEG, SS:STCKSEG

START   PROC
        MOV     AX,SEG DATASEG
        MOV     DS,AX

        CALL CRLF

        CALL OutBTime   ; Use video BIOS to output RTC Time.
        CALL OutBDate   ; Use video BIOS to output RTC Date.

        CALL CRLF

        MOV     AL,0    ; Successful return code.
        MOV     AH,4CH  ; DOS 2+ .EXE exit.
        INT     21H

START   ENDP

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OutBTime:       ; Output BIOS time, don't use DOS.
                ; 6 January 2010, SRN
; INPUT: None
; Uses:  AX, CX, DX.

        MOV     AL,' '
        CALL OutChar

        CALL RTime      ; CH = BCD Hours,   CL = BCD Minutes
                        ; DH = BCD Seconds, DL = DST Flag

        MOV     AL,CH   ; - - - Play with hours - - -
        CALL OutBCDs

        MOV     AL,':'
        CALL OutChar

        MOV     AL,CL   ; - - - Play with minutes - - -
        CALL OutBCD

        MOV     AL,':'
        CALL OutChar

        MOV     AL,DH   ; - - - Play with seconds - - -
        CALL OutBCD

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OutBDate:       ; Output BIOS Date, don't use DOS.
                ; 6 January 2010, SRN
; INPUT: None
; Uses:  AX, BX, CX, DX.

        MOV     AL,' '
        CALL OutChar

        CALL RDate      ; CH = BCD Century, CL = BCD Year
                        ; DH = BCD Month,   DL = BCD Day

        MOV     AL,DL   ; - - - Play with Day - - -
        CALL OutBCDs

        MOV     AL,DH   ; - - - Play with month - - - (first convert to binary)
        MOV     AH,AL
        SHR     AH,1    ; "Mask" off high digit
        SHR     AH,1
        SHR     AH,1
        SHR     AH,1
        AND     AL,0FH  ; Mask off low digit
        AAD             ; Combine two unpacked BCD digits into a binary num.
        XOR     BH,BH
        MOV     BL,AL   ; Binary Month
        SHL     BX,1
        SHL     BX,1    ; Four characters per label.
        ADD     BX,OFFSET Months ; Point to labels.

        MOV     AL,[BX]
        CALL OutChar
        MOV     AL,[BX+1]
        CALL OutChar
        MOV     AL,[BX+2]
        CALL OutChar
        MOV     AL,[BX+3]
        CALL OutChar

        MOV     AL,' '
        CALL OutChar

        MOV     AL,CH   ; - - - Play with Century - - -
        CALL OutBCD

        MOV     AL,CL   ; - - - Play with Year - - -
        CALL OutBCD

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Output carriage return and linefeed.
CRLF:
        MOV     AL,13
        CALL OutChar

        MOV     AL,10
        CALL OutChar

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; 6 January 2010, use video BIOS to display a character.
; Use function 0EH as it will process CR and LF as commands.
;  INPUT:  AL = Character to output.

OutChar:
        PUSH    AX
        PUSH    BX

        MOV     AH,0EH  ; Teletype Output Function
        MOV     BX,7    ; BH = Page, BL = (maybe) Attribute.
        INT     10H

        POP     BX
        POP     AX

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Take a byte in AL with 2 packed BCD digits, and print to screen.
; 7 Jan 2010, SRN.
OutBCD:
        MOV     AH,AL   ; Duplicate to put digits in both AH and AL.
        SHR     AH,1    ; "Mask" off high digit.
        SHR     AH,1
        SHR     AH,1
        SHR     AH,1
        AND     AL,0FH  ; Mask off low digit.
        OR      AX,3030H; Convert binary digits to ASCII characters.

        PUSH    AX
        MOV     AL,AH
        CALL OutChar    ; Output high digit.

        POP     AX

        CALL OutChar    ; Output low digit.

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Take a byte in AL with 2 packed BCD digits, and print to screen.
; Suppress leading zero for pretty print.  7 Jan 2010, SRN.
OutBCDs:
        MOV     AH,AL   ; Duplicate to put digits in both AH and AL.
        SHR     AH,1    ; "Mask" off high digit.
        SHR     AH,1
        SHR     AH,1
        SHR     AH,1
        AND     AL,0FH  ; Mask off low digit.
        OR      AX,3030H
        CMP     AH,30H  ; Suppress leading zero?
        JNZ     OBs_1
        MOV     AH,' '

OBs_1:  PUSH    AX
        MOV     AL,AH
        CALL OutChar

        POP     AX
        CALL OutChar

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;    BIOS Time Routines, data source "The Undocumented PC".
; Frank van Gilluwe says that if called during a clock update
; that these will fail.  Therefore check the carry flag before
; using the returned values.  I assume minimal errors will occur.

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Time of Day
RTime:
        MOV     AH,2    ; Get CMOS Time
        INT     1AH     ; Real Time Clock Interrupt
        JC      RTime
        MOV     [Hours],CH      ; BCD Hours
        MOV     [Minutes],CL    ; BCD Minutes
        MOV     [Seconds],DH    ; BCD Seconds
        MOV     [DST],DL        ; 0 = Disabled, 1 = enabled

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Date
RDate:
        MOV     AH,4    ; Read CMOS Date
        INT     1AH     ; Real Time Clock Interrupt
        JC      RDate
        MOV     [Century],CH    ; BCD 19 or 20
        MOV     [Year],CL       ; BCD 1 to 99
        MOV     [Month],DH      ; BCD 1 to 12
        MOV     [Day],DL        ; BCD 1 to 31

        RET

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CODE    ENDS
        END     START
Title: Re: Timer not being displayed
Post by: FORTRANS on January 08, 2010, 02:16:09 PM
There ought to be a rule that if you wake up at 1:30
with a dumb idea, you should be able to forget it and
go back to sleep.  That said, the following code takes a
packed BCD byte and converts it to two unpacked bytes.


        MOV     AH,AL   ; Duplicate to put digits in both AH and AL.
        SHR     AH,1    ; "Mask" off high digit.
        SHR     AH,1
        SHR     AH,1
        SHR     AH,1
        AND     AL,0FH  ; Mask off low digit.


   It can be replaced with this.


        DB      0D4H, 10H       ; AAM with divisor of 16 instead of 10.


Cheers,

Steve N.
Title: Re: Timer not being displayed
Post by: zak100 on January 09, 2010, 06:19:53 AM
Hi,
I am still working on int 1Ah. Its useful. I am not yet able to print clock values at correct positions using the format:
hh:mm:ss. Its printing decimal values but not at correct positions on screen. The values are scattered on the screen. My screen printing code is given below:

FirstDigitOfSecs:
    push ax
    cld
    mov ax,0B880h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    pop ax
    ret
SecondDigitOfSecs:
    push ax
    cld;----------------- Displaying colon also
    mov ax,0B882h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    mov ax,0B884h
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
    stosw
    pop ax
    ret
FirstDigitOfMins:
    push ax
    cld
    mov ax,0B886h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    pop ax
    ret
SecondDigitOfMins:
    push ax
    cld;----------------- Displaying colon also
    mov ax,0B888h
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    mov ax,0B88Ah
    mov es,ax
    xor di,di
    mov ah,1Fh
    mov al,':'
   
     stosw
    pop ax
    ret
FirstDigitofHrs:
    push ax
    cld
    mov ax,0B88Ch
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    pop ax
    ret
SecondDigitOfHrs:
    push ax
    cld
    mov ax,0B88Eh
    mov es,ax
    xor di,di
    mov ah,1Fh
    add dh, 30h
    mov al,dh
    stosw
    pop ax
    ret 



Somebody kindly guide me in this regard.

Zulfi.
Title: Re: Timer not being displayed
Post by: sinsi on January 09, 2010, 07:03:04 AM
The difference between segment B880 and B882 isn't 2 bytes but 2 paragraphs (32 bytes).
The convention is to leave ES as B800 and use that as a base.
Title: Re: Timer not being displayed
Post by: dedndave on January 09, 2010, 10:01:36 AM
Zulfi,
it is simpler to build the entire string, then display it all at once
try this code....

        .MODEL  TINY

;---------------------------------------------------------------------------------

LoadOfs EQU     0               ;must match the value in the bootloader source file

;---------------------------------------------------------------------------------

        .CODE

        ORG     0

_main   PROC    FAR

;set video mode 3 - clear screen

        mov     ax,3
        int     10h

;set segment registers

        push    cs
        pop     ds
        mov     ax,0B800h
        mov     es,ax
        cld

;date-time display update loop

TLoop0: mov     ah,2                   ;get BIOS RTC time
        int     1Ah
        jc      TLoop0

        cmp     dh,Seconds+LoadOfs
        jz      TLoop0

        mov     Seconds+LoadOfs,dh
        mov     si,offset DatTime+LoadOfs
        call    UpdDt
        mov     [si],ax                ;store month value
        xor     di,di                  ;screen buffer address = 0
        call    Dsply
        jmp     TLoop0

_main   ENDP

;---------------------------------------------------------------------------------

UpdDt   PROC    NEAR

;update date/time string

;CH = BCD hours
;CL = BCD minutes
;DH = BCD seconds
;SI = address of DatTime string

;update time values

        mov     al,dh                  ;AL = BCD seconds
        call    UAscii
        mov     [si+12h],ax
        mov     al,cl                  ;AL = BCD minutes
        call    UAscii
        mov     [si+0Fh],ax
        mov     al,ch                  ;AL = BCD hours
        call    UAscii
        mov     [si+0Ch],ax

;update date values

        push    si

UpdDt0: mov     ah,4                   ;get BIOS RTC date
        int     1Ah
        jc      UpdDt0

        pop     si

;CH = BCD century
;CL = BCD year
;DH = BCD month
;DL = BCD day

        mov     al,cl                  ;AL = BCD year
        call    UAscii
        mov     [si+8],ax
        mov     al,ch                  ;AL = BCD century
        call    UAscii
        mov     [si+6],ax
        mov     al,dl                  ;AL = BCD day
        call    UAscii
        mov     [si+3],ax
        mov     al,dh                  ;AL = BCD month

UAscii:
        DB      0D4h,10h               ;AAM 10h
        or      ax,3030h
        xchg    al,ah
        ret

UpdDt   ENDP

;---------------------------------------------------------------------------------

Dsply   PROC    NEAR

        mov     ah,0Ah                 ;AH = attribute
        jmp short Dsply1

Dsply0: stosw

Dsply1: lodsb
        or      al,al
        jnz     Dsply0

        ret

Dsply   ENDP

;---------------------------------------------------------------------------------

Seconds DB 0FFh                        ;force initial update

DatTime DB '00-00-0000',32,32,'00:00:00',0

;---------------------------------------------------------------------------------

        END     _main
Title: Re: Timer not being displayed
Post by: zak100 on January 09, 2010, 06:48:26 PM
I am trying to use an array now. If it doesnt work I would let you know. Thanks for your code. I am trying to improve on my conversion method.

Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 09, 2010, 08:24:11 PM
one thing i would suggest, Zulfi
set the ES register to 0B800h and leave it there
use the DI register to set the screen position
there are a couple reasons for this
1) the ES register can only make steps of 16 bytes - DI can make steps of 1 byte
2) you cannot load an immediate value into a segment register
it has to be put into a general register or in a memory location, first
with DI (or SI or BX), you can load the register directly
this is both smaller and faster
Title: Re: Timer not being displayed
Post by: zak100 on January 10, 2010, 06:39:39 PM
Hi,
Thanks for your guidance. I am encountering following probs.
1) I have to use a different algorithm (alg). The alg which I am using , is used to display decimal values.23:15:56. This is a decimal time. But
when I store it in a register e.g bh in my code, it becomes a hex value. Thus 23 is not 23d but it is 23h which is 35d and this is causing prob.
2) Another prob. is occurring when I am trying to display the values. I am using both si and di and the following code for displaying is not working:

    mov ax,0B800h
    mov es,ax
    xor di,di
    mov di,100h
    mov cx,8
    mov si,offset arr+LoadOfs
    mov ah,1Fh
   nextval: mov al, [si]
    inc si
    inc di
    stosw
     loop nextval


Kindly guide me how to use cld in this case.

Zulfi.
Title: Re: Timer not being displayed
Post by: dedndave on January 10, 2010, 07:12:10 PM
hiya Zulfi,
the values returned by INT 1Ah, functions 2 and 4 are packed BCD
that means that each byte register holds 2 digits of information
the upper 4 bits of the register contain the high order digit
and the lower 4 bits contain the low order digit
for example, the number 20 (decimal) will be 20h
to display the digits, you must do 2 things:
1) split the 2 digits into seperate bytes (i.e. unpack them)
2) convert them from BCD values to ASCII (by adding 30h)

in my code, i used AAM 10h (an undocumented instruction) as Steve mentioned earlier
if you look at his code, he used a more "legal" method
if the packed BCD digits are in AL, it can look like this...

        mov     ah,al
        and     ah,0Fh
        shr     al,1
        shr     al,1
        shr     al,1
        shr     al,1
        or      ax,3030h          ;make them ASCII

the high order digit is in AL and the low order digit is in AH
so that when you put them into memory as a word, the high order digit will be at the lower address

as for using the CLD instruction, you should be able to place it once at the beginning of the code and leave it
unless you use an STD instruction someplace to set the direction flag, it should remain cleared
as i mentioned before, the same is true of loading the ES register with 0B800h

early in the program...

        push    cs
        pop     ds              ;DS = CS
        mov     ax,0B800h
        mov     es,ax           ;ES = B800
        cld                     ;DF = 0


after that, the SI register should point to your data string
and DI should point to the location on the screen

remember, there are 2 bytes in the screen buffer for each character (the ASCII character and the color attribute)
there are 80 characters per line in video mode 3
so, to calculate the DI value:

address = 2 * (80 * row + column)
Title: Re: Timer not being displayed
Post by: FORTRANS on January 10, 2010, 10:45:29 PM
Hi,

Your code here:


    mov ah,1Fh
   nextval: mov al, [si]
    inc si
:    inc di
    stosw     ; <= You are automatically incrementing DI
     loop nextval


   You need to increment SI "by hand" as you are using a MOV
rather than LODSB.  But DI is being incremented by the STOSW.

Regards,

Steve
Title: Re: Timer not being displayed
Post by: zak100 on January 11, 2010, 05:15:32 AM
Hi,
Thanks. Steve I would check your code. Dave I want to use your alg. for conversion but I want to give one more try to the conversion alg. which I am using. Instead of subtracting 10D I should subtract 10h. I think this may solve the prob.

Zulfi.
Title: Re: Timer not being displayed
Post by: zak100 on January 12, 2010, 02:57:05 PM
Hi,
Timer is working now. I appreciate cooperation of all those who provided guidance to me in this prob. I have to now find the time elapsed since the OS started.

Zulfi.
Title: Re: Timer not being displayed
Post by: FORTRANS on August 22, 2010, 06:52:45 PM
Hi,

   Just for future reference: the code I posted to use Int 1AH
failed on one machine.  So a correction.

   Change the following logic for all similar int 1AH routine.


; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Time of Day

RTime:
        MOV     AH,2    ; Get CMOS Time
        INT     1AH     ; Real Time Clock Interrupt
        JC      RTime


   To incorporate a clear carry instruction.


; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Time of Day

RTime:
        CLC             ; At least one BIOS does not clear this, = infinite loop.
        MOV     AH,2    ; Get CMOS Time
        INT     1AH     ; Real Time Clock Interrupt
        JC      RTime


Regards,

Steve N.