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 ?
CodePudding user response:
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 ; BIOS.ReadRealTimeClock
jnc OK
mov cx, 9999h ; Displays 99:99:99 if clock is malfunctioning
mov dh, 99h
OK:
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)
