News:

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

Timer not being displayed

Started by zak100, January 04, 2010, 10:13:26 AM

Previous topic - Next topic

FORTRANS

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

dedndave

that looks pretty simple Steve   :bg
my other code does display hundredths, though (now that i have fixed a couple bugz)

zak100

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.

dedndave

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

zak100

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.

FORTRANS

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

FORTRANS

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.

zak100

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.

sinsi

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.
Light travels faster than sound, that's why some people seem bright until you hear them.

dedndave

#24
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

zak100

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.

dedndave

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

zak100

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.

dedndave

#28
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)

FORTRANS

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