《IBM-PC彙編語言程序設計》(第2版)【沈美明 溫冬嬋】——第五章——自編解析與答案

5.1 試編寫一個彙編語言程序,要求對鍵盤輸入的小寫字母用大寫字母顯示出來。
答:程序段如下:
BEGIN: MOV AH, 1 ;從鍵盤輸入一個字符的DOS調用
INT 21H
CMP AL, ‘a’ ;輸入字符<‘a’嗎?
JB STOP
CMP AL, ‘z’ ;輸入字符>‘z’嗎?
JA STOP
SUB AL, 20H ;轉換爲大寫字母,用AND AL, 1101 1111B也可

MOV DL, AL ;顯示一個字符的DOS調用
MOV AH, 2
INT 21H
JMP BEGIN
STOP: RET
5.2 編寫程序,從鍵盤接收一個小寫字母,然後找出它的前導字符和後續字符,再按順序顯示這三個字
符。
答:程序段如下:
BEGIN: MOV AH, 1 ;從鍵盤輸入一個字符的DOS調用
INT 21H
CMP AL, ‘a’ ;輸入字符<‘a’嗎?
JB STOP
CMP AL, ‘z’ ;輸入字符>‘z’嗎?
JA STOP
DEC AL ;得到前導字符
MOV DL, AL ;準備顯示三個字符
MOV CX, 3
DISPLAY: MOV AH, 2 ;顯示一個字符的DOS調用
INT 21H
INC DL
LOOP DISPLAY
STOP: RET
5.3 將AX寄存器中的16位數分成4組,每組4位,然後把這四組數分別放在AL、BL、CL和DL中。
答:程序段如下:
DSEG SEGMENT
STORE DB 4 DUP (?)
DSEG ENDS

BEGIN: MOV CL, 4 ;右移四次

MOV CH, 4 ;循環四次
LEA BX, STORE
A10: MOV DX, AX
AND DX, 0FH ;取AX的低四位
MOV [BX], DL ;低四位存入STORE中
INC BX
SHR AX, CL ;右移四次
DEC CH
JNZ A10 ;循環四次完了碼?
B10: MOV DL, STORE ;四組數分別放在AL、BL、CL和DL中
MOV CL, STORE+1
MOV BL, STORE+2
MOV AL, STORE+3
STOP: RET
5.4 試編寫一程序,要求比較兩個字符串STRING1和STRING2所含字符是否完全相同,若相同則顯
示‘MATCH’, 若不相同則顯示‘NO MATCH’。
答:程序如下:
DSEG SEGMENT
STRING1 DB ‘I am a student.’
STRING2 DB ‘I am a student!’
YES DB ‘MATCH’, 0DH, 0AH, ‘$’
NO DB ‘NO MATCH’, 0DH, 0AH, ‘$’
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG, ES: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX

PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
MOV ES, AX ;給ES賦值

BEGIN: LEA SI, STRING1 ;設置串比較指令的初值
LEA DI, STRING2
CLD
MOV CX, STRING2 - STRING1
REPE CMPSB ;串比較
JNE DISPNO
LEA DX, YES ;顯示MATCH
JMP DISPLAY
DISPNO: LEA DX, NO ;顯示NO MATCH
DISPLAY: MOV AH, 9 ;顯示一個字符串的DOS調用
INT 21H
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.5 試編寫一程序,要求能從鍵盤接收一個個位數N,然後響鈴N次(響鈴的ASCII碼爲07)。
答:程序段如下:
BEGIN: MOV AH, 1 ;從鍵盤輸入一個字符的DOS調用
INT 21H
SUB AL, ‘0’
JB STOP ;輸入字符<‘0’嗎?
CMP AL, 9 ;輸入字符>‘9’嗎?
JA STOP

CBW
MOV CX, AX ;響鈴次數N
JCXZ STOP
BELL: MOV DL, 07H ;準備響鈴
MOV AH, 2 ;顯示一個字符的DOS調用,實際爲響鈴
INT 21H
CALL DELAY100ms ;延時100ms
LOOP BELL
STOP: RET
5.6 編寫程序,將一個包含有20個數據的數組M分成兩個數組:正數數組P和負數數組N,並分別把這兩個
數組中數據的個數顯示出來。
答:程序如下:
DSEG SEGMENT
COUNT EQU 20
ARRAY DW 20 DUP (?) ;存放數組
COUNT1 DB 0 ;存放正數的個數
ARRAY1 DW 20 DUP (?) ;存放正數
COUNT2 DB 0 ;存放負數的個數
ARRAY2 DW 20 DUP (?) ;存放負數
ZHEN DB 0DH, 0AH, ‘The positive number is:’, ‘$’ ;正數的個數是:
FU DB 0DH, 0AH, ‘The negative number is:’, ‘$’ ;負數的個數是:
CRLF DB 0DH, 0AH, ‘$’
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX

PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV CX, COUNT
LEA BX, ARRAY
LEA SI, ARRAY1
LEA DI, ARRAY2
BEGIN1: MOV AX, [BX]
CMP AX, 0 ;是負數碼?
JS FUSHU
MOV [SI], AX ;是正數,存入正數數組
INC COUNT1 ;正數個數+1
ADD SI, 2
JMP SHORT NEXT
FUSHU: MOV [DI], AX ;是負數,存入負數數組
INC COUNT2 ;負數個數+1
ADD DI, 2
NEXT: ADD BX, 2
LOOP BEGIN1
LEA DX, ZHEN ;顯示正數個數
MOV AL, COUNT1
CALL DISPLAY ;調顯示子程序
LEA DX, FU ;顯示負數個數
MOV AL, COUNT2
CALL DISPLAY ;調顯示子程序
RET
MAIN ENDP
;--------------------------------------------------------------------------

DISPLAY PROC NEAR ;顯示子程序
MOV AH, 9 ;顯示一個字符串的DOS調用
INT 21H
AAM ;將(AL)中的二進制數轉換爲二個非壓縮BCD碼
ADD AH, ‘0’ ;變爲0~9的ASCII碼
MOV DL, AH
MOV AH, 2 ;顯示一個字符的DOS調用
INT 21H
ADD AL, ‘0’ ;變爲0~9的ASCII碼
MOV DL, AL
MOV AH, 2 ;顯示一個字符的DOS調用
INT 21H
LEA DX, CRLF ;顯示回車換行
MOV AH, 9 ;顯示一個字符串的DOS調用
INT 21H
RET
DISPLAY ENDP ;顯示子程序結束
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.7 試編寫一個彙編語言程序,求出首地址爲DATA的100D字數組中的最小偶數,並把它存放在AX中。
答:程序段如下:
BEGIN: MOV BX, 0
MOV CX, 100
COMPARE: MOV AX, DATA[BX] ;取數組的第一個偶數
ADD BX, 2
TEST AX, 01H ;是偶數嗎?
LOOPNZ COMPARE ;不是,比較下一個數
JNZ STOP ;沒有偶數,退出

JCXZ STOP ;最後一個數是偶數,即爲最小偶數,退出
COMPARE1: MOV DX, DATA[BX] ;取數組的下一個偶數
ADD BX, 2
TEST DX, 01H ;是偶數嗎?
JNZ NEXT ;不是,比較下一個數
CMP AX, DX ;(AX)<(DX)嗎?
JLE NEXT
MOV AX, DX ;(AX)<(DX),則置換(AX)爲最小偶數
NEXT: LOOP COMPARE1
STOP: RET
5.8 把AX中存放的16位二進制數K看作是8個二進制的“四分之一字節”。試編寫程序要求數一下值爲3(即
11B)的四分之一字節數,並將該數(即11B的個數)在終端上顯示出來。
答:程序段如下:
BEGIN: MOV DL, 0 ;計數初始值
MOV CX, 8
COMPARE: TEST AX, 03H ;是數03嗎?
JNZ NOEQUAL ;不是,轉走
INC DL ;是,計數
NOEQUAL: ROR AX, 1 ;準備判斷下一個數
ROR AX, 1
LOOP COMPARE
ADD DL, ‘0’ ;將計數值轉換爲ASCII碼
MOV AH, 2 ;進行顯示
INT 21H
STOP: RET
5.9 試編寫一個彙編語言程序,要求從鍵盤接收一個四位的16進制數,並在終端上顯示與它等值的二進制
數。
答:程序段如下:
BEGIN: MOV BX, 0 ;用於存放四位的16進制數

MOV CH, 4
MOV CL, 4
INPUT: SHL BX, CL ;將前面輸入的數左移4位
MOV AH, 1 ;從鍵盤取數
INT 21H
CMP AL, 30H ;<0嗎?
JB INPUT ;不是‘0~F’的數重新輸入
CMP AL, 39H ;是‘0~9’嗎?
JA AF ;不是,轉‘A~F’的處理
AND AL, 0FH ;轉換爲:0000B~1001B
JMP BINARY
AF: AND AL, 1101 1111B ;轉換爲大寫字母
CMP AL, 41H ;又<A嗎?
JB INPUT ;不是‘A~F’的數重新輸入
CMP AL, 46H ;>F嗎?
JA INPUT ;不是‘A~F’的數重新輸入
AND AL, 0FH ;轉換爲:1010B~1111B
ADD AL, 9
BINARY: OR BL, AL ;將鍵盤輸入的數進行組合
DEL CH
JNZ INPUT
DISPN: MOV CX, 16 ;將16位二進制數一位位地轉換成ASCII碼顯示
DISP: MOV DL, 0
ROL BX, 1
RCL DL, 1
OR DL, 30H
MOV AH, 2 ;進行顯示
INT 21H
LOOP DISP

STOP: RET
5.10 設有一段英文,其字符變量名爲ENG,並以$字符結束。試編寫一程序,查對單詞SUN在該文中的出現
次數,並以格式“SUN:xxxx”顯示出次數。
答:程序如下:
DSEG SEGMENT
ENG DB ‘Here is sun, sun ,.,$’
DISP DB ‘SUN:’
DAT DB ‘0000’ , 0DH, 0AH, ‘$’
KEYWORD DB ‘sun’
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG, ES: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
MOV ES, AX ;給ES賦值
BEGIN: MOV AX, 0
MOV DX, DISP-ENG-2 ;計算ENG的長度(每次比較sun,因此比較次數-2)
LEA BX, ENG
COMP: MOV DI, BX
LEA SI, KEYWORD
MOV CX, 3
REPE CMPSB ;串比較
JNZ NOMATCH
INC AX ;是,SUN的個數加1

ADD BX, 2
NOMATCH: INC BX ;指向ENG的下一個字母
DEC DX
JNZ COMP
DONE: MOV CH, 4 ;將次數轉換爲16進制數的ASCII碼
MOV CL, 4
LEA BX, DAT ;轉換結果存入DAT單元中
DONE1: ROL AX, CL
MOV DX, AX
AND DL, 0FH ;取一位16進制數
ADD DL, 30H
CMP DL, 39H
JLE STORE
ADD DL, 07H ;是“A~F”所以要加7
STORE: MOV [BX], DL ;轉換結果存入DAT單元中
INC BX
DEC CH
JNZ DONE1
DISPLAY: LEA DX, DISP ;顯示字符串程序(將DISP和DAT一起顯示)
MOV AH, 09H
INT 21H
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.11 從鍵盤輸入一系列以$爲結束符的字符串,然後對其中的非數字字符計數,並顯示出計數結果。
答:程序段如下:
DSEG SEGMENT

BUFF DB 50 DUP (‘ ’)
COUNT DW 0
DSEG ENDS

BEGIN: LEA BX, BUFF
MOV COUNT, 0
INPUT: MOV AH, 01 ;從鍵盤輸入一個字符的功能調用
INT 21H
MOV [BX], AL
INC BX
CMP AL, ‘$’ ;是$結束符嗎?
JNZ INPUT ;不是,繼續輸入
LEA BX, BUFF ;對非數字字符進行計數
NEXT: MOV CL, [BX]
INC BX
CMP CL, ‘$’ ;是$結束符,則轉去顯示
JZ DISP
CMP CL, 30H ;小於0是非數字字符
JB NEXT
CMP CL, 39H ;大於9是非數字字符
JA NEXT
INC COUNT ;個數+1
JMP NEXT
DISP: ┇ ;16進制數顯示程序段(省略)
5.12 有一個首地址爲MEM的100D字數組,試編制程序刪除數組中所有爲0的項,並將後續項向前壓縮,最後
將數組的剩餘部分補上0。
答:程序如下:
DSEG SEGMENT
MEM DW 100 DUP (?)

DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV SI, (100-1)*2 ;(SI)指向MEM的末元素的首地址
MOV BX, -2 ;地址指針的初值
MOV CX, 100
COMP: ADD BX, 2
CMP MEM [BX], 0
JZ CONS
LOOP COMP
JMP FINISH ;比較完了,已無0則結束
CONS: MOV DI, BX
CONS1: CMP DI, SI ;到了最後單元碼?
JAE NOMOV
MOV AX, MEM [DI+2] ;後面的元素向前移位
MOV MEM [DI], AX
ADD DI, 2
JMP CONS1
NOMOV: MOV WORD PTR [SI], 0 ;最後單元補0
LOOP COMP
FINISH: RET

MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.13 在STRING到STRING+99單元中存放着一個字符串,試編制一個程序測試該字符串中是否存在數字,如
有則把CL的第5位置1,否則將該位置0。
答:程序如下:
DSEG SEGMENT
STRING DB 100 DUP (?)
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV SI, 0 ;(SI)作爲地址指針的變化值
MOV CX, 100
REPEAT: MOV AL, STRING [SI]
CMP AL, 30H
JB GO_ON
CMP AL, 39H
JA GO_ON
OR CL, 20H ;存在數字把CL的第5位置1
JMP EXIT

GO_ON: INC SI
LOOP REPEAT
AND CL, 0DFH ;不存在數字把CL的第5位置0
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.14 在首地址爲TABLE的數組中按遞增次序存放着100H個16位補碼數,試編寫一個程序把出現次數最多的
數及其出現次數分別存放於AX和CX中。
答:程序如下:
DSEG SEGMENT
TABLE DW 100H DUP (?) ;數組中的數據是按增序排列的
DATA DW ?
COUNT DW 0
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV CX, 100H ;循環計數器
MOV SI, 0
NEXT: MOV DX, 0

MOV AX, TABLE [SI]
COMP: CMP TABLE [SI], AX ;計算一個數的出現次數
JNE ADDR
INC DX
ADD SI, 2
LOOP COMP
ADDR: CMP DX, COUNT ;此數出現的次數最多嗎?
JLE DONE
MOV COUNT, DX ;目前此數出現的次數最多,記下次數
MOV DATA, AX ;記下此數
DONE: LOOP NEXT ;準備取下一個數
MOV CX, COUNT ;出現最多的次數存入(CX)
MOV AX, DATA ;出現最多的數存入(AX)
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.15 數據段中已定義了一個有n個字數據的數組M,試編寫一程序求出M中絕對值最大的數,把它放在數據
段的M+2n單元中,並將該數的偏移地址存放在M+2(n+1)單元中。
答:程序如下:
DSEG SEGMENT
n EQU 100H ;假設n=100H
M DW n DUP (?)
DATA DW ? ;M+2n單元
ADDR DW ? ;M+2(n+1)單元
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT

MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV CX, n ;循環計數器
LEA DI, M
MOV AX, [DI] ;取第一個數
MOV ADDR, DI ;記下絕對值最大的數的地址
CMP AX, 0 ;此數是正數嗎?
JNS ZHEN ;是正數,即爲絕對值,轉去判斷下一個數
NEG AX ;不是正數,變爲其絕對值
ZHEN: MOV BX, [DI]
CMP BX, 0 ;此數是正數嗎?
JNS COMP ;是正數,即爲絕對值,轉去比較絕對值大小
NEG BX ;不是正數,變爲其絕對值
COMP: CMP AX, BX ;判斷絕對值大小
JAE ADDRESS
MOV AX, BX ;(AX)<(BX),使(AX)中爲絕對值最大的數
MOV ADDR, DI ;記下絕對值最大的數的地址
ADDRESS: ADD DI, 2
LOOP ZHEN
MOV DATA, AX ;記下此數
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段

;--------------------------------------------------------------------------
END START
5.16 在首地址爲DATA的字數組中存放着100H個16位補碼數,試編寫一個程序求出它們的平均值放在AX寄存
器中;並求出數組中有多少個數小於此平均值,將結果放在BX寄存器中。
答:程序如下:
DSEG SEGMENT
DATA DW 100H DUP (?)
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV CX, 100H ;循環計數器
MOV SI, 0
MOV BX, 0 ;和((DI),(BX))的初始值
MOV DI, 0
NEXT: MOV AX, DATA [SI]
CWD
ADD BX, AX ;求和
ADC DI, DX ;加上進位位
ADD SI, 2
LOOP NEXT
MOV DX, DI ;將((DI),(BX))中的累加和放入((DX),(AX))中

MOV AX, BX
MOV CX, 100H
IDIV CX ;帶符號數求平均值,放入(AX)中
MOV BX, 0
MOV SI, 0
COMP: CMP AX, DATA [SI] ;尋找小於平均值的數
JLE NO
INC BX ;小於平均值數的個數+1
NO: ADD SI, 2
LOOP COMP
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.17 試編制一個程序把AX中的16進制數轉換爲ASCII碼,並將對應的ASCII碼依次存放到MEM數組中的四個
字節中。例如,當(AX)=2A49H時,程序執行完後,MEM中的4個字節內容爲39H,34H,41H,32H。
答:程序如下:
DSEG SEGMENT
MEM DB 4 DUP (?)
N DW 2A49H
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX

MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV CH, 4 ;循環計數器
MOV CL, 4
MOV AX, N
LEA BX, MEM
ROTATE: MOV DL, AL ;從最低四位開始轉換爲ASCII碼
AND DL, 0FH
ADD DL, 30H
CMP DL, 3AH ;是0~9嗎?
JL NEXT
ADD DL, 07H ;是A~F
NEXT: MOV [BX], DL ;轉換的ASCII碼送入MEM中
INC BX
ROR AX, CL ;準備轉換下一位
DEC CH
JNZ ROTATE
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.18 把0~100D之間的30個數存入以GRADE爲首地址的30字數組中,GRADE+i表示學號爲i+1的學生的成績。
另一個數組RANK爲30個學生的名次表,其中RANK+i的內容是學號爲i+1的學生的名次。編寫一程序,根據GRADE
中的學生成績,將學生名次填入RANK數組中。(提示:一個學生的名次等於成績高於這個學生的人數加1。)
答:程序如下:
DSEG SEGMENT
GRADE DW 30 DUP (?) ;假設已預先存好30名學生的成績

RANK DW 30 DUP (?)
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV DI, 0
MOV CX, 30 ;外循環計數器
LOOP1: PUSH CX
MOV CX, 30 ;內循環計數器
MOV SI, 0
MOV AX, GRADE [DI]
MOV DX, 1 ;起始名次爲第1名
LOOP2: CMP GRADE [SI], AX ;成績比較
JBE GO_ON
INC DX ;名次+1
GO_ON: ADD SI, 2
LOOP LOOP2
POP CX
MOV RNAK [DI], DX ;名次存入RANK數組
ADD DI, 2
LOOP LOOP1
RET

MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.19 已知數組A包含15個互不相等的整數,數組B包含20個互不相等的整數。試編制一程序把既在A中又在B
中出現的整數存放於數組C中。
答:程序如下:
DSEG SEGMENT
A DW 15 DUP (?)
B DW 20 DUP (?)
C DW 15 DUP (‘ ’)
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV SI, 0
MOV BX, 0
MOV CX, 15 ;外循環計數器
LOOP1: PUSH CX
MOV CX, 20 ;內循環計數器
MOV DI, 0
MOV AX, A [SI] ;取A數組中的一個數

LOOP2: CMP B [DI], AX ;和B數組中的數相等嗎?
JNE NO
MOV C [BX], AX ;相等存入C數組中
ADD BX, 2
NO: ADD DI, 2
LOOP LOOP2
ADD SI, 2
POP CX
LOOP LOOP1
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.20 設在A、B和C單元中分別存放着三個數。若三個數都不是0,則求出三數之和存放在D單元中;若其中
有一個數爲0,則把其它兩單元也清0。請編寫此程序。
答:程序如下:
DSEG SEGMENT
A DW ?
B DW ?
C DW ?
D DW 0
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX

PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: CMP A, 0
JE NEXT
CMP B, 0
JE NEXT
CMP C, 0
JE NEXT
MOV AX, A
ADD AX, B
ADD AX, C
MOV D, AX
JMP SHORT EXIT
NEXT: MOV A, 0
MOV B, 0
MOV C, 0
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.21 試編寫一程序,要求比較數組ARRAY中的三個16位補碼數,並根據比較結果在終端上顯示如下信息:
(1) 如果三個數都不相等則顯示0;
(2) 如果三個數有二個數相等則顯示1;
(3) 如果三個數都相等則顯示2。
答:程序如下:
DSEG SEGMENT

ARRAY DW 3 DUP (?)
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: LEA SI, ARRAY
MOV DX, 0 ;(DX)用於存放所求的結果
MOV AX, [SI]
MOV BX, [SI+2]
CMP AX, BX ;比較第一和第二兩個數是否相等
JNE NEXT1
INC DX
NEXT1: CMP [SI+4], AX ;比較第一和第三兩個數是否相等
JNE NEXT2
INC DX
NEXT2: CMP [SI+4], BX ;比較第二和第三兩個數是否相等
JNE NUM
INC DX
NUM: CMP DX, 3
JL DISP
DEC DX
DISP: ADD DL, 30H ;轉換爲ASCII碼

MOV AH, 2 ;顯示一個字符
INT 21H
RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.22 從鍵盤輸入一系列字符(以回車符結束),並按字母、數字、及其它字符分類計數,最後顯示出這三類
的計數結果。
答:程序如下:
DSEG SEGMENT
ALPHABET DB ‘輸入的字母字符個數爲:’, ‘$’
NUMBER DB ‘輸入的數字字符個數爲:’, ‘$’
OTHER DB ‘輸入的其它字符個數爲:’, ‘$’
CRLF DB 0DH, 0AH, ‘$’
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV BX, 0 ;字母字符計數器
MOV SI, 0 ;數字字符計數器
MOV DI, 0 ;其它字符計數器

INPUT: MOV AH, 1 ;輸入一個字符
INT 21H
CMP AL, 0DH ;是回車符嗎?
JE DISP
CMP AL, 30H ;<數字0嗎?
JAE NEXT1
OTHER: INC DI ;是其它字符
JMP SHORT INPUT
NEXT1: CMP AL, 39H ;>數字9嗎?
JA NEXT2
INC SI ;是數字字符
JMP SHORT INPUT
NEXT2: CMP AL, 41H ;<字母A嗎?
JAE NEXT3
JMP SHORT OTHER ;是其它字符
NEXT3: CMP AL, 5AH ;>字母Z嗎?
JA NEXT4
INC BX ;是字母字符A~Z
JMP SHORT INPUT
NEXT4: CMP AL, 61H ;<字母a嗎?
JAE NEXT5
JMP SHORT OTHER ;是其它字符
NEXT5: CMP AL, 7AH ;>字母z嗎?
JA SHORT OTHER ;是其它字符
INC BX ;是字母字符a~z
JMP SHORT INPUT
DISP: LEA DX, ALPHABET
CALL DISPLAY

LEA DX, NUMBER
MOV BX, SI
CALL DISPLAY
LEA DX, OTHER
MOV BX, DI
CALL DISPLAY
RET
MAIN ENDP
;--------------------------------------------------------------------------
DISPLAY PROC NEAR
MOV AH, 09H ;顯示字符串功能調用
INT 21H
CALL BINIHEX ;調把BX中二進制數轉換爲16進制顯示子程序
LEA DX, CRLF
MOV AH, 09H ;顯示回車換行
INT 21H
RET
DISPLAY ENDP
;--------------------------------------------------------------------------
BINIHEX PROC NEAR ;將BX中二進制數轉換爲16進制數顯示子程序
MOV CH, 4
ROTATE: MOV CL, 4
ROL BX, CL
MOV DL, BL
AND DL, 0FH
ADD DL, 30H
CMP DL, 3AH ;是A~F嗎?
JL PRINT_IT
ADD DL, 07H

PRINT_IT: MOV AH, 02H ;顯示一個字符
INT 21H
DEC CH
JNZ ROTATE
RET
BINIHEX ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.23 已定義了兩個整數變量A和B,試編寫程序完成下列功能:
(1) 若兩個數中有一個是奇數,則將奇數存入A中,偶數存入B中;
(2) 若兩個數中均爲奇數,則將兩數加1後存回原變量;
(3) 若兩個數中均爲偶數,則兩個變量均不改變。
答:程序如下:
DSEG SEGMENT
A DW ?
B DW ?
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV AX, A

MOV BX, B
XOR AX, BX
TEST AX, 0001H ;A和B同爲奇數或偶數嗎?
JZ CLASS ;A和B都爲奇數或偶數,轉走
TEST BX, 0001H
JZ EXIT ;B爲偶數,轉走
XCHG BX, A ;A爲偶數,將奇數存入A中
MOV B, BX ;將偶數存入B中
JMP EXIT
CLASS: TEST BX, 0001H ;A和B都爲奇數嗎?
JZ EXIT ;A和B同爲偶數,轉走
INC B
INC A
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.24 假設已編制好5個歌曲程序,它們的段地址和偏移地址存放在數據段的跳躍表SINGLIST中。試編制一
程序,根據從鍵盤輸入的歌曲編號1~5,轉去執行五個歌曲程序中的某一個。
答:程序如下:
DSEG SEGMENT
SINGLIST DD SING1
DD SING2
DD SING3
DD SING4
DD SING5
ERRMSG DB ‘Error! Invalid parameter!’, 0DH, 0AH, ‘$’
DSEG ENDS

;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOV AH, 1 ;從鍵盤輸入的歌曲編號1~5
INT 21H
CMP AL, 0DH
JZ EXIT ;是回車符,則結束
SUB AL, ‘1’ ;是1~5嗎?
JB ERROR ;小於1,錯誤
CMP AL, 4
JA ERROR ;大於5,錯誤
MOV BX, OFFSET SINGLIST
MUL AX, 4 ;(AX)=(AL)*4,每個歌曲程序的首地址佔4個字節
ADD BX, AX
JMP DWORD PTR[BX] ;轉去執行歌曲程序
ERROR: MOV DX, OFFSET ERRMSG
MOV AH, 09H
INT 21H ;顯示錯誤信息
JMP BEGIN
SING1: ┇
JMP BEGIN
SING2: ┇

JMP BEGIN
SING3: ┇
JMP BEGIN
SING4: ┇
JMP BEGIN
SING5: ┇
JMP BEGIN
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
5.25 試用8086的乘法指令編制一個32位數和16位數相乘的程序;再用80386的乘法指令編制一個32位數和
16位數相乘的程序,並定性比較兩個程序的效率。
答:8086的程序如下(假設爲無符號數):
DSEG SEGMENT
MUL1 DD ? ;32位被乘數
MUL2 DW ? ;16位乘數
MUL0 DW 0,0 ,0 ,0 ;乘積用64位單元存放
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX
MOV AX, DSEG
MOV DS, AX ;給DS賦值

BEGIN: MOV BX, MUL2 ;取乘數
MOV AX, WORD PTR MUL1 ;取被乘數低位字
MUL BX
MOV MUL0, AX ;保存部分積低位
MOV MUL0+2, DX ;保存部分積高位
MOV AX, WORD PTR[MUL1+2] ;取被乘數高位字
MUL BX
ADD MUL0+2, AX ;部分積低位和原部分積高位相加
ADC MUL0+4, DX ;保存部分積最高位,並加上進位
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
80386的程序如下(假設爲無符號數):
.386
DSEG SEGMENT
MUL1 DD ? ;32位被乘數
MUL2 DW ? ;16位乘數
MUL0 DD 0,0 ;乘積用64位單元存放
DSEG ENDS
;--------------------------------------------------------------------------
CSEG SEGMENT
MAIN PROC FAR
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;設置返回DOS
SUB AX, AX
PUSH AX

MOV AX, DSEG
MOV DS, AX ;給DS賦值
BEGIN: MOVZX EBX, MUL2 ;取乘數,並0擴展成32位
MOV EAX, MUL1 ;取被乘數
MUL EBX
MOV DWORD PTR MUL0, EAX ;保存積的低位雙字
MOV DWORD PTR[MUL0+4], EDX ;保存積的高位雙字
EXIT: RET
MAIN ENDP
CSEG ENDS ;以上定義代碼段
;--------------------------------------------------------------------------
END START
80386作32位乘法運算用一條指令即可完成,而8086則需用部分積作兩次完成。
5.26 如數據段中在首地址爲MESS1的數據區內存放着一個長度爲35的字符串,要求把它們傳送到附加段中
的緩衝區MESS2中去。爲提高程序執行效率,希望主要採用MOVSD指令來實現。試編寫這一程序。
答:80386的程序如下:
.386
.MODEL SMALL
.STACK 100H
.DATA
MESS1 DB ‘123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ’,? ;長度爲35的字符串
.FARDATA
MESS2 DB 36 DUP (?)
.CODE
START: MOV AX, @DATA
MOV DS, AX ;給DS賦值
MOV AX, @FARDATA
MOV ES, AX ;給ES賦值

ASSUME ES:@FARDATA
BEGIN: LEA ESI, MESS1
LEA EDI, MESS2
CLD
MOV ECX, (35+1)/4 ;取傳送的次數
REP MOVSD
;--------------------------------------------------------------------------
MOV AX, 4C00H ;返回DOS
INT 21H
END START
5.27 試用比例變址尋址方式編寫一386程序,要求把兩個64位整數相加並保存結果。
答:80386的程序如下:
.386
.MODEL SMALL
.STACK 100H
.DATA
DATA1 DQ ?
DATA2 DQ ?
.CODE
START: MOV AX, @DATA
MOV DS, AX ;給DS賦值
BEGIN: MOV ESI, 0
MOV EAX, DWORD PTR DATA2[ESI*4]
ADD DWORD PTR DATA1[ESI*4], EAX
INC ESI
MOV EAX, DWORD PTR DATA2[ESI*4]
ADC DWORD PTR DATA1[ESI*4], EAX

;--------------------------------------------------------------------------
MOV AX, 4C00H ;返回DOS
INT 21H
END START

 

參考文章

http://blog.sina.com.cn/s/blog_77f58b350100q4dv.html

https://wenku.baidu.com/view/303e0e114431b90d6c85c720.html

https://shentuzhigang.blog.csdn.net/article/details/106560578

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章