Tập lệnh assembly của Intel 8086/8088 (Phần 3)

5. Lệnh Mul và Div

Cú pháp:

Mul     [Toán hạng nguồn]
IMul   [Toán hạng nguồn]
Div      [Toán hạng nguồn]
IDiv    [Toán hạng nguồn]
Trong đó: [Toán hạng nguồn]có thể là thanh ghi hay ô nhớ. Với các lệnh nhân: [Toán hạng đích] ngầm định là thanh ghi Al hoặc Ax. Với các lệnh chia: [Toán hạng đích] là một trong các thanh ghi đa năng Ax, Bx,...

Tác dụng:

-     Lệnh Mul (Multiply): Thực hiện phép nhân trên số không dấu. Nếu [Toán hạng nguồn] là toán hạng 8 bít thì lệnh sẽ nhân nội dung của [Toán hạng nguồn] với giá trị thanh ghi AL, kết quả 16 bít chứa ở thanh ghi Ax.  

Nếu [Toán hạng nguồn] là toán hạng 16 bít thì lệnh sẽ nhân nội dung của [Toán hạng nguồn] với giá trị thanh ghi Ax, kết quả 32 bít chứa ở cặp thanh ghi Dx:Ax, phần thấp ở Ax, phần cao ở Dx. Nếu phần cao của kết quả (AH hoặc DX) bằng 0 thì các cờ CF = 0 và OF = 0.

-     Lệnh IMul (Interger Multiply): Tương tự lệnh Mul nhưng thực hiện phép nhân trên hai số có dấu. Kết quả cũng là một số có dấu.

     -     Lệnh Div (Divide): Thực hiện phép chia trên số không dấu. Nếu [Toán hạng nguồn] là toán hạng 8 bít thì lệnh sẽ lấy giá trị của thanh ghi Ax (số bị chia) chia cho [Toán hạng nguồn] (số chia), kết quả thương số chứa trong thanh ghi Al, số dư chứa trong thanh ghi Ah.    

Nếu [Toán hạng nguồn] là toán hạng 16 bít thì lệnh sẽ lấy giá trị của cặp thanh ghi Dx:Ax (số bị chia) chia cho [Toán hạng nguồn] (số chia), kết quả thương số chứa trong thanh ghi Ax, số dư chứa trong thanh ghi Dx.

Nếu phép chia cho 0 xảy ra hay thương số vượt quá giới hạn của thanh ghi AL (chia 8 bít) hay Ax (chia 16 bít) thì CPU sẽ phát sinh lỗi “Divice overflow”.

-     Lệnh Idiv (Integer Divide): Tương tự lệnh  Div nhưng thực hiện phép chia trên hai số có dấu. Kết quả cùng là các số có dấu.

Ví dụ 1:

-             Mul         Bl                    ; Ax ßAL * Bl: số bị nhân ngầm định trong Al      

-             Mul         Bx                   ; Dx:Ax ßAx * Bx: số bị nhân ngầm định trong Ax

-             Idiv         Bl                    ; Ax/Bl, thương số chứa trong Al, số dư chứa trong Ah

-             Idiv         Bx                   ; Dx:Ax/Bx, thương số chứa trong Ax, số dư trong Dx

Ví dụ 2: Dãy các lệnh dưới đây sẽ thực hiện phép gán A = 4*A – 3*B, trong đó A và B là các biến kiểu word:

                    Mov        Ax, 4                ; số nhân phải được chứa trong Ax

                    IMul        A                      ; thực hiện phép nhân

                    Mov        Bx, Ax              ; lưu tạm kết quả vào Bx      

                    Mov        Ax, 3                ; Ax = 3

                    Imul        B                     ; Ax = Ax * B

                    Sub         Bx, Ax          

                    Mov        A, Bx                ; đặt kết quả cuối cùng vào A

Trong trường hợp này ta đã giả sử hiện tượng tràn đã không xảy ra và kết quả phép nhân chỉ chứa trong thanh ghi Ax.  

Ví dụ 3: Các lệnh sau đây thực hiện phép: chia -123 cho 24:

                    Mov        Ax, -123         ; đặt số bị chia vào Ax

                    Mov        Bl, 24              ; đặt số chia vào Bl (thanh ghi 8 bít)

                    Idiv         Bl                    ; chia Ax cho Bl, kết quả chứa ở Al và Ah

Ví dụ 4: Dãy lệnh dưới đây sẽ thực hiện phép gán A = N! (tính N giai thừa). A là một biến word:

                    Mov        Ax, 1               ; chuẩn bị Ax để lưu kết quả

                    Mov        Cx, N              ; tính N!

               LapNhan:                        

                    Mul         Cx                   ; Ax ßAx * Cx

                    Loop       LapNhan    

                    ;---------------------------

                    Mov        A, Ax              ; trả kết quả vào biến A

Trong trường hợp này chúng ta giả sử kết quả không vượt quá gới hạn 16 bít.

Chúng ta đã biết: N! = 1 nếu N = 1, N! = N*(N-1)*(N-2)*...*1 nếu N>1, điều này hoàn toàn phù hợp với sự thay đổi của thanh ghi CX trong lệnh lặp Loop. Do đó, ở đây ta có thể sử dụng CX như là N trong biểu thức tính giai thừa.  

Chú ý: Hợp ngữ cung cấp lệnh AAM (Ascii Adjust for Multiple) để điều chỉnh kết quả phép nhân trên 2 số BCD dạng không dồn. Và lệnh AAD (Ascii Adjust for Division) để điều chỉnh kết quả phép chia trên 2 số BCD dạng không dồn. Ngoài ra còn có lệnh CBW (Convert Byte to Word) và lệnh CWD (Convert Word to Doubleword) để hỗ trợ cho phép chia trên các số có dấu [2 – 187-200].

Lệnh IMul của vi xử lý Intel 80286 cho phép ghi rõ [Toán hạng đích], [Toán hạng nguồn] trong câu lệnh, các lệnh này có thể có đến 3 toán hạng [1 - 541].

6. Lệnh logic: NOT – AND – OR – XOR – TEST

Trước khi tìm hiểu về các lệnh logic chúng ta xem lại kết quả thực hiện các phép tính logic trên 2 bít nhị phân A và B thông qua bảng sau đây:

A

B

A And B

A Or B

A Xor B

NotA

0

0

0

0

0

1

0

1

0

1

1

1

1

0

0

1

1

0

1

1

1

1

0

0


Bảng trên cho thấy: Với phép And: kết quả = 1 chỉ khi cả hai bít = 1; Với phép Or: kết quả = 0 chỉ khi cả hai bít = 0; Với phép Xor: kết quả = 0 khi hai bít giống nhau, kết quả = 1 khi hai bít khác nhau. Với phép Not: 0 thành 1, 1 thành 0.    

Cú pháp:

Not     [Toán hạng đích]
And     [Toán hạng đích], [Toán hạng nguồn]
Or       [Toán hạng đích], [Toán hạng nguồn]
Xor     [Toán hạng đích], [Toán hạng nguồn]
Test    [Toán hạng đích], [Toán hạng nguồn]
Trong đó: [Toán hạng đích], [Toán hạng nguồn] có thể là hằng số (trực hằng), biến, thanh ghi hay địa chỉ ô nhớ. [Toán hạng đích] không thể là hằng số.

Tác dụng: Mỗi lệnh logic thực hiện phép tính logic tương ứng trên các bít (tương ứng về vị trí) của [Toán hạng đích] và [Toán hạng nguồn], kết quả được ghi vào lại [Toán hạng đích]. Riêng lệnh Not, thực hiện phép đảo bít ngay trên các bít của [Toán hạng đích]. Hầu hết các lệnh logic đều ảnh hưởng đến các cờ CF, OF, ZF,...

-     Lệnh Not (Logical Not): Thực hiện việc đảo ngược từng bít trong nội dung của [Toán hạng đích]. Lệnh này không làm ảnh hưởng đến các cờ.

Lệnh Not thường được sử dụng để tạo dạng bù 1 của [Toán hạng đích].      

-     Lệnh And (Logical And): Thực hiện phép tính logic And trên từng cặp bít (tương ứng về vị trí) của [Toán hạng nguồn] với [Toán hạng đích], kết quả lưu vào [Toán hạng đích].

Lệnh And thường được sử dụng để xóa (= 0) một hoặc nhiều bít xác định nào đó trong một thanh ghi.

-     Lệnh Or (Logical Inclusive Or):Thực hiện phép tính logic Or trên từng cặp bít (tương ứng về vị trí) của [Toán hạng nguồn] với [Toán hạng đích], kết quả lưu vào [Toán hạng đích].

Lệnh Or thường dùng để thiết lập (= 1) một hoặc nhiều bít xác định nào đó trong một thanh ghi.

-     Lệnh Xor (eXclusive OR):Thực hiện phép tính logic Xor trên từng cặp bít (tương ứng về vị trí) của [Toán hạng nguồn] với [Toán hạng đích], kết quả lưu vào [Toán hạng đích].

Lệnh Xor thường dùng để so sánh (bằng nhau hay khác nhau) giá trị của hai toán hạng, nó cũng giúp phát hiện ra các bít khác nhau giữa hai toán hạng này.

-     Lệnh Test: Tương tự như lệnh And nhưng không ghi kết quả vào lại [Toán hạng đích], nó chỉ ảnh hưởng đến các cờ CF, OF, ZF,...

Ví dụ 1:

                    Mov        Al,0                 ; Al ß0

                    Not          Al                    ; Al = Not Al. Tức là Al = 0FFh

Ví dụ 2: Cho AL = (10010011)2, BL = (11001100)2.

-             And         Al, Bl              ; Al ß 10010011 And 11001100. Al =

-             And         Al, 0                ; Al ß 10010011 And 0. Al =

-             Or            Bl, Al              ; Bl ß 11001100 Or 10010011. Al =

-             Or           Bl, 4                ; Bl ß 11001100 Or 100. Al =

-             Xor         Al, Bl              ; Al ß 10010011 Xor 11001100. Al =

-              Xor         Bl, Bl              ; Bl ß 11001100 Xor 11001100. Bl = 00000000

Ví dụ 3: Để xóa nội dung thanh ghi nào đó, trong hợp ngữ ta có thể sử dụng một trong các lệnh sau đây:

-             Mov        Ax, 0

-             Sub         Ax, Ax

-             Xor         Ax, Ax            ; các cặp bít giống nhau thì đều = 0

Ví dụ 5: Lệnh sau đây sẽ xóa (= 0) các bít 3 và 6 của thanh ghi AL, các bít khác giữ nguyên giá trị:

-             And         AL, 10110111b        ; AL ßAL And 10110111

Trong trường hợp này: dãy bít  10110111 được gọi là dãy bít mặt nạ, các bít 3 (= 0) và 6 (= 0) được gọi là các bít mặt nạ. Như vậy muốn làm cho bít nào = 0 ta cho bít mặt nạ tương ứng với nó = 0, các bít còn lại trong dãy bít mặt nạ đều = 1.      

Ví dụ 6:  Lệnh sau đây sẽ thiết lập (= 1) các bít 3 và 6 của thanh ghi AL, các bít khác giữ nguyên giá trị:

-             Or            AL, 01001000b        ; AL ßAL Or 01001000

Trong trường hợp này: dãy bít 01001000 được gọi là dãy bít mặt nạ, các bít 3 (= 1) và 6 (= 1) được gọi là các bít mặt nạ. Như vậy muốn làm cho bít nào = 1 ta cho bít mặt nạ tương ứng với nó = 1, các bít còn lại trong dãy bít mặt nạ đều = 0.      

Ví dụ 7: Lệnh sau đây sẽ kiểm tra bít 12 của thanh ghi AX là = 0 hay = 1:

-             And         AX, 0001000000000000b              ; AX ßAX And 0001000000000000

Với dãy bít mặt nạ như trên, nếu bít 12 của Ax = 0 thì kết quả: Ax = 0, nếu bít 12 của Ax = 1 thì kết quả: Ax <> 0.

Cách dùng lệnh And như trên để kiểm tra bít ít được sử dụng, vì nó làm thay đổi giá trị của thanh ghi cần kiểm tra (điều này có thể khắc phục bằng lệnh Test) và phải thêm bước kiểm tra giá trị của Ax (= 0 hay <> 0) mới biết được kết quả kiểm tra. Ngoài ra, nó cũng chỉ kiểm tra được 1 bít.

Trong thực tế người ta thường sử dụng kết hợp giữa các lệnh dịch bít, lệnh quay bít, lệnh nhảy,... để kiểm tra các bít trong một thanh ghi.

7. Lệnh chuyển dữ liệu qua cổng: IN và OUT

Cú pháp:

IN           AL, <Địa chỉ cổng>      
OUT       <Địa chỉ cổng>, AL
Trong đó:<Địa chỉ cổng> chính là số hiệu cổng (port) mà lệnh nhận nhiệm vụ trao đổi dữ liệu qua nó. Địa chỉ cổng có thể được ghi trực tiếp dưới dạng một hằng số hoặc được ghi thông qua thanh ghi Dx.

Tác dụng:

-     LênhIn (Input): Đọc một lượng dữ liệu 8 bít từ cổng được chỉ ra ở <Địa chỉ cổng> đưa vào lưu trữ trong thanh ghi AL.

Nếu địa chỉ cổng nằm trong giới hạn từ 0 đến FF (hệ thập lục phân) thì có thể viết trực tiếp trong câu lệnh, nếu địa chỉ cổng lớn hơn FF thì ta phải dùng thanh ghi Dx để chỉ định địa chỉ cổng.

-     LệnhOut (Output): Gởi một lượng dữ liệu 8 bít từ thanh ghi AL ra cổng được chỉ ra ở <Địa chỉ cổng>. Tương tự lệnh In, địa chỉ cổng có thể được viết trực tiếp trong câu lệnh hoặc thông qua thanh ghi Dx.

Ví dụ 1:

-             In             Al, 40h                       ;                    

-             Mov        Dx, 3B0h                   ;

               In             Al, Dx                         ;

Ví dụ 2:

-             Out          40h, Al                       ;                    

-             Mov        Dx, 3B0h                   ;

               Out          Dx, Al                         ;

Ví dụ 3:

Các khai báo hằng:

                    DAT        EQU                13h     ;

                    POR        EQU                7Ch     ;

Các lệnh:

        Mov        Al, POR          ;

        Mov        Bl, DAT          ;

        Out          Bl, Al              ;



Mới hơn Cũ hơn

Biểu mẫu liên hệ