【问题标题】:Displaying characters with DOS or BIOS使用 DOS 或 BIOS 显示字符
【发布时间】:2017-11-28 13:01:58
【问题描述】:

浏览Ralph Brown's interrupt list, 我发现有很多不同的方法可以将文本字符输出到屏幕上。

ROM BIOS API 提供以下功能:

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

DOS API 提供以下功能:

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

这些函数有什么作用?我怎么称呼他们?我该如何选择?

【问题讨论】:

    标签: assembly x86 dos x86-16 bios


    【解决方案1】:

    上述所有功能在它们完成的功能上都是独一无二的,但是 起初,丰富度似乎有些夸张。

    • Int 21h AH=02h Write Character To Standard Output
      此函数解释字符代码 7 (Beep), 8 (Backspace), 9 (Tab), 10(换行)和 13(回车)。所有其他字符代码是 显示。
      退格是非破坏性的,意味着光标移动一个位置到 留下而不擦除下面的东西。退格在左边缘停止 屏幕。
      通过此功能扩展选项卡。标签扩展是替换的过程 ASCII 9 由一系列一个或多个空格 (ASCII 32) 直到光标到达 列位置是 8 的倍数。
      换行将光标向下移动一行,如果需要,滚动屏幕。
      回车将光标移动到屏幕的最左侧。

    • Int 21h AH=06h Direct Console Output
      与函数 02h 非常相似,但不适合一般用途 无法输出字符 255。仅供参考 FAT 文件名中的合法字符。
      似乎它的存在只是为了避免 ctrlC/ ctrl中断检查。

    • Int 21h AH=09h Write String To Standard Output
      函数 02h 的字符串版本,但无法输出字符 36,因为那个被用作字符串终止符。这是一个主要缺点 因为第 36 个字符 ($) 不仅是众所周知的货币符号,而且 FAT 文件名中的合法字符。

    • Int 21h AH=40h Write To File Or Device
      当与预定义句柄 1 一起使用时,此函数输出到 STDOUT 默认为屏幕。所以这里还有另一种显示的可能性 人物。但是请注意,它不依赖于字符串终止 字符,而是长度。当然是最完善的输出功能。 它解释需要解释的东西,它不排除某些 字符,它允许捕获重定向错误,尽管后者涉及使用Int 24h handler

    • Int 10h AH=09h Write Character And Attribute At Cursor Position
      没有任何字符代码被解释,它们都显示在屏幕上。 在文本模式下,提供的属性字节产生前景和 背景颜色,但在图形模式下,您只能获得前景色。 光标位置不变。遗憾! 1

    • Int 10h AH=0Ah Write Character Only At Cursor Position
      与文本模式下的函数 09h 类似,但省略了属性字节。 在图形模式下,此功能与功能 09h 相同。

    • Int 10h AH=0Eh Teletype Output
      此函数解释字符代码 7 (Beep)、8 (Backspace)、 10(换行)和 13(回车)。所有其他字符代码是 显示。可惜这个功能不能展开标签!

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


    然后选择哪个功能完全取决于你是什么类型的程序 写作。基本上可以在控制台应用程序和完整的应用程序之间进行选择 屏幕应用程序。 CHKDSK.EXE 或 TREE.COM 等工具是控制台应用程序。 QBASIC.EXE 或 NE.COM 等程序是全屏应用程序。

    控制台应用程序:

    • 不关心使用颜色
    • 以线性方式将其输出写入屏幕
    • 不妨碍操作系统的输出重定向功能
    • 通常执行一项任务
    • 往往一眨眼就结束了

    面向屏幕的应用程序:

    • 从使用适量的颜色中受益匪浅
    • 在屏幕上徘徊,在它想要的地方写下它想要的东西
    • 不需要担心输出重定向,因为上面很快就会出现 使此类输出不可读
    • 经常执行(过多)任务
    • 一直持续到您决定退出时为止

    控制台应用程序

    只有 DOS 输出函数提供所需/推荐的redirection 能力。输出功能 02h 完美。即使它没有自己的错误 报告何时应该在输出时发生错误(非常不可能) 重定向,"Abort, Retry, Fail?" 的默认严重错误消息 看起来并不太格格不入。 (如果这是一个全屏应用程序, 同样的信息会极大地扰乱屏幕。)

    ; 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
    

    但有时您会希望显示一个临时项目,例如:

    • 某种提示(“-- 更多--”、“准备就绪时按下键...”等)
    • 一个正在运行的计数器/百分比
    • 进度条

    为了避免弄乱任何重定向的输出,最好不要使用 DOS 这些临时项目的输出函数。最好使用 WriteStringBIOS 接下来的代码。

    全屏应用

    现在输出重定向是你的敌人,所以不要使用任何 DOS 输出函数。 如果您不需要颜色,那么下一个代码 sn-p 适合您。它基本上 为 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
    

    大多数时候,一点颜色会产生奇迹。以下代码 sn-ps 使用 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
    

    在 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
    

    总结

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

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

    【讨论】:

    • 我会说在B800:0000 直接写入文本VGA 模式实际上更简单,所以对于全屏应用程序我肯定会使用那个。而且它比 BIOS 调用快十倍以上,所以如果你想做一些类似滚动 ASCII 迷宫的游戏,这是唯一合理的选择。
    猜你喜欢
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多