《汇编语言》王爽 实验

《汇编语言》王爽 实验

练习题目:

1.编程计算0123H、0456H,0abxH、0defH、0fesH、0cbaH、0987H这8个数据的和,结果存放在ax中。

assume cs:code

code segment
       dw 0123h,0564h,0789H,0abcH,0defH,0fedH,0cbaH,0987H
                ;由于数据在代码段中,所以段地址是CS
                ;dw定义的数据在最开始的地方,所以偏移地址是0开始
  start:
       mov bx,0 ;存放偏移地址,最开始为0
       mov ax,0 ;用于存放结果
       mov cx,8
      s:
       add ax,cs:[bx]
       add bx,2 ;读完一个数,偏移地址bx加2
       loop s
       
       mov ax,4c00h
       int 21h
       
code ends
end start

2.利用栈编程将定义的数据逆序(联想栈的特性)存放:dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H。(有疑问 没看懂???)

assume cs:codesg
codesg segment
        dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H;地址0~15
        dw 0,0,0,0,0,0,0,0;定义8个字型空数据,后面当作栈来使用,地址是16~31
        ;由于数据在代码段中,所以段地址是CS

    start:  
            mov ax,cs
            mov ss,ax
            mov sp,32;设置栈顶ss:sp指向cs:32,十进制的32
            
            mov bx,0
            mov cx,8
           s:push cs:[bx];入栈
            add bx,2
            loop s; 以上代码段0~15个单元中的8个字型数据一次入栈

            mov bx,0
            mov cx,8
          s0:pop cs:[bx];出栈
            add bx,2
            loop s0;依次出栈8个执行数据到代码段0~15单元中

            mov ax,4c00h
            int 21h
codesg ends
end start

在8086CPU中数据、栈和代码存储空间不能大于64KB。可以用像定义代码段一样的方法来定义多个段并在其中定义需要的数据,或者通过定义数据来取得栈空间。

改进后:

assume cs:codesg,ds:data,ss:stack;在源程序中为三个段进行有意义的名称
data segment
        dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends

stack segment
        dw 0,0,0,0,0,0,0,0 ;定义8个字型空数据,后面当作栈来使用
stack ends

code segment
    start:      
            mov ax,stack
            mov ss,ax
            mov sp,16     ;设置栈底ss:sp指向stack:16
            
            mov ax,data
            mov ds,ax     ;ds指向data段
            mov bx,0      ;ds:bx指向data段中的第一个单元(ds:bx)
                          ;为什么这里没有" mov cx,8 "
           s:push cs:[bx]
            add bx,2
            loop s        ;以上代码段0~16个单元中的8个字型数据依次入栈
            
            mov bx,0
            mov cx,8
          s0:pop cs:[bx]
            add bx,2
            loop s0       ;依次出栈8个执行数据到代码段0~16单元中

            mov ax,4c00h
            int 21h
codesg ends
end start

3.大小写转换。
关键点: and al,11011111B ;小写转换成大写
or al,00100000B ;大写转换成小写

assume cs:codesg,ds:datasg

datasg segment
db'BaSiC' ;表示字符串
db'iNfOfMaTiOn'
datasg ends

codesg segment
    start:  mov ax,datasg
            mov ds,ax         ;设置ds执行datasg段
            mov bx,0          ;设置(bx)=0,ds:bx指向'BaSiC'的第一个字母
            
            mov cx,5          ;设置循环次数,因为BaSiC有5个字母
            
          s:mov al,[bx+0]     ;将ASCII码从ds:bx所指向的单元中取出
            and al,11011111B  ;口岸al中ASCII码的第5个位置变为0,变为大写字母
            mov [bx],al       ;转变后将ASCII码写回单元
            
            mov [bx+5]        ;定位第二个字符串的字符
            or al,00100000B
            mov [bx+5],al
            
            inc bx
            
            loop s

            mov ax,4c00H
            int 21H
codesg ends
end start

4.用DI和SI实现复制到它后面的数据区中。
一般地,ds:si指向要复制的原始空间,ds:di指向复制的目的空间。

;用数组的思维[bx(si或di)+idata]的方式优化程序
assume cs:codesg,ds:datasg

datasg segment
db'welcome to asm!'
db'................'
datasg ends

codesg segment
    start  :mov ax,datasg
            mov ds,ax
            mov si,0 ;ds:si指向第一个字符串
            mov cx,8
          s:mov ax,[si] ;第一个字符串的的第一个元素
            mov [si+16],ax ;目标字符串的第二个元素
            add si,2
            loop s

            mov ax,4c00h
            int 21H
codesg ends
end start

用原始的方法可以这样写主程序:

     start:mov ax,datasg
            mov ds,ax
            mov si,0
            mov di,16 ;ds:si指向要复制的原始空间(第一个字符串),ds:di指向复制的目的空间(第二个字符串)
            mov cx,8
          s:mov ax,[si]
            mov [di],ax
            add si,2
            add di,2
            loop s

5.编程将数据段中每一个单词的头一个字母改为大写字母。
如图所示:
在这里插入图片描述

assume cs:codesg,ds:datasg
datasg segment
    db'1. file          ';长度刚好都是16个字节
    db'2. edit          '
    db'3. search        '
    db'4. view          '
    db'5. options       '
    db'6. help          '
datasg ends

codesg segment
      start:
            mov ax,datasg
            mov ds,ax
            mov bx,0
            mov cx,6
          s:    
            mov al,[bx+3]
            and al,11011111B
            mov [bx+3],al
            add bx,16
            loop s

            mov ax,4c00h
            int 21h
codesg ends
end start

6. 编程将数据段中每个单词改为大写字母

assume cs:codesg,ds:datasg
    datasg segment
    db 'ibm             '
    db 'dec             '
    db 'dos             '
    db 'vax             '
datasg ends

codesg segment
      start:
            mov ax,datasg
            mov ds,ax
            mov bx,0;用bx来定位行
            mov cx,4
            
         s0:
            mov dx,cx;用dx寄存器来临时存放外层cx的值
            mov si,0;用si来定位列
            mov cx,3
            
          s:
            mov al,[bx+si]
            and al,11011111B
            mov [bx+si],al
            inc si
            loop s
            
            add bx,16
            mov cx,dx;在进行外层循环的时候回复cx的值
            loop s0
            
            mov ax,4c00h
            int 21h
codesg ends
end start

在上面的程序中,8086 CPU si、cx、ax、bx这些寄存器经常要使用到;cs、ip、ds也不能用,因为cs:ip时刻指向当前指令,ds指向datasg段;那么可用的寄存器就只用dx、di、es、ss、sp、bp等寄存器了。内存可以解决经常性的数据暂存问题。为了使程序结构清晰便于阅读,应该使用栈。

使用栈改进后的程序使用栈:

assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
    db 'ibm             '
    db 'dec             '
    db 'dos             '
    db 'vax             '
datasg ends

stacksg segment
    dw 0,0,0,0,0,0,0,0;定义一个段,用作栈段,容量为16个字节
stacksg ends

codesg segment
      start:mov ax,stacksg
            mov ss,ax
            mov sp,16
            mov ax,datasg
            mov ds,ax
            mov bx,0;用bx来定位行
            mov cx,4
         s0:push cx;datasg:40h单元存放外层cx的值
            mov si,0;用si来定位列
            mov cx,3
          s:mov al,[bx+si]
            and al,11011111B
            mov [bx+si],al
            inc si
            loop s
            add bx,16
            pop cx;在进行外层循环的时候回复cx的值
            loop s0
            mov ax,4c00h
            int 21h
codesg ends
end start

7.利用除法指令计算 dd 100001H 除以 dw 100,商放在 dw 0中

data segment
    dd 100001H
    ;16位存储在ax中,高16位存储在dx中
    ;被除数100001大于2^16=65535(FFFF),不能用ax来存放,要用dx和ax两个寄存器联合存放。除数小于255,可用一个8位寄存器存放,但是被除数是32位的,除数应为16位,所以要用一个16位寄存器来存放除数。
    ;100001的十六进制为186A1H,100001的高16(1)存放在dx,低16(86AH)存放在ax中。

    dw 100
    dw 0
data ends

    mov ax,data
    mov ds,ax
    mov ax,ds:[0];16位存储在ax中
    mov dx,ds:[2];16位存储在dx中
    div word ptr ds:[4]
    mov ds:[6],ax

8.编写:安装中断7ch的中断例程实现求一word型数据的平方。

1、编程实现求平方功能的程序;
2、安装程序在0:200处;
3、设置中断向量表将程序的入口地址保存在7ch表项中,使其成为中断7ch的中断例程。
;计算
assume cs:code;主程序
             code segment
             start:
                     mov ax,3456
                     int 7ch
                     add ax,ax
                     adc ax,dx
                     mov ax,4c00h
                     int 21h
             code ends
             end start

             assume cs:code
             code segment
             start:;安装程序
                     mov ax,cs
                     mov ds,ax
                     mov si offset sqr;设置ds:si指向源地址
                     mov ax,0
                     mov es,ax
                     mov di,200h;设置es:di指向目的地址
                     mov cx,offset sqrend- offset sqr;设置cx为传输长度
                     cld;设置传输方向为正
                     rep movsb;跳转
            
                     ;设置中断向量表
                     mov ax,0
                     mov es,ax
                     mov word ptr es:[7ch*4],200h
                     mov word ptr ws:[7ch*4+2],0
                     mov ax,4c00h
                     int 21h
                 ;中断例程(实现功能)
                 sqr:
                     mul ax
                     iret;中断例程实现返回指令iret(配套使用int···iret,子程序中配套使用call···ret)
                 sqrend:
                     nop
             code ends
end start

老师布置的实验题目:

实验二
1.编程实现书上问题7.9

;通过编程将datasg段中每个单词前4个字母改写为大写字母
assume cs:codesg,ss:stacksg,ds:datasg

stacksg segment
 dw 0,0,0,0,0,0,0,0
stacksg ends

datasg segment
 db '1. display      '
 db '2. brows        '
 db '3. replace      '
 db '4. modify       '
datasg ends

codesg segment
 start: 
codesg ends
end start

在这里插入图片描述在这里插入图片描述

源代码:

;将datasg段中每个单词的前4个字母改成大写字母

assume cs:codesg,ss:stacksg,ds:datasg
;assume用来加上某一段寄存器和程序中的某一用segment……ends定义的段相关联。

;①segment是段的意思,是段定义伪指令
;②汇编中,有数据段,代码段,堆栈段以及附加段
;格式:
;段名 SEGMENT [定位类型] [组合类型] [类别名]
;段名 ENDS
;③功能:把程序分段,实现存储器的分段管理。

stacksg segment
  dw 0,0,0,0,0,0,0,0
stacksg ends

;伪指令db、dw、dd都可以定义字符串,但最多的是用db来定义字符串,其中一个原因是dw、dd定义的字符串到了内存中排序是相反的。
;db定义 字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1
;dw定义 字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2
;dd定义 双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4

;datasg中定义了4个字符串,每个字符串长度均为16字节,要求修改每个单词前4个字母,则要修改每个字符串的[3]~[6]
datasg segment
  db '1. display      '
  db '2. brows        '
  db '3. replace      '
  db '4. modify       '
datasg ends

codesg segment
  start:mov ax,stacksg
        mov ss,ax
        mov sp,16
        mov ax,datasg
        mov ds,ax
        mov bx,0
        mov cx,4
      ;用一个二重循环来解决,第一重循环用来循环字符串,第二重用来修改第一行字符串的【3~6】,共4*4次循环
      ;运用一个栈保存第一重循环数
      s:push cx
        mov di,3
        mov cx,4
        
     s0:mov al,[bx+di]
        and al,11011111b
        mov [bx+di],al
        inc di
        loop s0
        
        pop cx
        add bx,16
        loop s
        
        mov ax,4c00h
        int 21      ;21号中断
        ;这两条指令说实现的功能就是程序返回。
        
codesg ends

end start
;end是个伪指令,程序的结束标记

2.寻址方式在结构化数据访问中的应用

Power idea 公司从1975年成立一直到1995年的基本情况如下。
在这里插入图片描述下面的程序中,已经定义好了这些数据:

assume cs:code

data segment
    db '1975','1976','1977','1978','1979','1980', '1981'
    db '1982', '1983','1984', '1985','1986', '1987','1988'
    db '1989','1990','1991','1992','1993','1994','1995'
    ;以上是表示21年的21个字符串
	
    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479
    dd 140417,197514,345980,590827,803530,118300,1843000
    dd 2759000,3753000,4649000,5937000
    ;以上是表示21年公司总收入的21个dword型数据
	
    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037
    dw 5635,8226,11542,14430,15257,17800
	;以上是表示21年公司雇员人数的21个word数据
data ends

table segment
  ;预留位置,用于显示数据
   db 21 dup ('year summ ne ?? ')
table ends

编程,将data段中的数据按如下格式写入到table段中,并计算21年中的人均收入(取整),结果也按照下面的格式保存到table段中:
在这里插入图片描述提示,可将data段中的数据看成是多个数组,而将table中的数据看成是一个结构性数据的数组,每个结构性数据中包含多个数据项。可用bx定位每个结构性数据,用idata定位数据项,用si定位数组项中的每个元素,对于table中的数据的访问可采用[bx].idata和[bx].idata[si]的寻址方式。

参考博客题目解析
参考博客源代码

源代码:


3.将任意输入的十进制数(<32768)转换成四位十六进制进行输出显示。
要求:1)有提示信息
2)按下ESC推出程序
3)将结果显示在屏幕中间

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值