?? 匯編.txt
字號:
PUSH CX
REP MOVSB
POP CX
SUB DX,CX
為什么不干脆些?
SUB DX,CX
REP MOVSB
6,有段程序,很有規(guī)律,但卻極無效率:
X1:
TEST AH,1
JZ X2
MOV BUF1,BL
X2:
TEST AH,2
JZ X3
MOV BUF2,DX ; 凡雙數(shù)用DX,單數(shù)用BL
X3:
TEST AH,4
JZ X4
MOV BUF3,BL
X4:
.. ; 以下各段與上述程序相似
X8:
..
這種金玉其表的程序,最沒有實用價值,改的方法應(yīng)由緩沖器著手,先安排成
序列,由小而大如:
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,回路最怕千回百轉(zhuǎn),不暢不順,如:
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,當處理字碼時,需要字母的序數(shù),有這樣的寫法:
CMP AL,60H
JA ABCD1
SUB AL,40H ; 大寫字母
ABCD:
..
ABCD1:
SUB AL,60H ; 小寫字母
JMP ABCD
要知道字母碼的特色在于大寫為 40H 至4AH,小寫為60H 至6AH ,以上程序,
其實只要一個指令就可以了:
AND AL,1FH
簡單明了!
9,大多數(shù)的程序在程序員自己測試下很少發(fā)生錯誤,而一旦換一另個人執(zhí),就會發(fā)現(xiàn)
錯誤百出。
其原因在于寫程序者已經(jīng)假定了正確的情況,當然不會以明知為錯誤的方式操
作。可是換了一個人,沒有先入為主的成見,很可能輸入了「不正確」的數(shù)據(jù),結(jié)果是
問題叢生。
要知道真正的使用者,絕非設(shè)計者本人,在操作過程中,按鍵錯誤在所難免。
這種錯誤應(yīng)該在程序中事先加以檢查,凡是輸入數(shù)據(jù)有「正確、錯誤」之別者,錯誤性
數(shù)據(jù)一定要事先加以排除。
這樣做看起來似乎程序不夠精簡,可是正確的重要性遠在精簡之上。一旦發(fā)生
了錯誤,再精簡的程序也沒有使 用價值。
此外,在程序中常有加、減的運算,這時也應(yīng)該作正確性檢查,否則會發(fā)生上
述同樣的問題。
三、指令應(yīng)用要靈活
有一段很簡單的程序,其寫作的方法甚多,但是指令應(yīng)用的良窳,會使得程序的效
率相去天上地下,難以估計。
這段程序的用途,是要將一段數(shù)據(jù)中,英文字符大、小寫相互轉(zhuǎn)換。當然,轉(zhuǎn)換的
選擇要由使用者決定,在下面程序且略去使用界面,假設(shè)已得知轉(zhuǎn)換的方式。
設(shè)數(shù)據(jù)在 DS:SI中,數(shù)據(jù)長度=CX ,大寫轉(zhuǎn)小寫時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的程序?qū)懙锰L,共 25B,有共享的價值,于是作為子程
序調(diào)用。
試想一下,每一筆數(shù)據(jù),都要調(diào)用一次,浪費四個字符事小,但每次要費 23+20個
時鐘脈沖,數(shù)據(jù)多時,不啻為天文數(shù)字。更何況這段程序?qū)懙脴O差,在回路中,又多浪
費了幾十個時鐘。關(guān)于這一點,下面會繼續(xù)討論。
照上面這段程序,略加改進,寫法如下:
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
這樣的寫法還是不佳,因為在回路中,用常數(shù)與寄存器比較,速度較寄存器相比為
慢。應(yīng)該先將需要比較的值,放在暫存器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
以上這段程序,空間小,速度快,每筆數(shù)據(jù),平均僅需不到40個時鐘值,以10 MHZ
計,十萬筆數(shù)據(jù),約需半秒鐘!
請注意程序中所用的技巧,由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:
這種分支也可以由另一種技巧所取代,即預(yù)設(shè)法。事先將所需用的參數(shù)放在固定的
緩沖區(qū)中,此時取用即可:
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
以上介紹為變量法技巧,即將所要比較的值,放在寄存器中。由于寄存器快速、節(jié)
省空間,因此程序效率高。更重要的一點,是程序本身的彈性大,只要應(yīng)用方式統(tǒng)一,
事先把參數(shù)設(shè)妥,即可共享。
四、回路中的指令
回路最重要的是速度,因為本段程序,將在計數(shù)器的范圍之內(nèi),連續(xù)執(zhí)行下去。如
果不小心浪費了幾個時鐘值,在回路的累積下,很可能使程序成為牛步。
要想把回路寫好,一定要記清楚每個指令的執(zhí)行時鐘,以便選擇效率最高者。同時,
要知道哪些指令可以獲得相同的處理效果,才能有更多的選擇。
其次,在回路中,最忌諱用緩沖器,不僅占用空間大,處理速度慢,而且不能靈活
運用,功能有限。另外也應(yīng)極力避免常數(shù),盡量設(shè)法經(jīng)由寄存器執(zhí)行,用得巧妙時,常
會將整個程序的效率提高百十倍。
還有便是少用 PUSH,POP,DIV,MUL和 CALL 等浪費時鐘的指令。除此之外,小心、
謹慎,深思、熟慮,才是把回路寫好的不二法門。
在前例中,把比較常數(shù)的指令換為比較暫存器,便是很好的證明。如果用常數(shù),兩
段程序決不可能共享,時、空都無謂地浪費了。
以下再舉數(shù)例,乍看這似乎有些吹毛求疵,但是仔細計算一下所浪費的時間,可能
就笑不出聲了。
茲假定以下回路需處理五萬字符的數(shù)據(jù),頻率為 10MHZ,其情況為:
1: LOOP1:
2: LODSB
3: XOR AL,[DI]
4: STOSB
5: LOOP LOOP1
本程序計數(shù)器等于50,000,每次需
12T+14T+11T+17T=55T 個時鐘脈沖
若以50,000次計,需時 47*50,000/10,000,000 秒,即約四分之一秒。
只要稍稍將指令調(diào)整一下,為:
1: LOOP1:
2: LODSW
3: XOR AX,[DI]
4: STOSW
5: LOOP LOOP1
這樣計數(shù)器只要25,000次,每次
16T+18T+15T+17T=66T
則25,000次需時 66*25,000/10,000,000 秒,約六分之一秒,比前面的程序快了二
分之一。
同理,在回路中加回路,而每個回路需 17T,也是很大的浪費。倘若加調(diào)用 CALL
指令,則需 23T+20T=43T,浪費得更多,讀者不可不慎。
當某一段程序用得很頻繁時,理應(yīng)視作子程序,例如下面的 LODAX:
1: LOOP1:
2: CALL LODAX
3: LOOP LOOP1
4: RET
5: LODAX:
6: LODSW
7: XOR AX,[DI]
8: STOSW
9: RET
其實這是貪小失大,僅四個字符的程序,竟用三個字符的調(diào)用指令去交換,是絕對
得不償失的。
再如同下面的程序,頗有值得商榷之處。
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。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -