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


    实验一:查看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,还在改

      

     

  • 相关阅读:
    PCB genesis方槽加内角槽孔实现方法
    PCB genesis连孔加除毛刺孔(槽孔与槽孔)实现方法(三)
    PCB genesis连孔加除毛刺孔(圆孔与槽孔)实现方法(二)
    PCB genesis连孔加除毛刺孔(圆孔与圆孔)实现方法(一)
    为什么要用Redis而不直接用Map做缓存
    Linux 查询端口被占用命令
    HashMap 和 Hashtable 的区别
    RandomAccess是什么
    接口和抽象类的区别是什么?
    为什么 Java 中只有值传递?
  • 原文地址:https://www.cnblogs.com/chrysanthemum/p/11456457.html
Copyright © 2020-2023  润新知