📄 汇编.txt
字号:
PUSH CX
REP MOVSB
POP CX
SUB DX,CX
为什么不干脆些?
SUB DX,CX
REP MOVSB
6,有段程序,很有规律,但却极无效率:
X1:
TEST AH,1
JZ X2
MOV BUF1,BL
X2:
TEST AH,2
JZ X3
MOV BUF2,DX ; 凡双数用DX,单数用BL
X3:
TEST AH,4
JZ X4
MOV BUF3,BL
X4:
.. ; 以下各段与上述程序相似
X8:
..
这种金玉其表的程序,最没有实用价值,改的方法应由缓冲器着手,先安排成
序列,由小而大如:
BUF1 DB ?
BUF2 DW ?
BUF3 DB ?
BUF4 DW ?
..
然后,程序改为:
MOV DI,OFFSET BUF1 ; 第一个缓冲器
MOV AL,BL
MOV CX,4
X1:
SHR AH,1
JZ X2
STOSB
X2:
SHR AH,1
JZ X3
MOV [DI],DX
INC DI
INC DI
X3:
LOOP X1
7,回路最怕千回百转,不畅不顺,如:
SUB AH,AH
ABCD:
CMP AL,BL
JB ABCD1
SUB AL,BL
INC AH
JMP ABCD
ABCD1:
..
以上 ABCD1这个入口是多余的,下面就好得多:
MOV AH,-1
ABCD:
INC AH
SUB AL,BL
JA ABCD
ADD AL,BL ; 还原
..
8,当处理字码时,需要字母的序数,有这样的写法:
CMP AL,60H
JA ABCD1
SUB AL,40H ; 大写字母
ABCD:
..
ABCD1:
SUB AL,60H ; 小写字母
JMP ABCD
要知道字母码的特色在于大写为 40H 至4AH,小写为60H 至6AH ,以上程序,
其实只要一个指令就可以了:
AND AL,1FH
简单明了!
9,大多数的程序在程序员自己测试下很少发生错误,而一旦换一另个人执,就会发现
错误百出。
其原因在于写程序者已经假定了正确的情况,当然不会以明知为错误的方式操
作。可是换了一个人,没有先入为主的成见,很可能输入了「不正确」的数据,结果是
问题丛生。
要知道真正的使用者,绝非设计者本人,在操作过程中,按键错误在所难免。
这种错误应该在程序中事先加以检查,凡是输入数据有「正确、错误」之别者,错误性
数据一定要事先加以排除。
这样做看起来似乎程序不够精简,可是正确的重要性远在精简之上。一旦发生
了错误,再精简的程序也没有使 用价值。
此外,在程序中常有加、减的运算,这时也应该作正确性检查,否则会发生上
述同样的问题。
三、指令应用要灵活
有一段很简单的程序,其写作的方法甚多,但是指令应用的良窳,会使得程序的效
率相去天上地下,难以估计。
这段程序的用途,是要将一段数据中,英文字符大、小写相互转换。当然,转换的
选择要由使用者决定,在下面程序且略去使用界面,假设已得知转换的方式。
设数据在 DS:SI中,数据长度=CX ,大写转小写时BL=0,反之,则BL=1。
我见过一种写法,简直无法原谅:
1: LOOP1:
2: CALL CHANGE
3: JC LOOP11
4: ADD AL,20H
5: JMP SHORT LOOP12
6: LOOP11:
7: SUB AL,20H
8: LOOP12:
9: MOV [SI-1],AL
10: LOOP LOOP1
11: RET
12: CHANGE:
13: LODSB
14: OR BL,BL
15: JZ CHANGS
16: CMP AL,61H
17: JB CHARET
18: CMP AL,7AH
19: JA CHARET
20: STC
21: CHARET:
22: RET
23: CHANGS:
24: CMP AL,41H
25: JB CHARET
26: CMP AL,5AH
27: JA CHARET
28: CLC
29: RET
这种程序错在把由12到29的程序写得太长,共 25B,有共享的价值,于是作为子程
序调用。
试想一下,每一笔数据,都要调用一次,浪费四个字符事小,但每次要费 23+20个
时钟脉冲,数据多时,不啻为天文数字。更何况这段程序写得极差,在回路中,又多浪
费了几十个时钟。关于这一点,下面会继续讨论。
照上面这段程序,略加改进,写法如下:
1: CHANGE:
2: LODSB
3: OR BL,BL
4: JZ CHANGS
5: CMP AL,61H
6: JB CHARET
7: CMP AL,7AH
8: JA CHARET
9: SUB AL,20H
10: CHANG0:
11: MOV [SI-1],AL
12: CHANG1:
13: LOOP CHANGE
14: RET
15: CHANGS:
16: CMP AL,41H
17: JB CHANG1
18: CMP AL,5AH
19: JA CHANG1
20: ADD AL,20H
21: JMP CHANG1
这样的写法还是不佳,因为在回路中,用常数与寄存器比较,速度较寄存器相比为
慢。应该先将需要比较的值,放在暂存器DH,DL 中,改进如次:
1: MOV AH,20H
2: MOV DX,7A61H
3: OR BL,BL
4: JZ CHANGE
5: MOV DX,5A41H
6: CHANGE:
7: LODSB
8: CMP AL,DL
9: JB CHANG1
10: CMP AL,DH
11: JA CHANG1
12: XOR AL,AH
13: MOV [SI-1],AL
14: CHANG1:
15: LOOP CHANGE
16: RET
以上这段程序,空间小,速度快,每笔数据,平均仅需不到40个时钟值,以10 MHZ
计,十万笔数据,约需半秒钟!
请注意程序中所用的技巧,由2至6的分支法,就比下面这种写法为佳:
1: OR BL,BL
2: JZ CHAN1
3: MOV DX,5A41H
4: JMP SHORT CHANGE
5: CHAN1:
6: MOV DX,7A61H
7: CHANGE:
这种分支也可以由另一种技巧所取代,即预设法。事先将所需用的参数放在固定的
缓冲区中,此时取用即可:
MOV DX,BWCOM ; 比较之默认值
这样程序又简单些了:
1: MOV AH,20H
2: MOV DX,BWCOM
3: CHANGE:
4: LODSB
5: CMP AL,DL
6: JB CHANG1
7: CMP AL,DH
8: JA CHANG1
9: XOR AL,AH
10: MOV [SI-1],AL
11: CHANG1:
12: LOOP CHANGE
13: RET
以上介绍为变量法技巧,即将所要比较的值,放在寄存器中。由于寄存器快速、节
省空间,因此程序效率高。更重要的一点,是程序本身的弹性大,只要应用方式统一,
事先把参数设妥,即可共享。
四、回路中的指令
回路最重要的是速度,因为本段程序,将在计数器的范围之内,连续执行下去。如
果不小心浪费了几个时钟值,在回路的累积下,很可能使程序成为牛步。
要想把回路写好,一定要记清楚每个指令的执行时钟,以便选择效率最高者。同时,
要知道哪些指令可以获得相同的处理效果,才能有更多的选择。
其次,在回路中,最忌讳用缓冲器,不仅占用空间大,处理速度慢,而且不能灵活
运用,功能有限。另外也应极力避免常数,尽量设法经由寄存器执行,用得巧妙时,常
会将整个程序的效率提高百十倍。
还有便是少用 PUSH,POP,DIV,MUL和 CALL 等浪费时钟的指令。除此之外,小心、
谨慎,深思、熟虑,才是把回路写好的不二法门。
在前例中,把比较常数的指令换为比较暂存器,便是很好的证明。如果用常数,两
段程序决不可能共享,时、空都无谓地浪费了。
以下再举数例,乍看这似乎有些吹毛求疵,但是仔细计算一下所浪费的时间,可能
就笑不出声了。
兹假定以下回路需处理五万字符的数据,频率为 10MHZ,其情况为:
1: LOOP1:
2: LODSB
3: XOR AL,[DI]
4: STOSB
5: LOOP LOOP1
本程序计数器等于50,000,每次需
12T+14T+11T+17T=55T 个时钟脉冲
若以50,000次计,需时 47*50,000/10,000,000 秒,即约四分之一秒。
只要稍稍将指令调整一下,为:
1: LOOP1:
2: LODSW
3: XOR AX,[DI]
4: STOSW
5: LOOP LOOP1
这样计数器只要25,000次,每次
16T+18T+15T+17T=66T
则25,000次需时 66*25,000/10,000,000 秒,约六分之一秒,比前面的程序快了二
分之一。
同理,在回路中加回路,而每个回路需 17T,也是很大的浪费。倘若加调用 CALL
指令,则需 23T+20T=43T,浪费得更多,读者不可不慎。
当某一段程序用得很频繁时,理应视作子程序,例如下面的 LODAX:
1: LOOP1:
2: CALL LODAX
3: LOOP LOOP1
4: RET
5: LODAX:
6: LODSW
7: XOR AX,[DI]
8: STOSW
9: RET
其实这是贪小失大,仅四个字符的程序,竟用三个字符的调用指令去交换,是绝对
得不偿失的。
再如同下面的程序,颇有值得商榷之处。
1: LOOP1:
2: MOV DX,NUMBER1
3: MOV CX,NUMBER2
4: LOOP2:
5: PUSH CX
6: MOV CX,DX
7: LOOP3:
8: LODSW
9: XOR AX,[DI]
10: STOSW
11: LOOP LOOP3
12: INC DI
13: INC DI
14: POP CX
15: LOOP LOOP2
16: RET
第二个回路是多余的,这是高级语言常用的观念,对汇编语言完全不适用。
稍加改动,不损上面程序原有的条件,得到:
1: LOOP1:
2: MOV DX,NUMBER1
3: LOOP2:
4: MOV CX,NUMBER2
5: LOOP3:
6: LODSW
7: XOR AX,[DI]
8: STOSW
9: LOOP LOOP3
10: INC DI
11: INC DI
12: DEC DX
13: JNZ LOOP2
14: RET
这样回路少了一个,程序中将5,6,14,15 各条中原来为15T+2T+12T+17T=46T的时间,省
为12,13,14条的2T+16T+17T=35T。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -