mov ah, 2 and int 1ah - 错误的打印时间?

mov ah, 2 and int 1ah - wrong print hours?

所以,我刚刚从 中找到了代码。我正在尝试以小时为单位打印当前时间,但输出不是预期的。

这是 wroing output

的屏幕截图

预期输出是当前时间: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

使用 QEMU 编译和运行:

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

如何解决这个问题?

输出不显示当前时间,因为您给 BIOS.WriteString 函数 13h 的 ES:BP 中的远指针是错误的。
问题在于 ORG 0x7C00 指令以及您如何设置 DS 段寄存器。

当您指定 7C00h 的原点时,您指示汇编器将代码的第一个字节视为驻留在 7C00h 的偏移地址处。这意味着段开始 DS 应该指向 的 0000h 的偏移地址现在在内存中很低。您应该在 DS 中加载的唯一正确值是 0。

也可以指定 ORG 0000h,然后在 DS 段寄存器中加载的正确值将是 07C0h(就像您所做的那样)。

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

为了获得正确的结果,您需要在 timecvthrs 子例程中取消注释这些行。


这是一个带有一些改进的快速重写:

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

如果使用mov指令加载tmfld的地址,它会缩短1个字节。
您可以通过将对相关字节大小寄存器的加载组合为相应字大小寄存器的 1 次加载来进一步改进这一点:

例如变化:

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

进入

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