Sau khi thực hiện lệnh cmp thì kết quả được lưu ở đâu?

Lệnh so sánh:

Cú pháp:      Cmp     [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, biến, thanh ghi hay ô nhớ. [Toán hạng đích] không thể là hằng số. [Toán hạng đích] và [Toán hạng nguồn] không thể đồng thời là ô nhớ.
  • Tác dụng: Lệnh Cmp [Compare] được sử dụng để so sánh giá trị/nội dung của [Toán hạng đích] so với [Toán hạng nguồn]. Tương tự như lệnh Sub, nó lấy [Toán hạng đích] trừ đi [Toán hạng nguồn] nhưng kết quả không làm thay đổi [Toán hạng đích] mà chỉ làm thay đổi giá trị của một số cờ hiệu: CF, ZF, OF,...

Kết quả so sánh của lệnh Cmp là: [Toán hạng đích] > [Toán hạng nguồn]; [Toán hạng đích] ≥[Toán hạng nguồn]; [Toán hạng đích] < [Toán hạng nguồn]; [Toán hạng đích] ≤[Toán hạng nguồn]; [Toán hạng đích] = [Toán hạng nguồn]; [Toán hạng đích] ≠ [Toán hạng nguồn];... mỗi kết quả sẽ tác động [0 →1, 1→0] đến một cờ tương ứng cụ thể nào đó.

Do đó, để biết được kết quả so sánh chương trình phải sử dụng các lệnh kiểm tra cờ [đó là cá lệnh nhảy], và chúng phải được đặt ngay sau lệnh so sánh. Như vậy lệnh Cmp sẽ không có ý nghĩa khi nó đứng độc lập.

Có thể nói ngược lại, lệnh Cmp được sử dụng để cung cấp điều kiện nhảy [thay đổi giá trị các cờ] cho các lệnh nhảy có điều kiện.    

Ví dụ 1:

  • Cmp        Ax, Bx                        ; so sánh giá tị thanh ghi Ax với Bx
  • Cmp        Ax, 20                        ; so sánh giá trị thanh ghi Ax với 20
  • Cmp        Ax, [SI]                      ; so sánh Ax với nội dung ô nhớ được chỉ bởi SI

Ví dụ 2:         

  • Cmp        Al, ‘A’                        ; so sánh giá trị thanh ghi Al với ‘A’
  • Cmp        Al, Var1                     ; so sánh giá trị thanh ghi Al với giá trị biến Var1

Tất cả cá lệnh Cmp ở trên điều không có ý nghĩa, vì nó không cho biết kết quả so sánh một cách trực tiếp mà phải ánh thông qua các cờ.

Lệnh Cmp không thể sử dụng để so sánh hoặc kiểm tra giá trị của các cờ.

Các lệnh nhảy

Lệnh nhảy không điều kiện:

Cú pháp:   Jmp       

  • Trong đó:  có thể là nhãn của một lệnh, tên của một thủ tục hoặc có thể là một thanh ghi, một ô nhớ [đã được định nghĩa] nào đó. cũng có thể là một biến nào đó, giá trị của nó thường là địa chỉ của một ô nhớ trong đoạn Code.
  • Tác dụng: Khi gặp lệnh này chương trình chuyển điều khiển [nhảy đến] đến thực hiện lệnh sau mà không phụ thuộc vào bất kỳ điều kiện nào.

Cơ chế thực hiện của lệnh Jmp là thay đổi nội dung của cặp thanh ghi con trỏ lệnh CS:IP. CS:IP mới sẽ là địa chỉ của lệnh sau trong bộ nhớ.

Lệnh Jmp có 3 dạng: Short, Near và Far. Đối với dạng Short và Far thì chỉ có thanh ghi IP bị thay đổi khi lệnh thực hiện, ngược lại, với dạng Far, khi lệnh thực hiện thì cả thanh ghi IP và thanh ghi đoạn CS đều bị thay đổi. Hay nói cách khác: Đối với dạng Short và Near thì lệnh Jmp và phải nằm trong cùng Segment nhớ, ngược lại, với dạng Far thì lệnh Jmp và có thể nằm ở các Segment nhớ khác nhau.

Ví dụ 1:

                    Start:

                          Jmp               Main

                          TieuDe         DB      ‘Khoa CNTT – DHHH’

                    Main       Proc

                  ..................

                    Main       Endp

                    End            Start

Ví dụ 2:

  • Jmp         short   Main

  • Jmp         Ax

  • Jmp         word      PTR     [BX]

  • Jmp         dword    PTR     [BX]

Ví dụ 3:

        Reset      DD      5BE000F0h

        Jmp         Reset 

Ví dụ 4:

                    Mov        Ax, 15

                    Mov        Bx, 20

                    Jmp         TTong

                    Add         Ax, Bx

              TTong:        

                    Sub         Ax, Bx

                    Mov        Cx, Ax

Kết thúc đoạn lệnh trên Cx = Ax = -5, vì lệnh Add      Ax, Bx không được thực hiện. Khi gặp lệnh Jmp      TTong chương trình nhảy đến thục hiện lệnh sau nhãn TTong, đó chính là lệnh Sub      Ax, Bx.                                   

Lệnh nhảy có điều kiện:                   

Cú pháp chung:                  

  • Trong đó: : Tương tự như lệnh Jmp.
  • Tác dụng: Khi gặp một lệnh nhảy có điều kiện, đầu tiên chương trình sẽ kiểm tra điều kiện nhảy của nó, nếu thỏa mãn thì sẽ nhảy đến thực hiện lệnh ở , nếu không thì bỏ qua không thực hiện lệnh nhảy này.

Điều kiện nhảy của các lệnh nhảy này chính là sự thay đổi giá trị của các cờ hiệu, do đó để tạo điều kiện nhảy cho một lệnh nhảy xác định thì chương trình phải làm thay đổi giá trị của cờ hiệu tương ứng với nó. Chương trình thường dùng các lệnh địch bít, quay bít, so sánh,... để làm thay đổi giá trị các cờ hiệu để tạo điều kiện nhảy cho các lệnh nhay. Cách đơn giản nhất là sử dụng lệnh Cmp ngay trước lệnh nhảy.   

Sau đây là các lệnh nhảy có điều kiện với dữ liệu có dấu:

  • Lệnh JG:             Nhảy nếu [Đích] > [Nguồn] ; [SF = 0F và ZF = 0]
  • Lệnh JL:             Nhảy nếu [Đích] < [Nguồn] ; [SF 0F]
  • Lệnh JGE:          Nhảy nếu [Đích] ≥[Nguồn] ; [SF = 0F]
  • Lệnh JLE:           Nhảy nếu [Đích] ≤[Nguồn] ; [CF 0F và ZF = 1]  
  •  ...

Trong đó: [Đích] và [Nguồn] chính là hai toán hạng: [Toán hạng đích] và [Toán hạng nguồn] trong lệnh Cmp đứng ngay trước lệnh nhảy. Tức là, chương trình sử dụng lệnh Cmp để tạo điều kiện nhảy cho các lệnh này. Cụ thể: lệnh nhảy có thực hiện được hay không [có chuyển điều khiển đến hay không] phụ thuộc vào giá trị của [Đích] và [Nguồn] trong lệnh Cmp đứng ngay trước nó.

Với việc sử dụng lệnh Cmp để tạo điều kiện nhảy cho các lệnh nhảy thì ta không cần quan tâm đến các cờ điều kiện nhảy của chúng.

Sau đây là các lệnh nhảy có điều kiện với dữ liệu không dấu:

  • Lệnh JA:            Nhảy nếu [Đích] > [Nguồn] ; [CF = 0 và ZF = 0]
  • Lệnh JB:              Nhảy nếu [Đích] < [Nguồn] ; [CF = 0]
  • Lệnh JNA:          Nhảy nếu [Đích] không lớn hơn [Nguồn]; [CF =1 or ZF =1]
  • Lệnh JNB:           Nhảy nếu [Đích] không nhỏ hơn [Nguồn] ; [CF = 0]

Các lệnh nhảy với dữ liệu có dấu có thể áp dụng với các dữ liệu không dấu.

Sau đây là các lệnh nhảy có điều kiện dùng chung:

  • Lệnh JC:              Nhảy nếu cờ CF = 1
  • Lệnh JNC:           Nhảy nếu cờ CF = 0
  • Lệnh JZ:              Nhảy nếu cờ ZF = 1
  • Lệnh JNZ:           Nhảy nếu cờ ZF = 0
  • Lệnh JE:              Nhảy nếu [Đích] = [Nguồn]; Tương tự JZ; [ZF = 1]
  • Lệnh JNE:           Nhảy nếu [Đích] ≠[Nguồn]; Tương tự JNZ; [ZF = 0]
  • ... [2 - 150]

Với các lệnh này, chương trình thường sử dụng các lệnh dịch bít hoặc lệnh quay bít để tạo điều kiện nhảy nó.

Ví dụ 1a: Dãy lệnh sau đây thực hiện việc gán giá trị cho thanh ghi Cx dựa vào giá trị của thanh ghi Ax và Dx:

                    Mov        Ax, 12

                    Mov        Dx, 25

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

                    Cmp        Ax, Dx                        ; Ax ? Bx

                    Jg            Nhan1                       ; nếu Ax > Dx

                    Jle           Nhan2                     

               Nhan1:

                    Mov        Cx, Ax

                    Jmp         Tiep_Tuc                

               Nhan2:                                        

                    Mov        Cx, Dx

                    Jmp        Tiep_Tuc                  

                Tiep_Tuc:

                    Mov        Bx, Cx

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

Có thể thấy, ở đây không cần dùng lệnh Jle    Nhan2, vì nếu Ax không lớn hơn Dx thì chắc chẵn nó sẽ nhỏ hơn hoặc bằng Dx. Ngoài ra cũng không cần dùng lệnh Jmp     Tiep_Tuc sau nhãn Nhan2, vì việc chuyển đến lệnh sau nhãn Tiep_Tuc ở đây là tất nhiên. Vì thế đoạn lệnh trên có thể được viết rút gọn như trong Ví dụ 1b sau đây.  

Ví dụ 1b: Dãy lệnh sau đây là trường hợp rút gọn của dãy lệnh trên:

                    Mov        Ax, 12

                    Mov        Dx, 25

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

                    Cmp        Ax, Dx

                    Jg            Nhan1                       ; nếu Ax > Dx

                    Mov        Cx, Dx                        ; khi Ax ≤Dx

                    Jmp        Tiep_Tuc

               Nhan1:

                    Mov        Cx, Ax                        ; khi Ax > Dx

                Tiep_Tuc:

                    Mov        Bx, Cx

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

Trong cả hai ví dụ trên: khi kết thúc, Bx =  Cx = Dx = 25. Nhưng nếu cho
Ax = 120 [Ax > Bx] thì Bx = Cx = Ax = 120.

Ví dụ 2: Giả sử tại địa chỉ 0A000:0100 trong bộ nhớ có chứa một mảng các số nguyên kiểu byte, gồm 100 phần tử [100 byte].

Các lệnh sau đây tính tổng của các phần tử trong mảng này mà giá trị của nó lớn hơn 123. Kết quả chứa ở thanh ghi Dx.

                    Mov        Ax, 0A000h

                    Mov        DS, Ax                          

                    Mov        DI, 0100h                        

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

                    Mov        Dx, 0                                 

                    Mov        Cx, 100                               

              Lap_TT:

                    Mov        Al, Byte PTR DS:[DI]        

                    Cmp        Al, 123                             

                    Jle           Tiep_Tuc                          

                    Add         Dx, Al                       

              Tiep_Tuc:

                    INC         DI                                ; trỏ đến phần tử kế tiếp

                    Loop       Lap_TT                      ; lặp lại: kiển tra và tính tổng

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

Ví dụ 3: Giả sử tại địa chỉ 0C000:00120 trong bộ nhớ có chứa một xâu kí tự, xâu này được kết thúc bởi giá trị 0 [số 0].

Các lệnh sau đây sẽ đếm xem xâu nói trên gồm bao nhiêu kí tự. Kết quả ghi vào ô nhớ ngay trước vùng nhớ chứa xâu này:

                    Mov        Ax, 0C000h

                    Mov        ES, Ax                              

                    Mov        DI, 00120h           

                    Mov        SI, DI

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

                    Mov        Dx, 0                                 

              Lap_Dem:

                    Mov        Al, Byte PTR ES:[DI]      

                    Cmp        Al, 0                                        ; so sánh Al với 0

                    Je            KetThuc                                 ; nếu Al = 0: đã đến cuối xâu

                    INC         Dx                                           ; khi Al 0: đếm

                    INC         DI                                            ; trỏ đến kí tự kế tiếp

                    Jmp         Lap_Dem                            ; lặp lại: kiển tra và đếm

              KetThuc:                 

                    Mov        Byte PTR DS:[SI - 1], Dx

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

Ví dụ 4: Các lệnh sau đây in nội dung bản bản ASCII ra màn hình, nhưng không in ra các kí tự có mã 07h, 0Ah, 0Dh.

                    Mov        Cx, 256

                    Mov        Ah, 02                  

                    Mov        Dl, 0          

              Lap_In:

                    Cmp        Dl, 07h    

                    Je            TTuc            

                    Cmp        Dl, 0Ah         

                    Je            TTuc

                    Cmp        Dl, 0Dh

                    Je            TTuc

                    Int           21h              

              TTuc:

                    INC         DL

                    Loop       Lap_In

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

Ví dụ 5: Các lệnh sau đây cho phép nhập một xâu kí tự bất kỳ, dài không quá 200 kí tự, từ bàn phím vào biến XauNhap. Sau đó copy các kí tự là chữ cái in hoa trong xâu vừa nhập vào biến XauHoa.

              Trước hết chương trình phải khai báo các biến:

                    XauNhap           DB      200, 0, 200 Dup [‘ ’]           

                    XauHoa             DB      200 Dup [‘ ’]

              Các lệnh:

                    Mov        Ax, Seg XauNhap

                    Mov        DS, XauNhap

                    Mov        Dx, Offset XauNhap

                    Mov        Ax, Seg XauHoa

                    Mov        ES, XauHoa

                    Mov        DI, Offset XauHoa

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

                    Mov        Ah, 0Ah                   

                    Int           21h

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

                    Mov        Cx, 0

                    Mov        Cl, XauNhap[1]     

                    Mov        SI, Dx                 

                    Add         SI, 2                     

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

              Lap_Copy:

                    Mov        Al, DS:[SI]              

                    Cmp        Al, ‘A’               

                    Jl             TTuc                     

                    Cmp        Al, ‘Z’              

                    Jg            TTuc                     

                    Mov        ES:[DI], Al          

                    INC         DI                      

              TTuc:

                    INC         SI                                 ;

                    Loop       Lap_Copy

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

Nên nhớ, trong bảng mã ASCII các kí tự là chữ cái in hoa nằm ở những vị trí liên tiếp nhau: A, B, C, ..., Z, chúng có mã lần lượt là 65, 66, 67, ..., 90.

Ví dụ 6: Giả sử tại địa chỉ 0F000:FFFE trong bộ nhớ ROM-BIOS có chứa một byte dữ liệu. Byte này cho biết loại của máy tính đang sử dụng. Cụ thể, nếu byte này: chứa trị 0FBh: máy PC/XT; chứa trị 0FCh: máy PC/AT; chứa trị 0FFh: máy PC classic;...

Các lệnh sau đây cho biết máy tính đang sử dụng thuộc loại máy nào:

Trước hết chương trình phải khai báo các biến trả lời:

        TB1         DB      ‘Day la may PC/XT.$’  

        TB2         DB      ‘Day la may PC/AT.$’

        TB3         DB      ‘Day la may PC classic.$’

Các lệnh:

        Mov        Ax, 0F000h

        Mov        ES, Ax

        Mov        SI, 0FFFEh

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

        Mov        Al, Byte PTR ES:[SI]

        Cmp        Al, 0FBh

        Je            TraLoi1

        Cmp        Al, 0Fch

        Je            TraLoi2

        Cmp        Al, 0Ffh

        Je            TraLoi3

        ...

TraLoi1:

        Mov        Ax, Seg TB1

        Mov        DS, Ax

        Lea          Dx, Offset TB1

        Mov        Ah, 09

        Int           21h

        Jmp         KetThuc

TraLoi2:

        Mov        Ax, Seg TB2

        Mov        DS, Ax

        Lea          Dx, Offset TB2

        Mov        Ah, 09

        Int           21h

        Jmp         KetThuc

TraLoi1:

        Mov        Ax, Seg TB3

        Mov        DS, Ax

        Lea          Dx, Offset TB3

        Mov        Ah, 09

        Int           21h

        Jmp         KetThuc

        .....

KetThuc:

        Mov        Ah, 4Ch

        Int           21h

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

Có thể nói, ví dụ trên đây là một thao tác điển hình trong lập trình hợp ngữ. Nó cũng cho thấy chức năng và thế mạnh của ngôn ngữ này. Đây cũng là mục tiêu mà người lập trình hợp ngữ nhắm tới. Việc truy xuất vào các vùng nhớ dữ liệu để lấy các byte/word thông tin cấu hình hệ thống là một yêu cầu cơ bản với các ngôn ngữ lập trình cấp thấp, và nó được thực hiện một cách khá đơn giản trong ngôn ngữ hợp ngữ. Ví dụ trên đây cũng cho thấy nguyên tắc để làm việc này.

Video liên quan

Chủ Đề