代码之家  ›  专栏  ›  技术社区  ›  LocketGoma

如何将BCD转换为ASCII并打印结果?

  •  -1
  • LocketGoma  · 技术社区  · 7 年前

    我想输出RTC日期。

    BCD to ASCII conversion ,但它使用中断21h,在本页中: https://en.wikipedia.org/wiki/BIOS_interrupt_call 中断21h不存在。

    DAY:
    mov ah,0x04
    int 0x1a
    mov al,dl
    aam ;to convert.
    mov bx,ax
    mov cx,ax
    add dl,ch
    mov ah,02h
    int 21h
    mov dl,cl
    int 21h
    

    我在ubuntu中测试了代码。我想我应该使用中断10h作为输出,而不是21h。( int 21h 不是 忙碌的

    那么,如何将BCD转换为ASCII,以及如何使用中断10h打印它?
    只使用以下样式?

    mov al, 'h'
    int 10h
    
    1 回复  |  直到 7 年前
        1
  •  4
  •   Ped7g    7 年前

    是什么 BCD (binary-coded decimal) ?

    在BIOS时间中断结果的情况下,使用“压缩BCD”。每个字节(8位)分为4位(半字节)的两半,每个字节包含一个十进制值(4位允许0-15个值,但只有0-9个值用于保持“十进制”)。

    例如,如果时间以“37”秒结束,则秒字节将包含值 0x37 = 55 = 0b00110111 . 注意,在十六进制和二进制中,4位的一半是可见的/可读的,即使是在短时间的练习后(在非十进制中,您必须在头部计算除法/余数乘以16,将其拆分为3和7: 55 / 16 = 3 , 55 % 16 = 7

    现在,汇编非常简单,只需稍加修改,因此即使您不想深入研究专门的BCD指令,如 AAM ,可以使用普通位掩码+移位来提取这两个值。

    假设你有价值 0x37 BL ,您希望将其提取到 BH ( 0x03 )和 ( 0x07

    mov bh, bl   ; copy the packed value also into BH
    and bl, 0x0F ; keep only lower 4 bits in BL (0x37 & 0x0F = 0x07)
    shr bh, 4    ; shift right by 4 bits BH (unsigned(0x37) >> 4 = 0x03)
    ; and that's it, it's that simple to manipulate bits in assembly
    

    如何显示?

    这取决于您的目标平台,从问题和评论来看,您的目标是在只有BIOS可用的PC兼容计算机上实现x86 16b实模式,因此最简单的方法之一是将这些十进制0-9值转换为数字的ASCII值(添加48个作品,或者许多汇编器将为您进行字符转换,例如 add bl,'0' '0' ,它将计算正确的字符值)。

    int 10h 显示ASCII字符的服务,如 AH=0x0A 服务显示ASCII字符的示例 :

    mov ah, 0x0A  ; write ASCII character
    mov al, bl    ; character value to write
    xor bx, bx    ; bh = bl = 0 in text mode (adjust in gfx mode as needed)
    mov cx, 1     ; write it only once
    int 0x10      ; call the BIOS service
    

    由于您想显示时间,并且您在几个寄存器中有值,您可能需要在打印之间保留它们,例如,如果我使用 int 0x1A,02 服务来读取RTC,我会使用这个“架构”来显示它(不是编写完整的实现,只是顶层逻辑来向您展示如何使用 push/pop

    read_and_display_rtc_time:
        mov  ah,2
        int  0x1A     ; call service 00 of RTC BIOS interrupt
        push dx       ; preserve DH (seconds)
        push cx       ; preserve CL (minutes)
        mov  al,ch    ; AL = CH (hours)
        call display_bcd   ; display AL as BCD-packed decimal value
        call display_colon ; display ":"
        pop  ax       ; restore minutes (push cx) into AL
        call display_bcd   ; display AL as BCD-packed decimal value
        call display_colon ; display ":"
        pop  ax
        mov  al,ah    ; restore seconds into AL
        call display_bcd   ; display AL as BCD-packed decimal value
        ret
    
    display_bcd:
        ; AL contains BCD-packed decimal value (4:4 bits)
        ; TODO code to split it into two values, convert to ASCII and display
        ret
    
    display_colon:
        ; TODO code to display colon on screen
        ret
    

    mov cl,ax
    

    是的,这是不合法的,因为 ax cl cx ),因此在这种操作中会丢失8位。

    以程序员的身份证明你确实做到了 要丢失高位8位,可以写入 mov cl,al ( al 是的低8位的别名 斧头

    相反的转换类似 mov ax,cl 将再次失败,但作为程序员,您可以再次精确定义8位值应如何转换为16位值。

    例如,要进行“无符号”转换,可以使用386+指令:

    movzx ax,cl
    

    xor ax,ax   ; set all bits of AX to zero first
    mov al,cl   ; copy the CL into lower 8 bits of AX
    

    对于“签名”转换,还有一种特殊的386+方式:

    movsx ax,cl
    ; or before 80386 times there are two common options
    mov   al,cl     ; if "ax" is target, then there's special instr.
    cbw             ; sign extend AL into AX
    ; or when non-ax register is target, like DX
    mov   dh,cl     ; copy CL into upper 8 bits first
    sar   dx,8      ; now do sign-right-shift by 8 bits
      ; dx = sign extended CL
    

    请记住,计算机是一个更复杂的计算器,其他什么都没有,所以你应该试着从文字任务转换为思考你在输入端有哪些数值,哪些数值代表输出端(即使“字符”在计算机中只是数值),然后你只需找出数学公式,将输入数字转换为输出数字。

    AX AL 是8位,以及数字值如何以位(电流)编码。


    不完全是,你只是跑了 nasm