《汇编语言(王爽)第三版》实验【未完待续】


实验一:查看CPU和内存,用机器指令和汇编指令编程

(3) 在内存fff00H-fffffH的某几个单元中可以看到rom的生产日期

 

 这里是2017年5月19日

(4)向b810写数据

  

 在这里写入的数据都会显示在屏幕上

检测点3.1

(1)在Debug中,用“d 0:0 1f”查看内存,结果如下

 

 实验二:用机器指令和汇编指令编程

(1)用debug,将下面的程序写入内存,逐条执行,根据指令执行后的实际运行情况填空

 

 

 

 

 实验四:[bx]和loop的使用

1.编程,向内存0:200-0:23F依次传送数据0~63(3FH)。

;P121 第五章实验四 (1)
assume cs:code code segment main:
         mov ax,0020h mov ds,ax     ;指定段地址0200h

         mov bx,0h mov cx,003fh mov ax,0h s:   
         mov [bx],al inc bx inc al loop s mov ax,4c00h int 21h code ends end main
View Code

  2.编程,向内存0:200-0:23F依次传送数据0~63(3FH),只能使用9条指令。

;P121 第五章实验四 (2)
assume cs:code code segment main:
         mov ax,0020h mov ds,ax     ;指定段地址0200h
         mov bx,0h mov cx,003fh s:mov [bx],bl inc bl loop s mov ax,4c00h int 21h code ends end main
View Code

 3.补全下面的程序,其功能是将“mov ax,4c00”之前的指令复制到内存0:200处。

assume cs:code code segment main:
        mov ax,cs mov ds,ax mov ax,0020h mov es,ax        ;es=0020
        
        mov bx,0
        mov cx,17h s:    mov al,[bx] mov es:[bx],al inc bx loop s mov ax,4c00h int 21h code ends end main
View Code

  

  PS:指令的段地址是放在CS里面,所以第一个空是“cs”,由图可以看出这些代码一共长15h,但是cx要赋值17h

实验五 编写、调试具体多个段的程序

5) 

;默认是一次记录到代码段中的
assume cs:code a segment db 1,2,3,4,5,6,7,8 a ends b segment db 1,2,3,4,5,6,7,8 b ends cc segment db 0,0,0,0,0,0,0,0 cc ends code segment start:  mov ax,a mov ds,ax mov ax,b mov es,ax mov bx,0
        mov cx,8
        
   s:   mov al,ds:[bx] add es:[bx],al inc bx loop s mov ax,4c00h int 21h code ends end start
View Code

6)

assume cs:code a segment dw 1,2,3,4,5,6,7,8,0ah,0bh,0ch,0dh,0eh,0fh,0ffh a ends b segment db 0,0,0,0,0,0,0,0 b ends code segment start:  mov ax,a mov ds,ax mov ax,b mov ss,ax mov sp,16
        
        mov cx,8
        mov bx,0
        
   s:   push ds:[bx] add bx,2 loop s mov ax,4c00h int 21h code ends end start
View Code

 

实验六:实践课程中的程序

(1)7.1

;程序7.1 P 139
assume cs:code,ds:data data segment db 'unIX' db 'foRK' data ends code segment start:  mov al,'a'
            mov bl,'b'
            
            mov ax,4c00h int 21h code ends end start
View Code

 

(2)7.4

;大小写转换 P143 ; and or 的使用
assume cs:codesg,ds:datasg datasg segment db 'BaSiC' db 'iNforMaTiOn' datasg ends codesg segment start:  mov ax,datasg mov ds,ax mov bx,0
            mov cx,5
            
        ;第一个循环将第一段变成大写
          s:mov al,[bx] and al,11011111B
            mov [bx],al inc bx loop s ;第二个循环将第二段变成小写
            mov bx,5
            mov cx,11
         s0:mov al,[bx] or al,00100000B
            mov [bx],al inc bx loop s0 mov ax, 4c00h int 21h codesg ends end start
View Code

 


问题8.1:【图片里的代码没有打完整,等我截完图才发现,懒得改了Orz】

;问题8.1 p 171 ; 100001 / 100 = 1000 …… 1 ; 186A1H / 64H = 3E8H …… 1
assume cs:code data segment dd 100001  ;186A1 64
    dw 100     ;ax=86A1 dx=0001 6400 0000
    dw 0 data ends code segment start: mov ax,data mov ds,axq mov ax,ds:[0] mov dx,ds:[2] ;ax=86A1 dx=0001
           
           div word ptr ds:[4] mov ds:[6],ax mov ax,4c00h int 21h code ends end start
View Code


实验七:【总算是撸出来了好开心,这里要感谢一位师傅,在自闭的时候给了我冷静】

;实验七
assume cs:codesg data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995'
    ;年份:每一个一个4字节,4*21 【0-53H】 
 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,19514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
    ;每一个一个4字节,4*21 【54H-0A7H】
 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 dw 11542,14430,15257,17800
    ;员工数:每一个两个字节,2*21 【0A8H-H】
 data ends table segment db 21 dup('year summ ne ?? ') table ends codesg segment start:
        mov ax,data mov ds,ax mov ax,table mov es,ax ;定义好了数据段
        
        mov cx,21
        mov bx,0
        mov si,0
        mov di,0
        mov ax,0
        mov ss,ax mov sp,2003H s:
            
            push cx mov ax,0[si] mov es:0[bx],ax mov ax,0[si+2] mov es:2[bx],ax ;年份赋值:每一次赋一个字,执行两次,完成四个字节的赋值,si来遍历年份
            
            mov ax,54H[si] mov es:5[bx],ax mov ax,54H[si+2] mov es:7[bx],ax ;收入赋值:每一次赋一个字,执行两次,完成四个字节的赋值
            
            mov ax,0A8H[di] mov es:10[bx],ax ;雇员赋值:每一次赋一个字,执行一次,完成两个字节的赋值
                        
            mov ax,54H[si] mov dx,54H[si+2]   ;赋值被除数
            mov cx,0A8H[di] div word ptr cx pop cx mov es:13[bx],al add bx,16 ;用bx控制行
            add si,4  ;用si控制年份和收入
            add di,2  ;用di控制雇员 
 loop s mov ax,4c00H int 21H codesg ends end start
View Code


实验八:

八没啥好说的,直接debug一下就可以了,值得一提的是jmp放的是偏移地址,而且 “ -u ” 的时候,要加 “ 0 ”才会显示start前的指令


实验九:显示绿色、红底绿色、白底蓝色的welcome to masm!

  • 我先用python脚本写出了“welcome.....”的十六进制表示
u="welcome to masm!" strs=""

# 绿字 # for i in u: # strs=strs+str(hex(ord(i)))[2:]+"h,"+"2h"+"," # print(strs) # print(len(strs.split(",")))

# 绿地红字 # for i in u: # strs=strs+str(hex(ord(i)))[2:]+"h,"+"24h"+"," # print(strs) # print(len(strs.split(",")))

# 3.白底蓝字
for i in u: strs=strs+str(hex(ord(i)))[2:]+"h,"+"0F1h"+","
print(strs) print(len(strs.split(",")))
View Code
  •  然后再是写asm
;实验9
assume cs:code data1 segment ;1.绿底字体
 db 77h,2h,65h,2h,6ch,2h,63h,2h,6fh,2h,6dh,2h,65h,2h,20h,2h,74h,2h,6fh,2h,20h,2h,6dh,2h,61h,2h,73h,2h,6dh,2h,21h,2h data1 ends data2 segment ;2.绿底红字
 db 77h,24h,65h,24h,6ch,24h,63h,24h,6fh,24h,6dh,24h,65h,24h,20h,24h,74h,24h,6fh,24h,20h,24h,6dh,24h,61h,24h,73h,24h,6dh,24h,21h,24h data2 ends data3 segment ;3.白底蓝字
 db 77h,0F1h,65h,0F1h,6ch,0F1h,63h,0F1h,6fh,0F1h,6dh,0F1h,65h,0F1h,20h,0F1h,74h,0F1h,6fh,0F1h,20h,0F1h,6dh,0F1h,61h,0F1h,73h,0F1h,6dh,0F1h,21h,0F1h data3 ends code segment start:
        mov ax,0b800h mov ds,ax ;1.绿底字体
        mov ax,data1 mov es,ax mov cx,32
        mov bx,0
        
        s1:
        mov al,es:[bx] mov ds:[bx+0a12h],al inc bx loop s1 ;2.绿底红字
        mov ax,data2 mov es,ax mov cx,32
        mov bx,0
        
        s2:
        mov al,es:[bx] mov ds:[bx+0a32h],al inc bx loop s2 ;3.白底蓝字
        mov ax,data3 mov es,ax mov cx,32
        mov bx,0
        
        s3:
        mov al,es:[bx] mov ds:[bx+0a52h],al inc bx loop s3 mov ax,4c00h int 21h code ends end start
View Code

 

 

 

 


10.10 参数和结果传递的问题

这里我改了一下代码   mov [di].2,dx    的时候居然报错有点迷

;P201
assume cs:code data segment dw 1,2,3,4,5,6,7,8 dd 0,0,0,0,0,0,0,0 data ends code segment start:
            mov ax,data mov ds,ax mov si,0
            mov di,16
            
            mov cx,8
        s:   
            mov bx,[si] call cube mov [di],ax mov [di+2],dx add si,2
            add di,4 loop s mov ax,4c00h int 21h cube:   mov ax,bx mul bx mul bx ret code ends end start
View Code


 

10.11 批量数据的传递

assume cs:code data segment db 'conversation' data ends code segment start:
        mov ax,data mov ds,ax     ;ds赋值
        
        mov si,0
        mov cx,12    ;设置循环体
        call capital   ;调用函数
        
        mov ax,4c00h int 21h capital:
        and byte ptr [si],11011111b   ;将字符转为大写
        inc si loop capital ret code ends end start
View Code

 


实验十(1) 显示字符串

在这次实验中,我们将要编写3个子程序,通过它们来认识几个常见的问题和掌握解决这些问题的方法。同前面的所有实验一样,这个实验是必须要独立完成的,在后面的课程中,将要用到这个实验中编写的3个子程序。
1.  显示字符串
问题:

显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。

提示:
(1)  子程序的入口参数是屏幕上的行号和列号,注意在子程序内部要将它们转化为显存中的地址,首先要分析一下屏幕上的行列位置和显存地址的对应关系:
(2)  注意保存子程序中用到的相关寄存器:
(3)  这个子程序的内部处理和显存的结构密切相关,但是向外提供了与显存结构无关的接口。通过调用这个子程序,进行字符串的显示时可以不必了解显存的结构,为编程提供了方便。在实验中,注意体会这种设计思想。

子程序描述
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
    (cl)=颜色,ds:si指向字符串的首地址
返回:无
就用举例:在屏幕的8行3列,用绿色显示data段中的字符串。

这一份是网上的答案,我结合自己的理解添加了注释【感觉师傅写的很谨慎,考虑地很完善】

 1 assume cs:code  2 data segment  3         db 'welcome to masm!',0
 4 data ends  5 
 6 code segment  7 start: 
 8    ;dx存放的是行列信息
 9     mov dh,8
10     mov dl,3
11     mov cl,2
12     mov ax,data 13     mov ds,ax 14     mov si,0
15     
16     call show_str 17     mov ax,4c00h 18     int 21h 19         
20 show_str:  
21 
22     ; 23     ;入栈储存数据tt
24     ;   
25     push dx 26     push cx 27     push si 28     
29     ; 30     ;第八行定位【460-4ff】
31     ; 【7*a0=460】
32     mov bl,dh   ;行号赋值8
33     dec bl       ;行号自减一
34     
35     mov al,160     ;A0h【每一行的自增值】
36     
37     mul bl         ;将bl与al相乘结果放到ax中
38     mov bx,ax     ;结果赋值
39     ; 40     ;第三列定位【04-05】
41     ; 42     add dl,dl ;列号自增
43     ; 44     ;行列号拼接形成偏移地址
45     ; 46     add bl,dl 47     ; 48     ;设定显示位置
49     ; 50     mov ax,0b800h 51     mov es,ax 52     
53     mov al,cl ;颜色赋值【后面要用cx来结束循环所以这里要把cx的数据先保存起来】
54     
55     mov di,0    ;数据初始化
56     s:     
57         mov ch,0
58         mov cl,ds:[si] 59         jcxz ok 60         ;将数据赋给cx,当cx为0的时候(到字符串尾)就会自动退出
61         
62         mov es:[bx+di],cl 63         mov es:[bx+di+1],al;颜色赋值【颜色设定在高位】
64         
65         add di,2 ;es段每次跳两个字节
66         inc si  ;ds段每次跳一个
67  loop s 68     
69     ok:    
70         ; 71         ;数据恢复
72         ; 73         pop dx 74         pop cx 75         pop si 76         ret
77 code ends 78 end start

 

然后这一份是我自己写的暴力版,当初完全没get到,cl=2 有什么内涵 Orz

 1 ;实验10(1)
 2 assume cs:code  3 data segment  4     db 'Welcome to masm!',0  ;17
 5 data ends  6 
 7 code segment  8     start:
 9         mov dh,8
10         mov dl,3
11         mov cl,2
12         mov ax,data 13         mov ds,ax 14         
15         mov si,0
16         call show_str 17         
18         mov ax,4c00h 19         int 21h 20         
21         
22     show_str: 
23         mov si,0466h 24         mov cx,17
25         
26         mov ax,0b800h 27         mov es,ax 28         
29         mov di,0
30         
31     s:    mov al,ds:[di] 32         mov es:[si],al 33         
34         mov ah,2
35         mov es:[si+1],ah 36         
37         add si,2
38         add di,1
39         jcxz ok 40  loop s 41         
42         
43     ok: ret
44 code ends 45 end start

 

 


 实验十(2) 解决除法溢出

问题
前面讲过,div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数:进行16位除法的时候,用ax存储结果的商,dx存储结果的余数。可是,现在有一个问题,如果结果的商大于ah或ax所能存储的最大值,那么将如何?比如,下面的程序段:

1  mov bh,1
2  mov ax,1000
3  div   bh

进行的是8位除法,结果的商为1000,而1000在ah中放不下,又比如,下面的程序段:

1 mov ax,1000h 2 mov dx,1
3 mov bx,1
4 div   bx

进行的是16位除法,结果的商为11000H,而11000H在ax中存放不下。我们在用div指令做除法的时候,很可能发生上面的情况:结果的商过大,超出了寄存器所能存储的范围。当CPU执行div等除法指令的时候。如果发生这样的情况,将引发CPU的一个内部错误。这个错误被称为:除法溢出。我们可以通过特殊的程序来处理这个错误,这里我们不讨论这个错误的处理,这是后面的课程中要涉及的内容。

好了,我们已经清楚了问题的所在:用div指令做除法的时候可能产生除法溢出。由于有这样的问题,在进行除法运算的时候要注意除数和被除数的值,比如1000000/10就不能用div指令来计算。那么怎么办呢?我们用下面的子程序divdw解决。

子程序描述
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
参数:

    (ax)=dword型数据的低16位
    (dx)=dword型数据的高16位
    (cx)=除数
返回:

    (dx)=结果的高16位,(ax)=结果的低16位
    (cx)=余数
应用举例:

  计算1000000/10(F4240H/0AH)

1 mov ax,4240h 2 mov dx,000fh 3 mov cx,0ah 4 call divdw

结果:

   (dx)=0001h,(ax)=86a0h,(cx)=0

提示

给出一个公式:
X:被除数,范围:[0,FFFF FFFF]
N:除数,范围:[0,FFFF]
H:X高16位,范围:[0,FFFF]
L:X低16位,范围:[0,FFFF]
int():描述性运算符,取商,比如:rem(38/10)=8
rem():描述性运算符,取答数,比如:rem(38/10)=8


公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N


这个公式将可能产生溢出的除法运算:X/N,转变为多个不会产生溢出的除法运算。公式中,等号右边的所有除法运算都可以用div指令来做,肯定不会导致除法溢出。

 

这里我写到pop ax就与网上的答案产生分歧了,后来才知道没有好好理解王爽老师提供的公式的含义:

1 进行的是1000000/10
2 
3 000f 4240h / 0ah = 1h*10000h+[5*10000h+4240h]/0ah 4  = 10000h+54240h/ah 5  = 10000h+86a0h 6  = 186a0h 7 其中: 8 f / a = 1……5

 

 也就是说高位除的时候,它的商是结果的高位,它的余数是低位除的高位

 1 ;实验十(2)
 2 
 3 assume cs:code  4 
 5 stack segment  6     dw 8 dup(0)  7 stack ends  8 
 9 code segment 10     start:
11             mov ax,stack 12             mov ss,ax 13             mov sp,16
14             
15             mov ax,4240h 16             mov dx,000fh 17             mov cx,0ah 18             ;[ dx ax ] / cx = [dx ax] …… cx
19             call divdw 20             
21             mov ax,4c00h 22             int 21h 23             
24     divdw:  ;[x/n = int()/n*65536+mod()/n] 12/3 = (1*10 + 2)/3 = [int(12/10)*10 + mod(12/10)]/3 =int(12/10)*10/3 + mod(12/10)/3= 1 + 3 
25             ;将高位与除数做运算
26             push ax    ;将L存放起来
27             
28             mov ax,dx  ;将ax转化为H
29             mov dx,0   ;将余数位清零
30             div cx       ;int(H/N)=ax,rem(H/N)=dx
31             
32             mov bx,ax  ;将int(H/N)的值存起来[这是已经得到的高位]
33             
34             ;将低位与除数做运算
35             pop ax     ;将L赋值给ax,rem(H/N)=dx
36             div cx        ; 37             
38             mov cx,dx  ;cx放余数
39             mov dx,bx  ;dx放商的高位,ax默认低位
40     
41             ret
42 code ends 43 end start

 

实验十(3) 解决除法溢出

问题
编程,将data段中的数据以十进制的形式显示出来。

1 data segment 2 dw  123,12666,1,8,3,38
3 data ends

  这些数据在内存中都是二进制信息,标记了数值的大小。要把它们显示到屏幕上,成为我们能够读懂的信息,需要进行信息的转化。比如,数值12666,在机器中存储为二进制信息:0011000101111010B(317AH),计算机可以理解它。而我们要在显示器上读到可以理解的数值12666,我们看到的应该是一串字符:“12666”。由于 显卡遵循的是ASCII编码,为了让我们能在显示器上看到这串字符,它在机器中应以ASCII码的形式存储为:31H、32H、36H、36H、36H(字符“0”~“9”对应的ASCII码为30H~39H)。

  通过上面的分析可以看到,在概念世界中,有一个抽象的数据12666,它表示了一个数值的大小。在现实世界中它可以有多种表示形式,可以在电子机器中以高低电平(二进制)的形式存储,也可以在纸上、黑板上、屏幕上以人类的语言“12666”来书写。现在,我们面临的问题就是,要将同一抽象的数据,从一种表示形式转化为另一种表示形式。
  可见,要将数据用十进制形式显示到屏幕上,要进行两步工作:
(1)  将用二进制信息存储的数据转变为十进制形式的字符串:
(2)  显示十进制形式的字符串。
第二步我们在本次实验的第一个子程序中已经实现,在这里只要调用一下show_str即可。我们来讨论第一步,因为将二进制信息转变为十进制形式的字符串也是经常要用到的功能,我们应该为它编写一个通用的子程序。

子程序描述
名称:dtoc
功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:

    (ax)=word型数据
    ds:si指向字符串的首地址
返回:无
应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出来。在显示时我们调用本次实验中的第一个子程序show-str。

提示
  下面我们对这个问题进行一下简单地分析。
(1)  要得到字符串“12666”,就是要得到一列表示该字符的ASCII码:31H、32H、36H、36H、36H。十进制数码字符对应的ASCII码=十进制数码值+30H要得到表示十进制数的字符串,先求十进制数每位的值。例:对于12666,先求得每位的值:1、2、6、6、6。再将这些数分别加上30H,便得到了表示12666的ASCII码串:31H、32H、36H、36H、36H。
(2)  那么,怎样得到每位的值呢?采用如图10.2所示的方法。

 1 dtoc:
 2         push ax  3         push bx  4         push si  5             mov bx,10
 6             mov si,0
 7             
 8         s1:  
 9                         ;取出每一位并且将它转化为字符放到栈段里面
10             mov dx,0
11             div bx 12             add dx,30h 13             push dx 14             
15             inc si    ;记录一共push几个数字
16             mov cx,ax 17             Inc cx 18  loop s1 19                      
20            mov cx,si 21            mov si,0
22         s2:
23            pop ds:[si] 24            add si,1 
25  loop s2 26         
27         pop si 28         pop bx 29         pop ax 30     ret    

 

 

 后记:

一开始是打算这样写的,但是出现了报错,错误点是第17行。实际上当ax变成0的时候 loop,cx 默认自减一,然后cx就变成负的了,没有达到当ax变成零自动退出的目的,而且也没有三个push来保存数据,还是保有着C/C++当中的局部变量的思想Orz。这里数据恢复很重要啊

 1 dtoc:
 2             mov bx,10
 3             mov si,0
 4             
 5         s1:  
 6                         ;取出每一位并且将它转化为字符放到栈段里面
 7             mov dx,0
 8             div bx  9             add dx,30h 10             push dx 11             
12             inc si    ;记录一共push几个数字
13             mov cx,ax 14  loop s1 15             push ax 16                      
17            mov cx,si 18            mov si,0
19         s2:
20            pop ds:[si] 21            add si,1 
22  loop s2 23 ret    

 


 实验十一:

;实验十一
assume cs:codeseg

dataseg segment
	db "Beginner's All-purpose Symboliv Instruction Code.",0
dataseg ends

codeseg segment
	begin:
		mov ax,dataseg
		mov ds,ax       ;数据段初始化
 		mov si,0		;data:[0]
		call letters
		
		mov ax,4c00h
		int 21h

letters:
s:	mov cl,ds:[si]	;ds:[si]  => 将data段的每一位赋值给cl,那么当读到最后一位的0就会退出循环
	jcxz ok         ;当cx为0的时候跳转到ok
	mov bl,97		;97 ascii 是一个“a”
	cmp cl,bl		;执行cl-bl判断大小影响  cl > bl ==> cf,zf
	jnb ba		;大于等于就转移到ba,检测cf是否等于0(NC)
	inc si
	loop s
	
ba:					;大于等于a跳到这
	mov bl,122
	cmp cl,bl
	jna lz			;小于等于就转移检测cf/zf是否等于1(ZR)
	inc si          ;不然就找下一个
	jmp letters
lz:					;小于等于z跳到这( a<= x <=z )
    and cl,11011111b
	mov ds:[si],cl
	inc si
	jmp letters
ok:
	ret
	
codeseg ends
end begin

 


实验十二:

        mov ax, cs
        mov ds, ax
        mov si, offset do0

设定ds段,用C语言来描述就是相当于有一个data段的指针,将其指向code段(asm代码中的第29行)

        mov ax, 0
        mov es, ax
        mov di, 200h

设定es段,用C语言来描述就是相当于有一个指针,将其指向内存中的0:[200]

        mov cx, offset do0end - offset do0
        cld
        rep movsb

复习一下:

MOVSB:字符串传送指令,这条指令按字节传送数据。通过SI和DI这两个寄存器控制字符串的源地址和目标地址,比如DS:SI这段地址的N个字节复制到ES:DI指向的地址,复制后DS:SI的内容保持不变。

REP:指令就是“重复”的意思,术语叫做“重复前缀指令”,因为既然是传递字符串,则不可能一个字(节)一个字(节)地传送,所以需要有一个寄存器来控制串长度。这个寄存器就是CX,指令每次执行前都会判断CX的值是否为0(为0结束重复,不为0,CX的值减1),以此来设定重复执行的次数。因此设置好CX的值之后就可以用REP MOVSB了。

CLD:则是清方向标志位,也就是使DF的值为0,在执行串操作时,使地址按递增的方式变化,这样便于调整相关段的的当前指针。这条指令与STD的执行结果相反,即置DF的值为1。

所以说这三条的意思是将ds的内容赋值到es中。

        mov ax, cs
        mov ds, ax
        mov si, 202h        
              
        mov ax, 0b800h
        mov es, ax
        mov di, 12*160+36*2    

这一段是设置显示结果的初始化(指定ds,es段),其中在  “mov si,202h”中为什么设定si是202h ?因为rep movsb之后0:200段已经放的是cs中的代码,所以可以直接用

mov cx,9
		mov bl,2
	  s:mov al,ds:[si]
	    mov es:[di],al
		mov es:[di+1],bl
		inc si
		add di,2
		loop s  

这一段是把ds段中的db内容赋值到显存区,其中“mov es:[di+1],bl”设定颜色是绿的

        mov ax, 0
        mov es, ax
        mov word ptr es:[0], 200h
        mov word ptr es:[2], 0

设置中断向量将入口地址0:200写入中断向量表0号表项中,0号表项的地址是0:0

	mov ax, 1000
        mov bl, 1
        div bl

 一段除法溢出,测试写的对不对 

assume cs:codesg codesg segment start:
        mov ax, cs mov ds, ax mov si, offset do0 mov ax, 0
        mov es, ax mov di, 200h mov cx, offset do0end - offset do0 cld
        rep movsb
        
        mov ax, 0
        mov es, ax mov word ptr es:[0], 200h mov word ptr es:[2], 0
        
        mov ax, 1000
        mov bl, 1
        div bl mov ax, 4c00h int 21h do0:
        jmp short do0start db "overflow!"   
    do0start:
        mov ax, cs mov ds, ax mov si, 202h mov ax, 0b800h mov es, ax mov di, 12*160+36*2  
        
        mov cx,9
        mov bl,2
      s:mov al,ds:[si] mov es:[di],al mov es:[di+1],bl inc si add di,2 loop s mov ax,4c00h int 21h do0end:
        nop codesg ends end start
完整代码

 


 

十三章案例:

问题一:编写安装中断7ch的中断案例

功能:求一word型数据的平方

参数:(ax)=要计算的数据

返回值:dx,ax中存放结果的高16位和低16位

应用举例:求2*3456^2

assume cs:code code segment start:
            mov ax,3456
            jmp install finish:
             int 7ch add ax,ax adc dx,dx ;上面两条进行的是加法,dx存放高位,ax存放低位
            mov ax,4c00h int 21h install:
        push ax push cx push ds push si push es push di mov ax,cs mov ds,ax mov si,offset sqr ;将代码段的数据给data段
        mov ax,0
        mov es,ax mov di,200h mov cx,offset sqrend-offset sqr cld 
        rep movsb
        
        mov ax,0
        mov es,ax mov word ptr es:[7ch*4],200h mov word ptr es:[7ch*4+2],0
        
        pop di pop es pop si pop ds pop cx pop ax jmp finish sqr: 
        mul ax iret
    sqrend:
        nop code ends end start
View Code

 达到的目的:

 

; assume cs:codeseg
; codeseg segment
    ; start:mov ax,0b800h
    ; mov es,ax 
    ; mov byte ptr es:[12*160+42*2],'!'
    ; int 0
    
    ; mov ax,4c00h
    ; int 21
; codeseg ends
; end start

assume cs:code
data segment
    db 'conversation',0
data ends

code segment
    start:
            mov ax,data
            mov ds,ax
            mov si,0
            
            jmp install
        finish:
             int 7ch
                       
            ; mov ax, 0b800h
            ; mov es, ax
            ; mov di, 12*160+36*2 
            
            ; mov bl,2
          ; s:mov ch,0
            ; mov cl,ds:[si]
            ; mov es:[di],al
            ; mov es:[di+1],bl
            ; inc si
            ; add di,2
            
            ; loop s
            ; ;设置屏幕显示        
            
            mov ax,4c00h
            int 21h
            
    install:
        push ax
        push cx
        push ds
        push si
        push es
        push dx 
        
        s_start: 
        mov ax,cs
        mov ds,ax
        mov si,offset capital
        
        mov ax,0
        mov es,ax
        mov di,200h
        
        mov cx,offset capitalend - offset capital
        cld 
        rep movsb
                    ;上面完成的是赋值            
        mov ax,0
        mov es,ax
        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4],0
                    ;将地址写入
        pop dx
        pop es
        pop si
        pop ds
        pop cx
        pop ax
        
        jmp finish
        
    capital:
            ;小写转大写的功能函数
            push dx
            push cx
            push si
            
            mov ax,data
            mov dx,ax
            
            mov si,0
        change :
            mov cl,ds:[si]
            mov ch,0
            jcxz ok
            and byte ptr [si],11011111b
            inc si
            jmp short change
        ok:
            pop si
            pop cx
            pop dx
            iret
    capitalend:nop
            
code ends
end start
问题二的asm,还在改

 

 

 

 

  

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM