Cú pháp lệnh:
Một lệnh hợp ngữ đầy đủ gồm bốn thành phần sau đây:
[Nhãn lệnh:] <Tên lệnh> [Các toán hạng] [;Lời giải thích]
Trong đó:
- [Nhãn lệnh:]: Là một dãy các kí tự đứng trước câu lệnh (kết thúc bởi dấu hai chấm (:)), nó được chỉ định thay thế cho địa chỉ của câu lệnh trong các đoạn lệnh lặp, rẽ nhánh,... Do đó, nó chỉ được sử dụng khi cần.
Trong một chương trình hợp ngữ không thể có hai nhãn lệnh trùng tên, tên của các nhãn cũng không thể trùng với tên của các thủ tục trong chương trình.
- <Tên lệnh>: Là một trong các lệnh thuộc tập lệnh hợp ngữ (lệnh gợi nhớ: Mnemonic) của vi xử lý trên máy tính thực hiện lệnh này.
Lệnh hợp ngữ không phân biệt chữ hoa hay chữ thường. Trong chương trình hợp ngữ mỗi dòng chỉ có thể chứa một lệnh và mỗi lệnh phải được đặt trên một dòng.
- [Các toán hạng]: Là đối tượng mà lệnh tác động vào. Một lệnh hợp ngữ của Intel 8088/8086 có thể không có toán hạng, có một toán hạng, hoặc có hai toán hạng. Nếu có hai toán hạng thì toán hạng đứng trước gọi là [Toán hạng đích], toán hạng đứng sau gọi là [Toán hạng nguồn]. [Toán hạng đích] không thể là một hằng số.
Một số lệnh hợp ngữ của các Intel 80286/80386/... có thể có đến 3 toán hạng, trong trường hợp này cũng chỉ có một [Toán hạng đích].
- [;Lời giải thích]: Chỉ có tác dụng với người viết và người đọc chương trình, nó không có ý nghĩa với trình biên dịch, tức là, không được dịch sang mã máy. Lời giải thích thường được sử dụng để làm rõ ý nghĩa của câu lệnh (khi người viết thấy cần). Lời giải thích phải nằm sau dấu chấm phảy (;).
Ví dụ 1: Xét lệnh sau đây:
Lenh_VD: Mov AX,BX ; đặt giá trị thanh ghi BX vào thanh ghi AX
Trong đó:
- Lenh_VD: Trong trường hợp này dãy kí tự Lenh_VD được sử dụng làm nhãn lệnh cho lệnh Mov.
- Mov: Là tên lệnh.
- AX và BX: Là các toán hạng (đích và nguồn). Trong trường hợp này toán hạng là các thanh ghi đa năng 16 bít.
- “đặt giá trị thanh ghi BX vào thanh ghi AX”: Là lời giải thích cho lệnh này. Trong thực tế lời giải thích thường là tiếng Việt không dấu.
Ví dụ 2: Xem các lệnh sau đây:
- NOP ; đây là lệnh không có toán hạng
- Mov Ax, Bl ; lệnh này có hai toán hạng, [Toán hạng đích] là thanh
; ghi 16 bít, [Toán hạng nguồn] là thanh ghi 8 bít
- Add Cl, Spt ; lệnh này có hai toán hạng, [Toán hạng đích] là thanh
; ghi 8 bít, [Toán hạng nguồn] là một biến byte
- Mov Ax, [SI] ; lệnh này có hai toán hạng, [Toán hạng đích] là thanh
; ghi 16 bít, [Toán hạng nguồn] là một ô nhớ
- Sub Dl, ‘a’ – ‘A’ ; lệnh này có hai toán hạng, [Toán hạng đích] là thanh
; ghi 8 bít, [Toán hạng nguồn] là một hằng số
- IMul Ax, Bx, 20 ; lệnh này có ba toán hạng, [Toán hạng đích] là thanh
; ghi 16 bit (Ax), [Toán hạng nguồn] là thanh ghi 16 bít
; (Bx) và một hằng số (20)
Lệnh Imul ở trên là một lệnh nhân mới của vi xử lý Intel 80286. Lệnh này thực hiện như sau: lấy nội dung/giá trị hai [Toán hạng nguồn] nhân với nhau, kết quả chứa ở [Toán hạng đích] (trong lệnh trên là: Bx*20, tích kết quả chứa ở thanh ghi Ax (chỉ lấy 16 bít thấp của tích để đưa vào Ax)).
1. Lệnh Mov (Move):
Cú pháp lệnh:
Mov [Toán hạng đích], [Toán hạng nguồn]
Trong đó:
- [Toán hạng đích]: Có thể là thanh ghi (8 bít hay 16 bít), ô nhớ (chính xác hơn là địa chỉ của một ô nhớ) hay một biến nào đó. [Toán hạng đích] không thể là hằng số.
- [Toán hạng nguồn]: Có thể là hằng số, biến, thanh ghi, ô nhớ (chính xác hơn là địa chỉ của một ô nhớ) nào đó.
Tác dụng: Lấy nội dung (giá trị) của [Toán hạng nguồn] đặt vào [Toán hạng đích]. Nội dung của [Toán hạng nguồn] không bị thay đổi.
Ví dụ 1:
- Mov Ax, 5 ; Ax ß 5: đặt giá trị 5 vào thành ghi Ax
- Mov Ax, 5*2 ; Ax ß 5*2: đặt giá trị 10 vào thành ghi Ax
- Mov Bx, (80*(Dong - 1) + (Cot - 1))*2
; Dong, Cot là các biến
- Mov Dl, ‘A’ ; Dl = 41h: đặt mã ASCII của ‘A’ vào thanh ghi Dl
- Mov Cx, Var1 ; Cx = Var1: đặt giá trị của biến Var1 vào thanh ghi Cx
- Mov Ax, Bx ; Ax = Bx: đặt giá trị của thanh ghi Bx vào Ax
- Mov Ax, Dl ; Ax = Dl: đặt giá trị của Dl (8 bít) vào Ax (16 bít)
- Mov Bl, Dx ; Bl = Dx: không hợp lệ, vì: Dx (16 bít) mà Bl (8 bít)
- Mov Dl, 300 ; Dl = 300: không hợp lệ, vì 300 vượt giới hạn 1 byte
Ví dụ 2: Giả sử DI = 100; Ô nhớ tại địa chỉ offset 100 trong đoạn nhớ Data (được chỉ bởi DS) chứa kí tự B. Thì :
- Mov Ax, DI ; (1) đặt giá trị thanh ghi DI vào thanh ghi Ax: Ax = 100
- Mov Ax, [DI] ; (2) Ax = <nội dung của ô nhớ được chỉ bởi DI (DI
; chứ địa chỉ offset của ô nhớ)>. Tức là, đặt nội dung của
; ô nhớ được chỉ bởi DI vào thanh ghi Ax: Ax = 41h
Hãy phân biệt sự khác nhau giữa hai lệnh trên: Lệnh (1) sử dụng chế độ địa chỉ thanh ghi. Lệnh (2) sử dụng chế độ địa chỉ gián tiếp thanh ghi.
Nhớ lại rằng: Trong chế độ địa chỉ gián tiếp thanh ghi, các thanh ghi chỉ có thể là BX, DI, SI (địa chỉ đoạn chứa trong DS) hay BP (địa chỉ đoạn chứa trong SS). Như vậy lệnh (2) tương đương với lệnh (3) nhưng khác lệnh (4):
- Mov Ax, DS:[DI] ; (3)
- Mov Ax, ES:[DI] ; (4)
Ví dụ 3:
- Mov Ax, [SI] ; đặt nội dung ô nhớ được chỉ bởi SI vào thanh ghi Ax
- Mov [DI], Bx ; đặt giá trị của thanh ghi bx vào ô nhớ được chỉ bởi DI
- Mov [DI], [SI] ; [DI] ß [SI] : lệnh không hợp lệ, vì: không thể chuyển
; nội dung của ô nhớ vào một ô nhớ một cách trực tiếp
- Mov Var1, Ax ; Var1 ß Ax : đặt giá trị t/ghi Ax vào biến word Var1
Chú ý:
- Lệnh Mov không làm ảnh hưởng đến các cờ.
- Mov DS:[DI], ES:[SI] ; lệnh không hợp lệ, vì: không thể chuyển dữ liệu
; trực tiếp giữa hai toán hạng bộ nhớ với nhau
- Mov DS, ES ; DS ß ES: lệnh không hợp lệ,
- Mov ES, 0100 ; lệnh không hợp lệ, vì: không thể chuyển
; trực tiếp một hằng số vào thanh ghi đoạn.
Để chuyển giá trị của hai thanh ghi đoạn hay nội dung của hai ô nhớ ta có thể mượn một thanh ghi đa năng làm trung gian:
- Mov Ax, ES ; hai lệnh này chuyển nội dung của thanh ghi đoạn ES
Mov DS, Ax ; vào thanh ghi đoạn DS thông qua thanh ghi Ax
Theo cách thông thường, để hoán đổi giá trị của hai thanh ghi đoạn hay nội dung của hai ô nhớ người ta thường sử dụng hai thanh ghi đa năng làm trung gian:
- Mov Ax, [DI] ; lưu tạm nội dung ô nhớ được chỉ bởi DI và Ax
Mov Bx, [SI] ; lưu tạm nội dung ô nhớ được chỉ bởi SI và Bx
Mov [DI], Bx ; chuyển giá trị của t/ghi Bx và ô nhớ được chỉ bởi DI
Mov [SI], Ax ; chuyển giá trị của t/ghi Ax và ô nhớ được chỉ bởi SI
Bốn lệnh trên có tác dụng hoán đổi nội dung của hai ô nhớ trong đoạn Data (DS) được chỉ bởi DI và SI (DI và SI chứa địa chỉ Offset của các ô nhớ).
- Không thể dùng thanh ghi đoạn CS làm [Toán hạng đích] trong lệnh Mov.
2. Các lệnh Inc – Dec – Add và Sub
Cú pháp lệnh:
- Inc [Toán hạng đích]
- Add [Toán hạng đích],[Toán hạng nguồn]
- Dec [Toán hạng đích]
- Sub [Toán hạng đích],[Toán hạng nguồn]
Trong đó: [Toán hạng đích], [Toán hạng nguồn]: tương tự lệnh Mov.
Tác dụng:
- Lệnh Inc (Increment): làm tăng giá trị của [Toán hạng đích] lên 1 đơn vị.
- Lệnh Dec (Decrement): làm giảm giá trị của [Toán hạng đích] xuống 1 đơn vị.
- Lệnh Add (Addition): lấy giá trị/nội dung của [Toán hạng nguồn] cộng vào giá trị/nội dung của [Toán hạng đích], kết quả này đặt vào lại [Toán hạng đích].
- Lệnh Sub (Subtract): lấy giá trị/nội dung của [Toán hạng đich] trừ đi giá trị/nội dung của [Toán hạng nguồn], kết quả này đặt vào lại [Toán hạng đích].
Ví dụ 1:
Mov Ax, 121 ; đặt giá trị 121 vào thanh ghi Ax
Mov Bx, 223 ; đặt giá trị 232 vào thanh ghi Bx
Inc Ax ; Ax = Ax + 1: tăng Ax lên 1 đơn vị (Ax = 122)
Dec Bx ; Bx = Bx + 1: giảm Bx xuống 1 đơn vị (Bx = 222)
Sub Ax, Bx ; Ax = Ax – Bx : Ax = -100
Add Ax, 120 ; Ax = Ax + 120 : Ax = 20
Mov Cx, Ax ; Cx= Ax : Cx = 20
Dãy lệnh trên, đặt giá trị cuối cùng của thanh ghi Ax vào thanh ghi Cx (Cx = 20).
Ví dụ 2:
- Inc Spt ; Spt = Spt + 1; tăng giá trị biến Spt lên 1 đơn vị
- Inc DS:[SI] ; tăng ndung ô nhớ được chỉ bởi DS:SI lên 1 đơn vị
- Add Ax, Var1 ; Ax = Ax + Var1; cộng giá trị biến Var1 vào Ax
- Add Var2, Dx ; Var2 = Var2 + Dx. Biến Var2 là biến dạng word
- Add Dx, [SI] ; cộng thêm nội dung ô nhớ được chỉ bởi SI vào Dx
- Add [DI], [SI] ; [DI] = [DI] + [SI] : lệnh không hợp lệ, vì: không thể
; cộng trực tiếp nội dung hai ô nhớ với nhau.
; Yêu cầu của lệnh trên có thể được viết lại như sau:
Mov Ax, [SI] ; lưu tạm nội dung ô nhớ được chỉ bởi SI và Ax
Mov Bx, [DI] ; lưu tạm nội dung ô nhớ được chỉ bởi DI và Bx
Add Bx, Ax ; cộng Ax và Bx, kết quả chứa ở Bx
Mov [DI], Bx ; đặt kết quả phép cộng vào lại ô nhớ được chỉ bởi DI
Ví dụ 3: Cộng thêm giá trị của thanh ghi Ax vào nội dung của ô nhớ tại địa chỉ offset 0100 trong đoạn DS:
Mov DI, 0100 ; trỏ DI về ô nhớ offset 0100
Mov Bx, DS:[DI] ; lưu tạm ndung ô nhớ DS:DI vào thanh ghi Bx
Add Bx, Ax ; cộng thêm Ax vào Bx
Mov DS:[DI], Bx ; đặt kết quả vào lại ô nhớ DS:DI (DS:0100)
Trong trường hợp này ta có thể sử dụng lệnh Add DS:[DI],Ax.
Ví dụ 4: Giả sử tại ô nhớ 0B800:0100 trong bộ nhớ có chứa một word dữ liệu. Hãy tăng nội dung của ô nhớ này lên một đơn vị.
Mov Ax, 0B800h ; mượn thanh ghi Ax làm trung gian để chuyển
Mov ES, Ax ; địa chỉ đoạn của ô nhớ cần truy xuất vào ES
Mov DI, 01 ; đặt địa chỉ offset của ô nhớ cần truy xuất vào DI
;-----------------------; (gọi ngắn gọn: trỏ ES:DI về ô nhớ cần truy xuất)
Mov Dx, ES:[DI] ; chuyển tạm nội dung ô nhớ cần tăng vào Dx
Inc Dx ; tăng giá trị thanh ghi Dx lên 1 đơn vị
Mov ES:[DI], Dx ; đặt giá trị Dx đã tăng vào lại ô nhớ cần tăng
Ví dụ 5: Giả sử tại địa chỉ 0A00:0100 trong bộ nhớ có chứa một byte dữ liệu. Hãy chuyển nội dung của ô nhớ này vào thành ghi AL.
Mov Ax, 0A00h ; (1); Các lệnh (1), (2), (3) trỏ cặp thanh
Mov ES, Ax ; (2); ghi ES:DI về ô nhớ có địa chỉ 0A00:0100
Mov DI, 0100h ; (3); trong đó 0A00 là địa chỉ Segment và
;------------------------- ; 0100 là địa chỉ Offset. Lệnh (4) chuyển nội
Mov Al, ES:[DI] ; (4); dung ô nhớ được chỉ bởi ES:DI vào Al.
Ví dụ 6: Giả sử tại địa chỉ 0100:0100 trong bộ nhớ có chứa 2 word dữ liệu liên tiếp (hai ô nhớ liên tiếp). Hãy tính tổng nội dung hai word nhớ này, rồi lấy kết quả ghi vào ô nhớ tại địa chỉ 0100:0120.
Mov Ax, 0100
Mov ES, Ax ; trỏ cặp thanh ghi ES:SI về đầu vùng nhớ
Mov SI, 0100 ; cần truy xuất.
Mov DI,0120 ; trỏ cặp thanh ghi ES:DI về ô nhớ chứa kết quả
;------------------------- ; các ô nhớ này ở trong cùng một Segment
Mov Ax, ES:[SI] ; lưu tạm nội dung ô nhớ đầu tiên vào Ax
Add Ax, ES:[SI+2] ; cộng nội dung ô nhớ kế tiếp vào Ax
Mov ES:[DI], Ax ; ghi kết quả vào ô nhớ 0100:0120
Lệnh Add Ax, ES:[SI+2] ở trên sử dụng chế độ định địa chỉ bộ nhớ gián tiếp, cụ thể là định địa chỉ chỉ mục (sử dụng thanh ghi chỉ mục SI).
Qua 3 ví dụ 4, 5, 6 ta có thể rút ra nguyên tắc cơ bản khi truy xuất dữ liệu/nội dung của một ô nhớ là: Sử dụng một cặp thanh ghi thích hợp (DS:DI, DS:SI, ES:DI, ES:SI,...) để chứa địa chỉ logic (gồm cả Segment và Offset) của ô nhớ cần truy xuất. Thao tác này thường gọi là trỏ về ô nhớ cần truy xuất. Sau đó sử dụng cặp thanh ghi này để ghi/đọc nội dung của ô nhớ đã được trỏ tới.
Ngoài ra, khi truy xuất ô nhớ cần phải xác định dữ liệu/nội dung tại đó là một Byte hay một Word và nếu là truy xuất đọc thì kết quả sẽ được lưu vào đâu (thanh ghi hay ô nhớ).
Chú ý 1:
- Không thể cộng trực tiếp hai thanh ghi đoạn. Trong trường hợp này phải sử dụng các thanh ghi đa năng làm trung gian.
- Lệnh Add thực hiện phép cộng không nhớ. Để thực hiện phép cộng có nhớ (cộng thêm giá trị của cờ nhớ (CF) hiện tại vào kết quả) phải sử dụng lệnh ADC (ADD with Carry) [2 - 171]. Tương tự với lệnh Sub và SBB [2 - 180].
- Để thực hiện phép cộng trên các số/giá trị BCD (Binary Coded Decimal) ta phải sử dụng các lệnh cộng AAA (Ascii Adjust for Addition) và DAA (Decimal Adjust for Addition) để điều chỉnh (adjust) kết quả cuối cùng [2 - 172]. Tương tự, với phép trừ trên các số BCD phải sử dụng lệnh AAS và DAS [2 - 183].
Chú ý 2:
- Các thanh ghi của vi xử lý Intel 8086/8088 đều là 16 bít, nên để chứa một đại lượng dữ liệu 32 bít nó phải dùng 2 thanh ghi, thường là các thanh ghi đa năng (thanh ghi tích lũy): Ax, Bx, Cx, Dx. Cặp thanh ghi Dx:Ax thường được sử dụng nhất, khi đó Ax chứa 16 bít thấp, Dx chứa 16 bít cao của đại lượng 32 bít.
- Để cộng/trừ trên các số 32 bít ta không thể sử dụng Add/Sub theo cách thông thường, mà phải thực hiện như sau: Cộng/Trừ 16 bít thấp, sau đó Cộng/Trừ 16 bít cao. Nếu phép Cộng/Trừ trên 16 bít thấp xuất hiện bít nhớ/bít mượn thì phải tiến hành điều chỉnh kết quả, nếu không kết quả sẻ sai. Sử dụng các phép kiểm tra cờ để biết phép Cộng/Trừ có xuất hiện bít nhớ/bít mượn hay không [1 - 477].
0 Comment:
Đăng nhận xét
Thank you for your comments!