Thực hành Assembly - Bài 2: Lệnh so sánh - Lệnh nhảy - Lệnh lặp

Mục đích

 Hiểu cách so sánh hai số trong hợp ngữ

 Hiểu cách thay đổi thứ tự thực hiện các lệnh

 Biết cách sử dụng các lệnh so sánh, nhảy và lặp

 

doc6 trang | Chuyên mục: Vi Xử Lý – Vi Điều Khiển | Chia sẻ: dkS00TYs | Lượt xem: 29162 | Lượt tải: 1download
Tóm tắt nội dung Thực hành Assembly - Bài 2: Lệnh so sánh - Lệnh nhảy - Lệnh lặp, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
Bài thực hành số 2
Lệnh so sánh – Lệnh nhảy – Lệnh lặp
Mục đích
Hiểu cách so sánh hai số trong hợp ngữ
Hiểu cách thay đổi thứ tự thực hiện các lệnh
Biết cách sử dụng các lệnh so sánh, nhảy và lặp 
Tóm tắt lý thuyết
Lệnh so sánh
Trong hợp ngữ, muốn so sánh hai số, ta phải thực hiện một phép toán số học hoặc logic trên hai số đó và căn cứ vào các bit trong thanh ghi cờ rồi đưa ra kết luận. Để làm việc này, có thể dùng lệnh CMP và TEST.
Bản chất của lệnh CMP Des,Src là lệnh SUB Des,Src (thực hiện phép tính Des – Src) nhưng kết quả của phép tính không được lưu vào Des như trong lệnh SUB. 
Ví dụ: so sánh hai số nguyên dương
	MOV	AH,1
	MOV	AL,2
	CMP	AH,AL
Sau khi thực hiện hai lệnh trên, cờ Carry (CF) bật, báo hiệu rằng AH < AL
Bản chất của lệnh TEST Des,Src là lệnh AND Des,Src (thực hiện phép tính Des AND Src) nhưng kết quả của phép tính không được lưu vào Des như trong lệnh AND. 
Ví dụ: kiểm tra hai bit cuối cùng của AL
	TEST	AL,3	; 3h = 11b
Nếu cờ Zero (ZF) bật, có nghĩa là cả hai bit 0 và 1 của AL đều bằng 0.
Lệnh nhảy
Thông thường, khi một lệnh (instruction) được thực hiện, giá trị của thanh ghi IP (instruction pointer) được tự động cập nhật để trỏ đến lệnh kế tiếp. Ngoài ra, nội dung của thanh ghi IP chỉ có thể bị thay đổi thông qua một số lệnh đặc biệt. Đó là: các lệnh nhảy (J*), lệnh lặp (LOOP*), lệnh gọi hàm (call, ret), lệnh gọi ngắt (int, iret). Các lệnh này được xếp vào nhóm “Lệnh điều khiển luồng” (Program flow control instructions). Trong bài thực hành này, chúng ta sẽ học cách sử dụng các lệnh nhảy và các lệnh lặp.
Lệnh nhảy không điều kiện
JMP 
Có các trường hợp sau:
JMP SHORT (short jump). Khi đó trong mã lệnh lưu 1 byte khoảng cách (offset) giữa vị trí hiện tại và vị trí cần nhảy đến. Kiểu này chỉ nhảy trong phạm vi từ –128 đến +127 byte so với vị trí hiện tại.
Ví dụ:	JMP SHORT Calculate	
JMP (near jump). Khi đó trong mã lệnh lưu 2 byte khoảng cách (offset) giữa vị trí hiện tại và vị trí cần nhảy đến. Kiểu này nhảy tùy ý trong phạm vi segment.
Ví dụ:	JMP Calculate	
JMP FAR PTR (far jump). Khi đó trong mã lệnh lưu offset và segment của vị trí cần nhảy đến. Kiểu này nhảy đến bất kì chỗ nào.
Ví dụ:	JMP FAR PTR Calculate	
JMP (near indirect jump). Khi đó trong mã lệnh lưu địa chỉ offset của một ô nhớ. Khi thực hiện, IP sẽ được gán bằng giá trị lưu tại địa chỉ này. Có thể kết hợp dùng với định vị chỉ số.
Ví dụ:	
myPointer	DW	Prepare, Calculate, Check, Output
	...
	MOV	bx,2	; chỉ số trong mảng con trỏ
	SHL	bx,1	; nhân đôi
	JMP	myPointer[bx]
	...
Prepare:	; công việc 0
	...
Calculate:	; công việc 1
	...
Check:	; công việc 2 – nơi cần nhảy đến
	...
Output:	; công việc 3
	...
JMP (far indirect jump). Tương tự trường hợp trên, nhưng con trỏ gồm cả segment và offset. Chỉ khác ở khai báo con trỏ
Ví dụ:	
myPointer	DD	Prepare, Calculate, Check, Output
	...
	MOV	bx,1	; chỉ số trong mảng con trỏ
	MOV	cl,2
	SHL	bx,cl	; nhân 4
	JMP	myPointer[bx]
	...
Prepare:	; công việc 0
	...
Calculate:	; công việc 1 – nơi cần nhảy đến
	...
JMP (indirect jump via regs). Nhảy đến địa chỉ lưu trong thanh ghi AX.
Ví dụ:	
	MOV	ax, offset Calculate
	...
	JMP	ax	; (IP ← AX)
Lệnh nhảy có điều kiện
	J.... 
Các lệnh nhảy có điều kiện bắt đầu bằng chữ J sau đó là các chữ cái biểu thị điều kiện (ví dụ JGE ah,5: Jump if Greater than or Equal, nhảy nếu AH lớn hơn hay bằng 5), tiếp sau là một tên nhãn. Tùy thuộc vào trạng thái các cờ hiệu mà bộ vi xử lý có thực hiện việc nhảy đến nhãn hay không.
Đối với bộ vi xử lý 80286 trở xuống, lệnh nhảy có điều kiện có độ dài 2 byte, byte đầu tiên chứa mã lệnh, byte thứ hai chứa khoảng cách tương đối từ lệnh đến nhãn, vì vậy trong lệnh nhảy có điều kiện phải nằm trong khoảng từ -128 đến 127 so với vị trí lệnh nhảy. Muốn nhảy xa hơn ta phải dùng kết hợp lệnh nhảy không điều kiện JMP
Từ 80386 trở lên, bộ lệnh được bổ sung, cho phép sử dụng lệnh nhảy có điều kiện có độ dài 4 byte, do đó có quyền nằm tùy ý trong cùng phạm vi segment.
Khi sử dụng lệnh nhảy có điều kiện sau khi thực hiện phép so sánh, phải đặc biệt lưu ý toán hạng trong phép so sánh là số có dấu (signed) hay không có dấu (unsigned) để lựa chọn lệnh cho phù hợp.
	Ví dụ:
	MOV	AH,AL	; AL hiện bằng 128
	CMP	AH,1
	JGE	Greater	; AH > 1 nhưng không nhảy ????
	. . .
Greater:
Một số lệnh nhảy có điều kiện thường dùng (tham khảo thêm trong SGK trang 81): 
JE, JZ (nhảy nếu bằng).
JA (nhảy nếu lớn hơn, không dấu), JG (nhảy nếu lớn hơn, có dấu), JB (nhảy nếu nhỏ hơn, không dấu), JL (nhảy nếu nhỏ hơn, có dấu). 
JAE (nhảy nếu lớn hơn hay bằng, không dấu), JGE (nhảy nếu lớn hơn hay bằng, có dấu), JBE (nhảy nếu nhỏ hơn hay bằng, không dấu), JLE (nhảy nếu nhỏ hơn hay bằng, có dấu).
JNE, JNZ (nhảy nếu không bằng).
Ví dụ: nếu AL là số nguyên không dấu thì đoạn chương trình ở trên phải sửa lại như sau:
	MOV	AH,AL
	CMP	AH,1
	JAE	Greater
	. . .
Greater:
Lệnh lặp
Bằng cách dùng các lệnh nhảy có thể tạo ra vòng lặp. Tuy nhiên, để viết chương trình tiện lợi và ngắn gọn, có thể dùng thêm các lệnh lặp như LOOP, LOOPZ,…
Lệnh LOOP tự động giảm CX một đơn vị, sau đó kiểm tra xem CX có bằng 0, nếu không bằng thì nhảy đến nhãn 
Lệnh LOOPZ tự động giảm CX một đơn vị, sau đó kiểm tra xem CX có bằng 0 hoặc cờ ZF có bật không, nếu cả hai điều này không xảy ra thì nhảy đến nhãn 
Ví dụ: Nhập mảng A gồm 10 ký tự
MOV	SI, 0	; chỉ số mảng
MOV	CX, 10	; số lần lặp
LAP:
;nhập ký tự
MOV 	AH, 1
INT 	21H
MOV 	A[SI], AL
INC	SI
; xuất ký tự
MOV 	AH, 2
INT 	21H
LOOP	LAP
Tài liệu tham khảo
Nguyễn Minh Tuấn, Giáo trình hợp ngữ - Chương 4, ĐHKHTN, 2002
Randal Hyde, The art of assembly language programming – Chapter 6, 10.
Dan Rollins, TechHelp v.6.0
NortonGuide
Bài tập
Bài 1. Viết chương trình cho nhập 1 ký tự từ màn hình và xuất câu thông báo chào buổi sáng, buổi trưa hay buổi chiều tương ứng với ký tự nhậpvào là 'S', 's', 'T', 't', 'C', 'c'.
Bài 2. Nhập 2 số nguyên dương thuộc N,M thuộc [0..9], nhập 1 ký tự Char. Xuất ra màn hình ma trận gồm N dòng và M cột gồm ký tự Char.
	Ví dụ:	N=3, M=4, C='*'
* * * *
	* * * *
	* * * *
Bài 3. Nhập 2 số nguyên dương A, B. Tính A/B, A*B (không dùng lệnh DIV, MUL)
Ví dụ: A=18, B=3
Tính A/B: 18 - 3 - 3 - 3 - 3 - 3 - 3 = 0, vậy A/B = 6 (tổng số lần A trừ B cho đến khi A = 0).
Tính A*B = 18 + 18 + 18 = 54
Bài 4. Tìm USCLN của 2 số nguyên dương N, M nhập từ bàn phím. Kiểm tra N,M có là hai số nguyên tố cùng nhau không?
Ví dụ: 	N = 15, M = 6	=> USCLN(15, 6) = 3
Ví dụ: 	N = 3, M = 5 	=> USCLN(3, 5) = 1 => 3, 5 là 2 số nguyên tố cùng nhau.
Bài 5. Dùng lệnh lặp, viết chương trình nhập vào 1 chuỗi ký tự. Sau khi nhập xong đếm xem chuỗi có bao nhiêu ký tự. Xuất số ký tự có trong chuỗi.
Ví dụ: S = "Hello world !" ==> Số kí tự trong chuỗi là 13.
Bài 6. Nhập vào 2 chuỗi số, đổi 2 chuỗi thành số, sau đó cộng hai số, đổi ra chuỗi và xuất chuỗi tổng.
Ví dụ: 	S1 = "123" => N1 = 123
	S2 = "456" => N2 = 456
	N = N1 + N2 = 123 + 456 = 579 => S = "579" (xuất S ra màn hình)
Bài 7. Viết chương trình cho phép nhập vào một chuỗi S.
Đổi tất cả ký tự thường thành ký tự hoa.
Đổi tất cả ký tự hoa thành ký tự thường.
Bài 8. Nhập và xuất mảng 1 chiều. Tìm phần tử max, min, tính tổng các phần tử trong mảng.
	Ví dụ: 	N = 5
	A[N] = {3,1,2,7,4} 
	=> max = 7, min = 1, tổng = 17.
Bài 9. Cài đặt thuật toán Bubble Sort dùng ASM.
Thuật toán Bubble Sort theo ngôn ngữ C như sau:
	for (int i = 0; i< N-1; i++)
	for(int j=N-1;j > i; j--)
	if(a[j] < a[j-1])	
	Hoan_Vi (a[j], a[j-1]);
Bài 10. Nhập và xuất mảng A hai chiều. 
	a. Tính tổng các phần tử trên đường chéo chính, đường chéo phụ.
	b. Đếm số phần tử 0 và phần tử khác 0 trong mảng.
	c. Tìm phần tử max của mỗi dòng, mỗi cột. Tính tổng của mỗi dòng, mỗi cột.
d. Nhập 1 mảng hai chiều B, tạo một mảng hai chiều C có các phần tử trên dòng chẵn bằng với các phần tử trên dòng chẵn của A, các phần tử trên dòng lẻ bằng các phần tử trên dòng lẻ của B.
Mở rộng
Trong bài tập 5, làm sao để đếm số từ có trong chuỗi kí tự?
Trong bài tập 10, làm sao để thể hiện một menu cho phép người dùng chọn trong các kí tự từ ‘a’ đến ‘d’ sau đó thực hiện công việc ứng với chữ cái đó.
Hướng dẫn
Bài 1. Xem ví dụ:
.MODEL SMALL
.STACK 100H
.DATA
	CBS 	DB 	"CHAO BUOI SANG$"
	CBT	DB 	"CHAO BUOI TRUA$"
	CBC 	DB 	"CHAO BUOI CHIEU$"
.CODE
	MOV 	AX, @DATA
	MOV 	DS, AX
	;nhập 1 ký tự bất kỳ
	MOV 	AH, 1
	INT 	21H
	CMP 	AL, 'S'
	JE	CHAO_BUOI_SANG
	CMP 	AL, 's'
	JE	CHAO_BUOI_SANG
	CMP 	AL, 'T'
	JE	CHAO_BUOI_TRUA
	CMP 	AL, 't'
	JE	CHAO_BUOI_TRUA
	CMP 	AL, 'C'
	JE	CHAO_BUOI_CHIEU
	CMP 	AL, 'c'
	JE	CHAO_BUOI_CHIEU
CHAO_BUOI_SANG:
	LEA 	DX, CBS
	MOV	AH,9
	INT 	21H
	JMP 	THOAT
CHAO_BUOI_TRUA:
	LEA 	DX, CBT
	MOV	AH,9
	INT 	21H
	JMP 	THOAT
CHAO_BUOI_CHIEU:
	LEA 	DX, CBC
	MOV	AH,9
	INT 	21H
	JMP 	THOAT
THOAT:
	MOV 	AH, 4CH
	INT 	21H
END
Bài 3. Để nhập một số nguyên, có thể làm như sau: đầu tiên nhập xâu kí tự chứa các số từ 0 đến 9, sau đó đổi từng kí tự ra số và nhân với các lũy thừa tương ứng của 10 và cộng lại.
Bài 9. Xem ví dụ sau: Lặp gồm 2 vòng lặp (xếp mảng A có N phần tử tăng dần)
MOV 	N, 10	;giả sử mảng A gồm N ký tự, trong ví dụ này N=10
MOV	CX, N 	
DEC 	CX
MOV	SI, 0
FOR_I:
	PUSH	CX
	MOV 	CX, N
	MOV 	DI, 0
	MOV 	DL, A[SI]
	FOR_J:
	CMP	DL, A[DI]
	JB	LAP
	MOV 	BL, A[DI]
	MOV	A[DI], DL
	MOV 	A[SI], BL
	MOV	DL, A[SI]
	LAP:
	INC 	DI
	LOOP FOR_J
	INC 	SI
	POP	CX
	LOOP FOR_I

File đính kèm:

  • docThực hành Assembly - Bài 2 Lệnh so sánh - Lệnh nhảy - Lệnh lặp.doc