1
votes

So, I'm just found code from this question. I'm trying to print the current time in hours, but output not expected.

This is screenshoot for wroing output

Expected output is current time : 14 16 (secs)

BITS 16
ORG 0x7C00

_start:
    mov ax, 07C0h
    add ax, 288
    mov ss, ax              ; ss = stack space
    mov sp, 4096            ; sp = stack pointer

    mov ax, 07C0h
    mov ds, ax              ; ds = data segment


  call time
  call cvthrs
  call cvtmin
  call cvtsec
  call dsptime

    cli
endloop:
    hlt
    jmp     endloop


time:
;Get time from the system
mov ah,02h
int 1Ah
;ret

;CH - Hours
;CL - Minutes
;DH - Seconds

cvthrs:
;Converts the system time from BCD to ASCII
mov bh,ch ;copy contents of hours (ch) to bh
shr bh, 4
add bh,30h ;add 30h to convert to ascii
mov [tmfld],bh
mov bh,ch
;and bh,0fh
add bh,30h
mov [tmfld + 1],bh
ret

cvtmin:
mov bh,cl ;copy contents of minutes (cl) to bh
shr bh, 4
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 3],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [tmfld + 4],bh
ret

cvtsec:
mov bh,dh ;copy contents of seconds (dh) to bh
shr bh, 4
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 6],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [tmfld + 7],bh
ret

tmfld: db '00:00:00'

dsptime:
;Display the system time
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f;Attribute
mov cx,8 ;Character string is 8 long
mov dh,5 ;position on row 5
mov dl,0;and column 0
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[tmfld] ;load the offset address of string into BP
int 10H
ret

Compile and run using QEMU:

nasm time.asm -fbin -o time.img
qemu-system-i386 -drive format=raw,file=./time.img

How to fix this ?

1
@MargaretBloom: Missing code? This does assemble on its own. I didn't try running it, but I don't see any DOS int 21h calls, just int 1ah and int 10h which are both BIOS, aren't they? I only skimmed / searched the code, but your first 2 points don't seem to match this code. org 7c00h is a big problem, though, if setting segment registers to something other than 0, and yes having time fall through into cvthrs instead of running a ret seems weird.Peter Cordes
@PeterCordes Oops, I missed the scrolling bar :) I deleted my comment since yours already mention the issues.Margaret Bloom

1 Answers

0
votes

The output does not show the current time because the far pointer in ES:BP that you give to the BIOS.WriteString function 13h is wrong.
The problem is with the ORG 0x7C00 directive and how you setup the DS segment register.

When you specify an origin of 7C00h, you instruct the assembler to consider the first byte of your code to reside at the offset address of 7C00h. That means that the offset address of 0000h where the segment starts and where DS should point to is now way down in memory. The only correct value that you should load in DS is 0.

There's also the possibility to specify ORG 0000h, and then the correct value to load in the DS segment register would be 07C0h (like you did).

;ret           in time
;and bh,0fh    in cvthrs

For correct results you need to uncomment these lines in your time and cvthrs subroutines.


This is a quick rewrite with some improvements:

BITS 16
ORG 0000h

_start:
    mov ax, 07C0h
    mov ds, ax
    add ax, 32
    mov ss, ax              ; ss = 07E0h
    mov sp, 4096            ; sp = stack pointer

    call time

    mov  al, ch           ; hours
    call cvt              ; -> AX
    mov  [tmfld + 0], ax
    mov  al, cl           ; minutes
    call cvt              ; -> AX
    mov  [tmfld + 3], ax
    mov  al, dh           ; seconds
    call cvt              ; -> AX
    mov  [tmfld + 6], ax

    call dsptime

    cli
endloop:
    hlt
    jmp     endloop


time:
;Get time from the system
mov ah,02h
int 1Ah
ret

;CH - Hours
;CL - Minutes
;DH - Seconds

cvt:
mov  ah, al
shr  al, 4
and  ah, 0Fh
add  ax, 3030h
ret

tmfld: db '00:00:00'

dsptime:
;Display the system time
mov  ah, 13h     ;function 13h (Display String)
mov  al, 0       ;Write mode is zero
mov  bh, 0       ;Use video page of zero
mov  bl, 0Fh     ;Attribute
mov  cx, 8       ;Character string is 8 long
mov  dh, 5       ;position on row 5
mov  dl, 0       ;and column 0
push ds          ;put ds register on stack
pop  es          ;pop it into es register
mov  bp, tmfld   ;load the offset address of string into BP
int  10h
ret

times 510-($-$$) db 0
dw 0AA55h

It's 1 byte shorter if you load the address of tmfld using a mov instruction.
You can further improve this by combining loads to related byte-sized registers into 1 load of the corresponding word-sized register:

e.g. Change:

mov  dh, 5       ;position on row 5
mov  dl, 0       ;and column 0

into

mov  dx, 0500h   ; DH=5 (row), DL=0 (column)