|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
16.1节 描述单元长度的标号
编程:将a标号的数据累加的结果放在b标号处
代码:
- assume cs: code
- code segment
- a: db 1, 2, 3, 4, 5, 6, 7, 8
- b: dw 0
- start: mov si, offset b
- mov bx, offset a
- mov cx, 8
-
- s: mov al, cs:[bx]
- mov ah, 0
- add cs:[si], ax
- inc bx
-
- loop s
-
- mov ax, 4c00H
- int 21H
-
- code ends
- end start
复制代码
在程序中,code、a、b、s都是标号,这里仅表示内存单元的地址
但是我们可以用另外的标号,这种标号不但表示内存单元的地址,还表示内存单元的长度
上面的程序可以写下面的样子:
代码:
- assume cs: code
- code segment
- a db 1, 2, 3, 4, 5, 6, 7, 8
- b dw 0
-
- start: mov cx, 8
- mov bx, 0
- s: mov al, a[bx]
- mov ah, 0
- add b, ax
- inc bx
-
- loop s
-
- mov ax, 4c00H
- int 21H
- code ends
- end start
复制代码
可以看看与刚开始的程序不同的是a标号处没有冒号了,其他它的作用就是表示刚开始的地址和定义的长度
比如:
指令:mov al, a[bx]
相当于:mov al, cs:0[bx]
指令:add b, ax
相当于:add cs:[8], ax
我们称这种标号为数据标号,它标记了存储数据单元的地址和长度
16.2节 在其他段使用数据标号
因为一般我们都不会定义数据在代码段中,所以我们将数据标号用于数据段
注意:在后面加有":"的地址标号,只能在代码段中使用,不能在其他段中使用
看这样的例子
- data segment
- a db 1, 2, 3, 4, 5, 6, 7, 8
- b dw 0
- c dw a, b
-
- data ends
复制代码
相当于下面的代码:
- data segment
- a db 1, 2, 3, 4, 5, 6, 7, 8
- b dw 0
- c dw offset a, offset b
-
- data ends
复制代码
再看下面的:
- data segment
- a db 1, 2, 3, 4, 5, 6, 7, 8
- b dw 0
- c dd a, b
-
- data ends
复制代码
相当于下面的代码:
- data segment
- a db 1, 2, 3, 4, 5, 6, 7, 8
- b dw 0
- c dw offset a, seg a, offset b, seg b
-
- data ends
复制代码
16.3 直接地址表
编程:以十六进制的形式在屏幕中间显示给定的字节型数据
步骤:
(1)将所在显示的字节放在al中
(2)将al的高位和低位分开,我这里分别放入ah和al中
(3)ah和al即为在table标号中的偏移
(4)将在table标号中ah偏移的字符放在bx中,然后让它在屏幕中央显示
()将在table标号中al偏移的字符放在bx中,然后让它在屏幕中央显示
具体代码:
- assume cs: code
- code segment
- start: mov al, 2eH
- call showbyte
-
- mov ax, 4c00H
- int 21H
-
- showbyte: jmp short show
- table db '0123456789ABCDEF'
-
- show: push ax
- push bx
- push ds
-
- mov ah, al
- mov cl, 4
- shr ah, cl
- and al, 00001111b
-
- mov bl, ah
- mov bh, 0
- mov ah, table[bx]
-
- mov ax, 0b800H
- mov es, ax
- mov es:[12* 160 + 80], ah
-
- mov bl, al
- mov bh, 0
- mov al, table[bx]
-
- mov ax, 0b800H
- mov es, ax
- mov es:[12* 160 + 80 + 2], al
-
- pop ds
- pop bx
- pop ax
-
- ret
-
- code ends
- end start
-
-
复制代码
编程:写一个子程序,计算sin(x), x = 0、30 、60、 90、120、150、180
大概流程跟上面的程序差不多,就是寻找table标号的偏移不一样,程序的方法是度数/30,然后将得到的数字自加,结果就是在table标号的偏移
具体代码:
- assume cs:code
- code segment
- start:
- mov al,60
- call showsin
- mov ax,4c00h
- int 21h
- showsin:
- jmp short show
-
- table dw ag0,ag30,ag60,ag90,ag120,ag150,ag180 ;字符串偏移地址表
- ag0 db '0',0 ;sin(0)对应的字符串“0”
- ag30 db '0.5',0 ;sin(0)对应的字符串“0.5”
- ag60 db '0.866',0 ;sin(0)对应的字符串“0.866”
- ag90 db '1',0 ;sin(0)对应的字符串“1”
- ag120 db '0.866',0 ;sin(0)对应的字符串“0.866”
- ag150 db '0.5',0 ;sin(0)对应的字符串“0.5”
- ag180 db '0',0 ;sin(0)对应的字符串“0”
-
- show: push bx
- push es
- push si
- mov bx,0b800h
- mov es,bx
- ;以下用角度值/30 作为相对于table的偏移量,取得对应的字符串的偏移地址,放在bx中
- mov ah,0
- mov bl,30
- div bl
- mov bl,al
- mov bh,0
- add bx,bx
- mov bx,table[bx]
- ;以下显示sin(x)对应的字符串
- mov si,160*12+40*2
- shows:
- mov ah,cs:[bx]
- cmp ah,0
- je showret
- mov es:[si],ah
- inc bx
- add si,2
- jmp shows
- showret:
- pop si
- pop es
- pop bx
- ret
- code ends
- end start
复制代码
像这种可以依据数据,直接计算出元素的位置的表,我们称其为:直接定定址表
16.4 程序入口地址的直接定址表
编程:编写子程序,实现如下功能:
(1)清屏
(2)设置前景色
(3)设置背景色
(4)向前滚动一行
说明,:用寄存器ah传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向前滚动
具体代码:
- ;编程:实现一个子程序setscreen,为显示输出提供如下功能:
- ;(1) 清屏。
- ;(2) 设置前景色。
- ;(3) 设置背景色。
- ;(4) 向上滚动一行。
- ;
- ;入口参数说明:
- ;(1) 用 ah 寄存器传递功能号:0 表示清屏,1表示设置前景色,2 表示设置背景色,3 表示向上滚动一行;
- ;(2) 对于2、3号功能,用 al 传送颜色值,(al) ∈{0,1,2,3,4,5,6,7}
- setscreen: jmp short set
- table dw sub1,sub2,sub3,sub4
- set:
- push bx
- cmp ah,3 ;判断传递的是否大于 3
- ja sret
- mov bl,ah
- mov bh,0
- add bx,bx ;根据ah中的功能号计算对应子程序的地址在table表中的偏移
-
- call word ptr table[bx] ;调用对应的功能子程序
- sret:
- pop bx
- iret
- ;功能子程序1:清屏
- sub1:
- push bx
- push cx
- push es
- mov bx,0b800h
- mov es,bx
- mov bx,0
- mov cx,2000
-
- sub1s:
- mov byte ptr es:[bx],' '
- add bx,2
- loop sub1s
- pop es
- pop cx
- pop bx
- ret ;sub1 ends
- ;功能子程序2:设置前景色
- sub2:
- push bx
- push cx
- push es
- mov bx,0b800h
- mov es,bx
- mov bx,1
- mov cx,2000
-
- sub2s:
- and byte ptr es:[bx],11111000b
- or es:[bx],al
- add bx,2
- loop sub2s
- pop es
- pop cx
- pop bx
- ret ;sub2 ends
- ;功能子程序3:设置背景色
- sub3:
- push bx
- push cx
- push es
- mov cl,4
- shl al,cl
- mov bx,0b800h
- mov es,bx
- mov bx,1
- mov cx,2000
-
- sub3s:
- and byte ptr es:[bx],10001111b
- or es:[bx],al
- add bx,2
- loop sub2s
- pop es
- pop cx
- pop bx
- ret ; sub3 ends
- ;功能子程序4:向上滚动一行
- sub4:
- push cx
- push si
- push di
- push es
- push ds
- mov si,0b800h
- mov es,si
- mov ds,si
- mov si,160 ;ds:si指向第n+1行
- mov di,0 ;es:di指向第n行
- cld
- mov cx,24;共复制24行
- sub4s:
- push cx
- mov cx,160
- rep movsb ;复制
- pop cx
- loop sub4s
- mov cx,80
- mov si,0
-
- sub4s1:
- mov byte ptr es:[160*24+si],' ' ;最后一行清空
- add si,2
- loop sub4s1
- pop ds
- pop es
- pop di
- pop si
- pop cx
- ret ;sub4 ends
复制代码
在这里我们显然看到直接地址表的优势,如果想要加入一个新的子程序,只需要把它加入表中即可 |
评分
-
查看全部评分
|