使用DOS或BIOS显示字符

Sep*_*and 5 x86 assembly dos bios

通过Ralph Brown的中断列表,我发现有许多不同的方法可以将文本字符输出到屏幕上.

ROM BIOS API提供以下功能:

  • AH = 09h - 在光标位置写字符和属性
  • AH = 0Ah - 仅在光标位置写入字符
  • AH = 0Eh - 电传输出
  • AH = 13h - 写字符串

DOS API提供以下功能:

  • AH = 02h - 将字符写入标准输出
  • AH = 06h - 直接控制台输出
  • AH = 09h - 将字符串写入标准输出

这些功能有什么作用?我怎么称呼他们?我如何在它们之间做出选择?

Sep*_*and 13

所有前面提到的功能在它们完成的任务中都是独一无二的,但首先,丰度似乎有点夸大.

  • Int 21h AH = 02h 将字符写入标准输出
    此功能解释字符代码7(蜂鸣声),8(退格),9(标签),10(换行)和13(回车).显示所有其他字符代码.
    Backspace是非破坏性的,意味着光标向左移动一个位置而不擦除下面的内容.Backspacing停在屏幕的左边缘.
    选项卡由此功能扩展.选项卡扩展是通过一系列一个或多个空格(ASCII 32)替换ASCII 9的过程,直到光标到达8的倍数的列位置.
    换行将光标向下移动一行,如果需要则滚动屏幕.
    回车将光标移动到屏幕的最左侧.

  • Int 21h AH = 06h 直接控制台输出
    非常类似于功能02h,但不太适合一般用途,因为无法输出字符255.FYI是FAT文件名中的合法字符.
    它似乎完全存在以避免ctrlC/ ctrlBreak检查.

  • Int 21h AH = 09h 将字符串写入标准输出
    函数02h的字符串版本,但由于无法输出字符36,因此将其用作字符串终止符.这是一个主要缺点,因为字符36($)不仅是众所周知的货币符号,而且是FAT文件名中的合法字符.

  • Int 21h AH = 40h 写入文件或设备
    当与预定义句柄1一起使用时,此功能输出到STDOUT,默认为屏幕.所以这是显示字符的另一种可能性.但请注意,它不依赖于字符串终止字符,而是依赖于长度.当然是最完整的输出功能.它解释了需要解释的内容,它不排除某些字符,它允许捕获重定向错误,尽管后者涉及使用Int 24h处理程序.

  • Int 10h AH = 09h 在光标位置写入字符和属性
    没有字符代码被解释,它们都显示在屏幕上.在文本模式下,提供的属性字节产生前景色和背景色,但在图形模式下,您只能获得前景色.光标位置不会改变.可怜!1

  • Int 10h AH = 0Ah 仅在光标位置写入字符
    类似于文本模式中的函数09h但省略属性字节.在图形模式下,此功能与功能09h相同.

  • Int 10h AH = 0Eh Teletype输出
    此功能解释字符代码7(Beep),8(退格),10(换行)和13(回车).显示所有其他字符代码.太糟糕了,这个功能不会扩展标签!

  • Int 10h AH = 13h Write String
    在某种程度上,这是函数0Eh的字符串版本.然而,对于一般用途,缺少标签扩展肯定是一个限制.
    为什么这么多参数呢?2


选择哪个功能完全取决于您正在编写的程序类型.基本上可以在控制台应用程序和全屏应用程序之间进行选择.像CHKDSK.EXE或TREE.COM这样的工具是控制台应用程序.QBASIC.EXE或NE.COM等程序是全屏应用程序.

控制台应用程序:

  • 不关心使用颜色
  • 以线性方式将其输出写在屏幕上
  • 不会妨碍操作系统的输出重定向功能
  • 通常执行单个任务
  • 经常在眨眼之间终止

面向屏幕的应用程序:

  • 使用适量的颜色极大地受益
  • 在屏幕上徘徊,并在想要的地方写下它想要的东西
  • 不必担心输出重定向,因为上面很快会使这样的输出不可读
  • 经常执行(太)许多任务
  • 继续,直到你决定退出

控制台应用

只有DOS输出功能提供所需/推荐的重定向 功能.输出功能02h非常完美.即使它在输出重定向时出现错误(非常不可能)时缺少自己的错误报告,但是"中止,重试,失败?"的默认严重错误消息 看起来不太合适.(如果这是一个全屏应用程序,相同的消息将极大地破坏屏幕.)

; IN (ds:si) OUT ()
WriteStringDOS:
      pusha
      jmps    .b
.a:   mov     dl,al
      mov     ah,02h
      int     21h             ;DOS.DisplayCharacter -> AL
.b:   lodsb
      test    al,al
      jnz     .a
      popa
      ret
Run Code Online (Sandbox Code Playgroud)

但有时你会想要显示一个临时项目,如:

  • 某种提示(" - 更多 - ","准备好时按键......"等)
  • 跑步的计数器/百分比
  • 进度条

为了避免弄乱任何重定向输出,最好不要在这些临时项上使用DOS输出函数.最好使用 下一步的WriteStringBIOS代码.

全屏应用程序

现在输出重定向是你的敌人,所以不要使用任何DOS输出函数.如果您不需要颜色,则下一个代码段适合您.它基本上将标签扩展添加到BIOS Teletype功能.

; IN (ds:si) OUT ()
WriteStringBIOS:
      pusha
      mov     bx,0007h        ;Display page 0, Color if graphics mode
      jmps    .b
.a:   cmp     al,9
      je      .Tab
      mov     ah,0Eh
      int     10h             ;BIOS.Teletype
.b:   lodsb
      test    al,al
      jnz     .a
      popa
      ret
.Tab: mov     ax,0E20h        ;Start displaying space(s)
      int     10h             ;BIOS.Teletype
      mov     ah,03h
      int     10h             ;BIOS.GetCursor -> CX DX
      test    dl,7
      jnz     .Tab            ;Column not yet multiple of 8
      jmps    .b
Run Code Online (Sandbox Code Playgroud)

大多数时候,一点颜色会产生奇迹.以下代码片段使用BIOS功能09h输出彩色字符和BIOS功能0Eh以使光标前进.一个很好的组合,可以保持简单.

在文本视频模式下使用第一个:

; IN (bl,ds:si) OUT ()
WriteStringWithAttributeTVM:
      pusha
      mov     bh,0            ;Display page 0
      jmps    .d
.a:   cmp     al,9
      je      .Tab
      cmp     al,13
      ja      .b
      mov     cx,1101_1010_0111_1111b
      bt      cx,ax
      jnc     .c              ;7,8,10,13 don't need the color
.b:   mov     cx,1
      mov     ah,09h
      int     10h             ;BIOS.WriteCharacterAndAttribute
.c:   mov     ah,0Eh
      int     10h             ;BIOS.Teletype
.d:   lodsb
      test    al,al
      jnz     .a
      popa
      ret
.Tab: mov     cx,1            ;Start displaying colored space(s)
      mov     ax,0920h        ;ASCII 20h is space character
      int     10h             ;BIOS.WriteCharacterAndAttribute
      mov     ah,0Eh
      int     10h             ;BIOS.Teletype
      mov     ah,03h
      int     10h             ;BIOS.GetCursor -> CX DX
      test    dl,7
      jnz     .Tab            ;Column not yet multiple of 8
      jmps    .d
Run Code Online (Sandbox Code Playgroud)

使用16色彩色图形视频模式中的第二个.由于BIOS拒绝绘制背景颜色,因此它涉及更多.

; IN (bl,ds:si) OUT ()
WriteStringWithAttributeGVM:
      pusha
      mov     bh,0            ;Display page 0
      mov     bp,bx
      jmps    .d
.a:   cmp     al,9
      je      .Tab
      cmp     al,13
      ja      .b
      mov     cx,1101_1010_0111_1111b
      bt      cx,ax
      jnc     .c              ;7,8,10,13 don't need the color
.b:   push    ax
      mov     cx,1
      mov     bx,bp
      shr     bl,4            ;Get background color (high nibble)
      mov     ax,09DBh        ;ASCII DBh is full block character
      int     10h             ;BIOS.WriteCharacterAndAttribute
      xor     bx,bp           ;Anticipate upcoming 'xor'
      and     bl,15           ;Get foreground color (low nibble)
      or      bl,128          ;Have BIOS 'xor' it
      pop     ax
.c:   mov     ah,0Eh
      int     10h             ;BIOS.Teletype
.d:   lodsb
      test    al,al
      jnz     .a
      popa
      ret
.Tab: mov     cx,1            ;Start displaying colored space(s)
      mov     bx,bp
      shr     bl,4            ;Get background color
      mov     ax,0EDBh        ;ASCII DBh is full block character
      int     10h             ;BIOS.Teletype
      mov     ah,03h
      int     10h             ;BIOS.GetCursor -> CX DX
      test    dl,7
      jnz     .Tab            ;Column not yet multiple of 8
      jmps    .d
Run Code Online (Sandbox Code Playgroud)

综上所述

  • 对于控制台应用程序,WriteStringDOSWriteStringBIOS 程序绰绰有余3.
  • 对于全屏应用程序,WriteStringWithAttributeTVMWriteStringWithAttributeGVM程序同样提供3 4.
  • DOS和BIOS都没有足够的设备来处理图形视频模式.编写自己的图形例程(不是一个简单的任务!)或使用第三方图形库.

1长延迟功能请求:在接收复制计数为零时使光标前进.
2 Retorical,而不是一个实际的问题.
3除非您选择BIOS没有TTY支持的视频模式.例如.在VESA视频模式下,许多BIOS无法滚动.在传统的图形视频模式12h中,我甚至遇到了无法用功能09h写字符的BIOS!
4可以直接在视频存储器中写入,但需要更多努力.