鱼C论坛

 找回密码
 立即注册
查看: 32|回复: 1

[汇编作业] 实验十——三个子程序

[复制链接]
发表于 前天 22:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
assume cs:code,ds:data,ss:stack

data segment
        db '000000'
data ends
stack segment
        dw 32 dup(0)
stack ends


code segment

start:        mov ax,data       
                mov ds,ax
                mov ax,stack
                mov ss,ax
                mov sp,32
               
                mov ax,0ffffh
                mov dx,0
                mov cx,2
                call divdw
               
                mov si,0
                call dtoc
               
                mov dl,37
                mov dh,12
                mov cl,00000010b
                mov ax,data       
                mov ds,ax
                mov si,0
                call show_str
               
                mov ax,4c00h
                int 21h
               


               
               
                ;数据:ax
                ;字符串地址:ds:si
dtoc:        mov cx,0
                push cx
cle2:        mov dx,0
                mov cx,10               
                call divdw
                add cx,30h
                push cx
                mov cx,ax       
                jcxz cle3
                jmp cle2
               
cle3:        pop cx
                mov ds:[si],cl
                jcxz cle4
                inc si               
                jmp cle3
cle4:        ret

               
                ;被除数:ax低八位 dx高八位
                ;除数:cx
                ;商:ax低八位 dx高八位
                ;余数:cx
        s:        dw 0,0
divdw:        mov di,offset s
                mov bx,0
                mov cs:[di],ax ;将低八位暂存在cs:[di]中
                mov ax,dx
                mov dx,0
                div cx
                mov cs:[di+2],ax;将高八位除以除数的结果暂存在cs:[dx+2]中
                mov ax,cs:[di]
                div cx
                mov cx,dx
                mov dx,cs:[di+2]
                ret
                               
                ;di 行 1~25 第一行显示不出来刷新没了
                ;dh        列 1~80
                ;cl        属性        7闪烁  654背景红绿蓝   3高亮   210前景红绿蓝
                ;si        字符串偏移地址ds:si
show_str:       
                mov ax,0b800h       
                mov es,ax               
                mov bx,0
                mov al,dh
                sub al,1
                mov ch,160
                mul ch
                mov bx,ax
                mov al,dl
                sub al,1
                mov ch,2
                mul ch
                add bx,ax
                mov al,cl
                mov cx,0
                mov di,0
cle:        mov cl,ds:[si]
                jcxz sss               
                mov es:[bx+di],cl
                mov es:[bx+di+1],al
                add si,1
                add di,2
                loop cle
sss:        ret
               
               
               
       
               
code ends
end start
       
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 前天 22:50 | 显示全部楼层
原程序存在一些语法错误和逻辑问题,下面我将逐一分析并给出修正后的代码,同时保持原有的功能结构。


  • divdw 子程序的问题:原程序使用 cs: 直接存储数据是错误的,应使用堆栈或数据段变量。这里采用堆栈保存中间结果。
  • dtoc 子程序的问题:在将数字转换为字符串时,dx 被错误清零,导致只处理了16位数。同时,字符串存储顺序是反的(先低位后高位),需要正序存储。
  • show_str 子程序的问题:使用 ds:es: 时未指定偏移地址,且循环指令 loop 与字符判断冲突。


修正后的完整程序如下:


  1. assume cs:code, ds:data, ss:stack

  2. data segment
  3.     db '0000000000'        ; 预留10字节存储字符串
  4. data ends

  5. stack segment
  6.     dw 32 dup(0)
  7. stack ends

  8. code segment

  9. start:
  10.     mov ax, data
  11.     mov ds, ax
  12.     mov ax, stack
  13.     mov ss, ax
  14.     mov sp, 32

  15.     ; 计算 0FFFFh / 2
  16.     mov ax, 0FFFFh
  17.     mov dx, 0
  18.     mov cx, 2
  19.     call divdw            ; 结果:dx:ax=7FFFh, cx=余数

  20.     ; 将结果转换为字符串
  21.     mov si, 0
  22.     call dtoc

  23.     ; 在屏幕第12行第37列显示字符串
  24.     mov dl, 37            ; 列号
  25.     mov dh, 12            ; 行号
  26.     mov cl, 00000010b     ; 属性(绿色)
  27.     mov ax, data
  28.     mov ds, ax
  29.     mov si, 0
  30.     call show_str

  31.     ; 程序退出
  32.     mov ax, 4C00h
  33.     int 21h

  34. ;===============================================
  35. ; 子程序:divdw
  36. ; 功能:32位除以16位的不溢出除法
  37. ; 输入:dx:ax = 被除数(32位),cx = 除数(16位)
  38. ; 输出:dx:ax = 商(32位),cx = 余数(16位)
  39. ;===============================================
  40. divdw:
  41.     push bx               ; 保存 bx
  42.     mov bx, ax            ; 暂存低16位
  43.     mov ax, dx            ; 高16位移到 ax
  44.     mov dx, 0             ; 清零 dx,形成 0:高16位
  45.     div cx                ; ax = int(H/N), dx = rem(H/N)
  46.     push ax               ; 保存 int(H/N)
  47.     mov ax, bx            ; 恢复低16位
  48.     div cx                ; ax = 商的低16位, dx = 余数
  49.     mov cx, dx            ; 余数存入 cx
  50.     pop dx                ; 恢复 int(H/N) 作为商的高16位
  51.     pop bx                ; 恢复 bx
  52.     ret

  53. ;===============================================
  54. ; 子程序:dtoc
  55. ; 功能:将32位无符号数转换为十进制字符串
  56. ; 输入:dx:ax = 要转换的数字,ds:si 指向存储位置
  57. ; 输出:在 ds:si 处存放以0结尾的字符串
  58. ;===============================================
  59. dtoc:
  60.     push ax
  61.     push dx
  62.     push cx
  63.     push si
  64.     push bx

  65.     mov bx, si            ; 保存字符串起始位置
  66.     jmp dtoc_entry

  67. dtoc_loop:
  68.     mov cx, 10            ; 除数为10
  69.     call divdw            ; 除以10,余数在 cx
  70.     add cx, 30h           ; 余数转ASCII字符
  71.     push cx               ; 字符压栈(低位先入)

  72. dtoc_entry:
  73.     ; 判断商(dx:ax)是否为0
  74.     mov cx, dx
  75.     or cx, ax
  76.     jnz dtoc_loop         ; 不为0则继续循环

  77.     ; 商为0,压入结束标志0
  78.     mov cx, 0
  79.     push cx

  80.     ; 从栈中弹出字符,正序存入数据段
  81.     mov si, bx            ; 恢复字符串起始位置
  82. dtoc_pop:
  83.     pop cx
  84.     mov [si], cl          ; 存储字符
  85.     inc si
  86.     jcxz dtoc_done        ; 遇到0则结束
  87.     jmp dtoc_pop

  88. dtoc_done:
  89.     pop bx
  90.     pop si
  91.     pop cx
  92.     pop dx
  93.     pop ax
  94.     ret

  95. ;===============================================
  96. ; 子程序:show_str
  97. ; 功能:在屏幕指定位置显示字符串
  98. ; 输入:dh = 行号(0-24),dl = 列号(0-79)
  99. ;       cl = 属性,ds:si 指向字符串首地址
  100. ; 输出:无
  101. ;===============================================
  102. show_str:
  103.     push ax
  104.     push bx
  105.     push cx
  106.     push dx
  107.     push si
  108.     push di
  109.     push es

  110.     mov ax, 0B800h        ; 显存段地址
  111.     mov es, ax

  112.     ; 计算行偏移:行号 * 160
  113.     mov al, 160
  114.     mul dh                ; 结果在 ax
  115.     mov bx, ax

  116.     ; 计算列偏移:列号 * 2
  117.     mov al, 2
  118.     mul dl                ; 结果在 ax
  119.     add bx, ax            ; bx = 显存中的起始偏移

  120.     mov al, cl            ; 保存属性到 al
  121.     mov di, 0             ; 显存索引

  122. show_str_loop:
  123.     mov cl, [si]          ; 取字符
  124.     mov ch, 0             ; 设置 ch=0,用于判断字符是否为0
  125.     jcxz show_str_end     ; 字符为0则结束
  126.     mov es:[bx+di], cl    ; 写入字符
  127.     mov es:[bx+di+1], al  ; 写入属性
  128.     inc si
  129.     add di, 2
  130.     jmp show_str_loop

  131. show_str_end:
  132.     pop es
  133.     pop di
  134.     pop si
  135.     pop dx
  136.     pop cx
  137.     pop bx
  138.     pop ax
  139.     ret

  140. code ends
  141. end start
复制代码

主要修改说明:


  • divdw 子程序:采用标准的不溢出除法算法,使用堆栈暂存中间结果,避免直接操作代码段。
  • dtoc 子程序:修正了 dx 被错误清零的问题,确保处理32位数。通过栈实现从低位到高位的转换,再正序存储字符串。
  • show_str 子程序:显存写入时指定完整地址 es:[bx+di],循环改用 jmp 避免与 cx 冲突。
  • 数据段:预留10字节空间,确保足够存储转换后的字符串。


程序运行逻辑:计算 0FFFFh ÷ 2 = 7FFFh(32767),转换为字符串 "32767",在屏幕第12行第37列以绿色显示。


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-1-8 07:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表