用 DOS 显示数字

2024-02-12

我的任务是编写一个程序来显示我的线性地址 程序的PSP。我写了以下内容:

        ORG     256

        mov     dx,Msg
        mov     ah,09h          ;DOS.WriteStringToStandardOutput
        int     21h
        mov     ax,ds
        mov     dx,16
        mul     dx              ; -> Linear address is now in DX:AX

        ???

        mov     ax,4C00h        ;DOS.TerminateWithExitCode
        int     21h
; ------------------------------
Msg:    db      'PSP is at linear address $'

我搜索了 DOS api(使用拉尔夫·布朗的中断列表 http://www.ctyme.com/rbrown.htm) 并且没有找到一个输出数字的函数! 我错过了吗?我能做什么?

我想显示数字DX:AX以十进制表示。


确实,DOS 没有为我们提供直接输出数字的功能。
你必须先自己转换数字,然后让 DOS 显示它 使用文本输出功能之一。

显示 AX 中保存的无符号 16 位数字

当解决数字转换问题时,看看如何 组成数字的数字彼此相关。
让我们考虑一下数字 65535 及其分解:

(6 * 10000) + (5 * 1000) + (5 * 100) + (3 * 10) + (5 * 1)

方法一:除以10的减幂

处理从左到右的数字很方便,因为它 允许我们在提取单个数字后立即显示它。

  • 将数字 (65535) 除以10000,我们得到一位数的商 (6) 我们可以直接输出为字符。我们还得到了余数 (5535)这将成为下一步的股息。

  • 将上一步的余数 (5535) 除以1000, 我们获得 我们可以立即将其作为字符输出的一位数商 (5)。 我们还得到了余数(535),它将成为下一步的股息。

  • 将上一步的余数 (535) 除以100, 我们获得 我们可以立即将其作为字符输出的一位数商 (5)。 我们还得到了余数 (35),它将成为下一步的股息。

  • 将上一步 (35) 的余数除以10, 我们获得 我们可以立即将其作为字符输出的一位数商 (3)。 我们还得到余数 (5),它将成为下一步的股息。

  • 将上一步 (5) 的余数除以1, 我们获得 我们可以立即将其作为字符输出的一位数商 (5)。 这里余数总是 0。(避免这种情况silly除以 1 需要一些额外的代码)

    mov     bx,.List
.a: xor     dx,dx
    div     word ptr [bx]  ; -> AX=[0,9] is Quotient, Remainder DX
    xchg    ax,dx
    add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
    push    ax             ;(1)
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    pop     ax             ;(1) AX is next dividend
    add     bx,2
    cmp     bx,.List+10
    jb      .a
    ...
.List:
    dw      10000,1000,100,10,1

虽然这种方法当然会产生正确的结果,但它有一些问题 缺点:

  • 考虑较小的数字 255 及其分解:

    (0 * 10000) + (0 * 1000) + (2 * 100) + (5 * 10) + (5 * 1)
    

    如果我们使用相同的 5 步骤过程,我们会得到“00255”。那2位领先 零是不可取的,我们必须包含额外的指令才能获得 摆脱他们。

  • 分隔线随着每一步的变化而变化。我们必须将分隔符列表存储在 记忆。动态计算这些除法器是可能的,但会引入一个 很多额外的部门。

  • 如果我们想应用此方法来显示更大的数字,例如 32 位,我们希望最终涉及的部门将得到 确实有问题。

所以方法1不切实际,因此很少使用。

方法2:除以const 10

处理从右到左的数字似乎违反直觉 因为我们的目标是首先显示最左边的数字。但当你即将 发现,它工作得很漂亮。

  • 将数字 (65535) 除以10,我们得到一个商(6553) 成为下一步的红利。我们还得到余数 (5) 目前还无法输出,所以我们必须保存在某个地方。堆栈是一个 方便的地方这样做。

  • 将上一步的商 (6553) 除以10, 我们获得 商(655)将成为下一步的被除数。我们还得到 我们还不能输出余数 (3),因此我们必须保存它 某处。堆栈是一个方便的地方。

  • 将上一步的商 (655) 除以10, 我们获得 商 (65) 将成为下一步的被除数。我们还得到 我们还不能输出余数 (5),因此我们必须保存它 某处。堆栈是一个方便的地方。

  • 将上一步 (65) 的商除以10, 我们获得 商 (6) 将成为下一步的被除数。我们还得到 我们还不能输出余数 (5),因此我们必须保存它 某处。堆栈是一个方便的地方。

  • 将上一步 (6) 的商除以10, 我们获得 商 (0) 表示这是最后一次除法。我们还得到 余数 (6) 我们could立即输出为字符,but事实证明,不这样做是最有效的,所以像以前一样,我们将 将其保存在堆栈中。

此时堆栈保存着我们的 5 个余数,每个都是一个数字 [0,9] 范围内的数字。由于堆栈是 LIFO(后进先出), 重视我们将POPfirst 是我们想要显示的第一个数字。我们使用一个 单独循环 5POP的来显示完整的数字。但在实践中, 因为我们希望这个例程也能够处理具有 少于 5 位数字,我们将在数字到达时对其进行计数,然后再进行计算 许多POP's.

    mov     bx,10          ;CONST
    xor     cx,cx          ;Reset counter
.a: xor     dx,dx          ;Setup for division DX:AX / BX
    div     bx             ; -> AX is Quotient, Remainder DX=[0,9]
    push    dx             ;(1) Save remainder for now
    inc     cx             ;One more digit
    test    ax,ax          ;Is quotient zero?
    jnz     .a             ;No, use as next dividend
.b: pop     dx             ;(1)
    add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    loop    .b

第二种方法没有第一种方法的缺点:

  • 因为当商变为零时我们就停止,所以永远不会有任何问题 带有丑陋的前导零。
  • 分隔器是固定的。这很容易。
  • 应用这种方法来显示更大的数字非常简单 这正是接下来发生的事情。

显示 DX:AX 中保存的无符号 32 位数字

On 8086 /questions/tagged/8086需要级联 2 个除法来将 32 位值除以DX:AX by 10.
第 1 次除法除以高股息(以 0 扩展),产生高股息 商。第二部分划分低股息(扩展为 第一除法的余数)产生低商。这是剩下的 从我们保存在堆栈上的第二个部分开始。

检查双字是否在DX:AX为零,我已经OR-ed 两半都划伤了 登记。

我不需要计算数字,需要一个寄存器,而是选择放一个sentinel https://en.wikipedia.org/wiki/Sentinel_value在堆栈上。因为这个哨兵得到的值 (10) 是任何数字都无法得到的 有 ([0,9]),它可以很好地确定显示循环何时必须停止。

除此之外,此代码片段与上面的方法 2 类似。

    mov     bx,10          ;CONST
    push    bx             ;Sentinel
.a: mov     cx,ax          ;Temporarily store LowDividend in CX
    mov     ax,dx          ;First divide the HighDividend
    xor     dx,dx          ;Setup for division DX:AX / BX
    div     bx             ; -> AX is HighQuotient, Remainder is re-used
    xchg    ax,cx          ;Temporarily move it to CX restoring LowDividend
    div     bx             ; -> AX is LowQuotient, Remainder DX=[0,9]
    push    dx             ;(1) Save remainder for now
    mov     dx,cx          ;Build true 32-bit quotient in DX:AX
    or      cx,ax          ;Is the true 32-bit quotient zero?
    jnz     .a             ;No, use as next dividend
    pop     dx             ;(1a) First pop (Is digit for sure)
.b: add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    pop     dx             ;(1b) All remaining pops
    cmp     dx,bx          ;Was it the sentinel?
    jb      .b             ;Not yet

显示 DX:AX 中保存的有符号 32 位数字

程序如下:

首先通过测试符号位来判断有符号数是否为负数。
如果是,则对数字求反并输出“-”字符,但要注意不要 销毁其中的数字DX:AX正在进行中。

代码片段的其余部分与无符号数相同。

    test    dx,dx          ;Sign bit is bit 15 of high word
    jns     .a             ;It's a positive number
    neg     dx             ;\
    neg     ax             ; | Negate DX:AX
    sbb     dx,0           ;/
    push    ax dx          ;(1)
    mov     dl,"-"
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    pop     dx ax          ;(1)
.a: mov     bx,10          ;CONST
    push    bx             ;Sentinel
.b: mov     cx,ax          ;Temporarily store LowDividend in CX
    mov     ax,dx          ;First divide the HighDividend
    xor     dx,dx          ;Setup for division DX:AX / BX
    div     bx             ; -> AX is HighQuotient, Remainder is re-used
    xchg    ax,cx          ;Temporarily move it to CX restoring LowDividend
    div     bx             ; -> AX is LowQuotient, Remainder DX=[0,9]
    push    dx             ;(2) Save remainder for now
    mov     dx,cx          ;Build true 32-bit quotient in DX:AX
    or      cx,ax          ;Is the true 32-bit quotient zero?
    jnz     .b             ;No, use as next dividend
    pop     dx             ;(2a) First pop (Is digit for sure)
.c: add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    pop     dx             ;(2b) All remaining pops
    cmp     dx,bx          ;Was it the sentinel?
    jb      .c             ;Not yet

我需要针对不同的数字大小使用单独的例程吗?

在程序中偶尔需要显示的地方AL, AX, or DX:AX, 你可以 只需包含 32 位版本并使用下一点wrappers https://en.wikipedia.org/wiki/Wrapper_function对于较小的 尺寸:

; IN (al) OUT ()
DisplaySignedNumber8:
    push    ax
    cbw                    ;Promote AL to AX
    call    DisplaySignedNumber16
    pop     ax
    ret
; -------------------------
; IN (ax) OUT ()
DisplaySignedNumber16:
    push    dx
    cwd                    ;Promote AX to DX:AX
    call    DisplaySignedNumber32
    pop     dx
    ret
; -------------------------
; IN (dx:ax) OUT ()
DisplaySignedNumber32:
    push    ax bx cx dx
    ...

或者,如果您不介意破坏AX and DX寄存器使用 这个失败的解决方案:

; IN (al) OUT () MOD (ax,dx)
DisplaySignedNumber8:
    cbw
; ---   ---   ---   ---   -
; IN (ax) OUT () MOD (ax,dx)
DisplaySignedNumber16:
    cwd
; ---   ---   ---   ---   -
; IN (dx:ax) OUT () MOD (ax,dx)
DisplaySignedNumber32:
    push    bx cx
    ...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用 DOS 显示数字 的相关文章

随机推荐

  • Jackson - 将 JSON 反序列化为类

    我正在调用一个返回 JSON 的端点 看起来像这样 在 Postman 中 Result attribute1 attribute2 该请求返回的Content Type标头是text x json 与通常的application json
  • Sonata admin - 相关表中的“排序依据”字段

    我有一个产品管理课程 产品实体与类别实体具有多对一关系 即产品与类别相关联 在产品的管理 列表 页面中 我需要按每个产品关联的类别名称 按字母顺序 排序 如果字段位于实体本身上 则设置默认排序依据字段很容易 请参阅索纳塔管理员捆绑订单 ht
  • Retrofit中如何设置最大网络连接数

    我正在查看一些 AQuery 代码here https stackoverflow com questions 20488302 aquery android query how to load images actually发现有一种方法
  • 通过附加到新环境来检查 .rdata 文件的内容 - 可能吗?

    我感兴趣的是在 RDATA 文件中列出对象并仅加载选定的对象 而不是整个集合 以防某些对象可能很大或可能已存在于环境中 我不太清楚当名称存在冲突时如何做到这一点 因为attach 效果不太好 1 用于检查 R 数据文件的内容而不加载它 这个
  • 如何使用 html2canvas 和 jspdf 以正确且简单的方式导出为 pdf

    我目前正在开发一个学校管理软件 通常需要导出包含以下内容的html内容data tables and div tag 我已经尝试了所有可能的方法来编写一个能够以良好的方式导出我的 html 数据的代码 最好使用 css 在检查了一些问题和答
  • Heroku create-react-app 部署未捕获的语法错误:意外的令牌 <

    每当我使用 create react app buildpack 部署 heroku 应用程序时 第一次尝试访问我的域时 加载的页面是白色的 并且开发人员控制台中出现错误 Uncaught SyntaxError Unexpected to
  • 在Python中解析json字段

    有没有关于在 python 中解析 json 属性的好教程 我希望能够解析 ok 字段的真实值 以及名为 client ind 1 的索引 我不明白 python 文档对这个主题的覆盖范围 如果有人可以解释或向我指出更好的资源 那就太棒了
  • Cordova谷歌地图API密钥足够安全

    我想知道我现在使用的 Google 地图 API 密钥是否安全 因为我有一个带有 Google 地图的 Cordova 应用程序 所以我生成了一个 API 密钥 我无法将我的域密钥列入白名单 因为它在手机上运行客户端 此外 任何解压我的应用
  • 在 WinForms 中使用 XAML

    我想使用 XAML 在完整的 WinForms 应用程序中编译时生成类 尽管我愿意接受建议 但我不想使用 WPF 看起来这应该是可能的 但我找不到任何关于具体如何实现的信息 我发现的最接近的是这个页面 http anoriginidea w
  • 如何在故事板或 xib 中选择背景视图

    如果我用鼠标在情节提要或 xib 中选择一个视图 Xcode 将选择最前面的视图 我知道我可以选择文档大纲中的其他视图 但如果我想抓取背景视图并用鼠标移动它 当我在故事板中单击时 最前面的视图会再次被选中 我认为有一种方法可以循环浏览视图并
  • Visual Studio 2008 支持经典的 ASP 开发吗?

    Visual Studio 2008支持经典的ASP开发吗 我创建经典 ASP 网站已经很多年了 我想知道我是否可以使用我当前的工具集 或者我是否必须放弃使用记事本 Thanks Matt 我知道 VS 2008 现在包含经典 ASP 的智
  • 无法通过 AVPlayer 通过 HTTP 播放 mp3 文件

    我正在尝试通过 AVPlayer 播放 MP3 文件 let url URL string http transom org wp content uploads 2004 03 stereo 40kbps mp3 7 let asset
  • 关于学习“如何思考功能性”的建议?

    作为函数式语言的新手 几周前我开始接触 Erlang 我能接触到的第一种函数式语言 我开始写一些小算法 比如left rotate list bubble sort merge sortETC 我发现自己经常迷失在诸如 我应该使用辅助列表来
  • EJB Glassfish v3.1.2 客户端向会话 bean 传递的数据始终为 null

    我在调用会话 bean 方法从客户端传递方法参数时遇到问题 应用程序中 到达方法调用的数据始终为 null 或设置为默认值 而方法的过程与对象配合得很好 例如 我们有方法来持久化一个对象实体addStudent Student Studen
  • Snakemake 中“未给出通配符错误值”

    我正在尝试使用 Snakemake 制作一个简单的管道 从网络上下载两个文件 然后将它们合并到一个输出中 我认为可行的是以下代码 dwn lnks 1 https molb7621 github io workshop downloads
  • 水平滚动条未显示在我的文本框中

    在 Winform C 应用程序上 我在表单上显示一个文本框 该文本框将显示一行 仅一行 我想展示并使用水平滚动条 我将属性 滚动条 设置为水平 滚动条不显示 我将 WordWrap 添加为 false ScrollBar 不显示 我将 M
  • 我应该忽略 React 警告:输入元素不应从不受控制切换到受控制吗?

    错误代码 警告 组件正在更改要控制的时间类型的不受控输入 输入元素不应从不受控制切换到受控制 反之亦然 在组件的生命周期内决定使用受控或非受控输入元件 描述 所以我有一个组件 可以根据数组中的项目动态呈现多个输入字段 我的数组包含 7 天
  • C++ typedef 类型名 类名::模板

    我无法解析以下代码行的含义 typedef typename Allocator template rebind
  • “Groovy:无法解析类...”(LoginController.groovy 中的导入错误)

    我正在尝试使用 弹簧安全核心 2 0 RC2 使用 Grails 版本 2 3 1 但有我自己的LoginController groovy 按照伯特的笔记 here https stackoverflow com questions 19
  • 用 DOS 显示数字

    我的任务是编写一个程序来显示我的线性地址 程序的PSP 我写了以下内容 ORG 256 mov dx Msg mov ah 09h DOS WriteStringToStandardOutput int 21h mov ax ds mov