Bài giảng Cấu trúc máy tính - Chương 5: Lập trình hợp ngữ với 8088

pdf 161 trang ngocly 50
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Cấu trúc máy tính - Chương 5: Lập trình hợp ngữ với 8088", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_cau_truc_may_tinh_chuong_5_lap_trinh_hop_ngu_voi_8.pdf

Nội dung text: Bài giảng Cấu trúc máy tính - Chương 5: Lập trình hợp ngữ với 8088

  1. Cấu trúc máy tính Chƣơng 5 LẬP TRÌNH HỢP NGỮ VỚI 8088 516
  2. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 517
  3. 5.1. Mở đầu về lập trình hợp ngữ 1. Các loại ngôn ngữ lập trình 2. Cú pháp của hợp ngữ 3. Dữ liệu của chƣơng trình 4. Khai báo biến 5. Khai báo hằng 6. Một số lệnh cơ bản 7. Cấu trúc chƣơng trình 8. Chƣơng trình EXE và COM 9. Vào-ra đơn giản 10. Các ví dụ 11. Dịch và chạy chƣơng trình 518
  4. 1. Các loại ngôn ngữ lập trình . Ngôn ngữ máy:  Chỉ đƣợc biểu diễn bằng số nhị phân.  Bộ vi xử lý chỉ hiểu đƣợc các chƣơng trình mã máy.  Con ngƣời rất khó khăn để tạo lập hay đọc hiểu chƣơng trình ngôn ngữ máy. . Hợp ngữ (Assembly Language):  Là ngôn ngữ lập trình bậc thấp (gần ngôn ngữ máy nhất).  Đƣợc xây dựng trên cơ sở ký hiệu tập lệnh của bộ vi xử lý tƣơng ứng.  Phụ thuộc hoàn toàn vào bộ vi xử lý cụ thể. . Ngôn ngữ lập trình bậc cao:  Gần với ngôn ngữ tự nhiên hơn.  Đƣợc xây dựng độc lập với cấu trúc của máy tính. 519
  5. Lập trình với hợp ngữ . Ƣu điểm:  Can thiệp sâu vào cấu trúc hệ thống.  Hiểu sâu hơn về hệ thống.  Chƣơng trình mã máy tƣơng ứng sẽ ngắn hơn, thƣờng nhanh hơn và tốn ít bộ nhớ hơn. . Nhƣợc điểm:  Khó học vì gần với mã máy.  Chƣơng trình nguồn dài, không thích hợp để xây dựng những chƣơng trình lớn. Kết hợp ngôn ngữ lập trình bậc cao với hợp ngữ. 520
  6. Chƣơng trình dịch hợp ngữ . Đƣợc gọi là ASSEMBLER . Một số chƣơng trình dịch hợp ngữ cho IBM-PC:  MASM – Microsoft Marco Assembler: . Các tệp: MASM.EXE, LINK.EXE, EXE2BIN.EXE  TASM – Turbo Assembler: . Các tệp: TASM.EXE, TLINK.EXE 521
  7. Các bƣớc lập trình . Bƣớc 1: Phát biểu bài toán . Bƣớc 2: Xây dựng thuật giải . Bƣớc 3: Viết mã chƣơng trình . Bƣớc 4: Dịch và sửa lỗi cú pháp . Bƣớc 5: Chạy thử và hiệu chỉnh chƣơng trình 522
  8. Các cấu trúc lập trình cơ bản . Cấu trúc tuần tự . Cấu trúc rẽ nhánh . Cấu trúc lặp 523
  9. 2. Cú pháp của hợp ngữ . Chƣơng trình hợp ngữ gồm các dòng lệnh, mỗi lệnh viết trên một dòng, mỗi dòng có thể là:  Lệnh của bộ vi xử lý (instruction)  Chỉ dẫn của chƣơng trình dịch ASSEMBLER . Các lệnh hợp ngữ không phân biệt chữ hoa, chữ thƣờng. . Khi dịch thành mã máy thì chỉ có các lệnh của bộ vi xử lý mới đƣợc dịch. . Cấu trúc của một dòng lệnh : Tên Thao tác Toán hạng Chú thích ( Name Operation Operand Comment ) . Giữa các trƣờng phải có ít nhất một dấu cách (hoặc TAB) . Ví dụ: MAIN PROC BAT_DAU: MOV CX, 50 ; khoi tao bo dem 524
  10. Ý nghĩa các trƣờng trong lệnh . Trƣờng tên:  Sử dụng cho: nhãn lệnh, tên thủ tục, tên biến  Quy ƣớc đặt tên: dài từ 1 đến 31 ký tự, cho phép sử dụng: . Chữ cái (không phân biệt chữ hoa và chữ thƣờng) . Chữ số (không đƣợc dùng làm ký tự đầu tiên) . Các ký tự khác: ?, @, $, %, . (dấu . chỉ đƣợc dùng khi nó là ký tự đầu tiên). 525
  11. Ý nghĩa các trƣờng trong lệnh (tiếp) . Trƣờng thao tác:  Nếu là lệnh của vi xử lý thì đó chính là mã lệnh (MOV, CALL, ADD, ).  Nếu là chỉ dẫn thì đó là lệnh giả của chƣơng trình dịch (Pseudo-op). 526
  12. Ý nghĩa các trƣờng trong lệnh (tiếp) . Trƣờng toán hạng:  Đối với lệnh thì toán hạng xác định dữ liệu bị tác động bởi mã lệnh.  Một lệnh có thể có 0, 1, 2 toán hạng.  Ví dụ: . MOV CX,5 ; 2 toán hạng . INC AX ; 1 toán hạng . NOP ; 0 toán hạng  Đối với lệnh giả thì toán hạng cho thêm thông tin cho lệnh giả đó. . Trƣờng chú thích:  Bắt đầu bằng dấu ";" theo sau đó là lời giải thích. 527
  13. 3. Dữ liệu của chƣơng trình . Hợp ngữ cho phép biểu diễn dƣới dạng:  Số nhị phân: 1011b, 1011B,  Số thập phân: 35, 35d, 35D,  Số Hexa: 4Ah, 0ABCDh, 0FFFFH,  Kí tự: "A", 'HELLO', "Bach Khoa", . Tất cả các kiểu dữ liệu trên sau đó đều đƣợc trình dịch Assembler dịch ra mã nhị phân. . Mỗi kí tự đƣợc dịch thành mã ASCII tƣơng ứng  Chƣơng trình không phân biệt 'A' với 41h hay 65 528
  14. Các chỉ thị giả định số liệu Chỉ thị giả Biểu diễn DB Định nghĩa byte DW Định nghĩa word (2 byte) DD Định nghĩa double word (4 byte) DQ Định nghĩa quadword (8 byte liên tiếp) DT Định nghĩa tenbyte (10 byte liên tiếp) 529
  15. 4. Khai báo biến . Biến Byte:  Khai báo: Ten_bien DB Gia_tri_khoi_dau Ten_bien DB ?  Ví dụ: Age DB 25 ; Khởi tạo giá trị ban đầu Age = 25 Alpha DB ? ; Ban đầu Alpha không xác định  Khoảng xác định của biến Byte: . Số không dấu: [0, 255] . Số có dấu: [-128, 127] 530
  16. Khai báo biến (tiếp) . Biến Word:  Khai báo: Ten_bien DW Gia_tri_khoi_dau Test 1111 1011 Ten_bien DW ? 1111 1111 Đ ị a  Ví dụ: c Beta h 34h ỉ t ă Test DW -5 ; -5 = 1111111111111011b n g 12h d ầ Beta DW 1234h ; 1234h = 0001001000110100b n XYZ XYZ DW ? ?  Khoảng xác định của biến Word: . Số không dấu: [0, 65535] . Số có dấu: [-32768, 32767] 531
  17. Khai báo biến (tiếp) . Biến mảng: MangB 10h  Mảng Byte: 20h MangB DB 10h, 20h, 30h, 40h 30h Buffer DB 100 dup (?) 40h  Mảng Word: MangW DW -12, 127, 0A48Bh MangW 1111 0100  Mảng kí tự: 1111 1111 . Thực chất là mảng Byte 0111 1111 . Ví dụ: 2 cách viết sau là tƣơng đƣơng 0000 0000 M DB 'ABC' 1000 1011 M DB 41h, 42h, 43h 1010 0100 532
  18. 5. Khai báo hằng . Cú pháp: Ten_hang EQU Gia_tri . Ví dụ: TenTruong EQU 'BACH KHOA' CR EQU 13 LF EQU 10 ThongBao DB 'DAI HOC', CR, LF, TenTruong DoDaiChuoi EQU $ - offset ThongBao . Hằng không đƣợc cấp phát ngăn nhớ 533
  19. 6. Một số lệnh cơ bản . Lệnh MOV (Move): MOV đích, nguồn  Copy dữ liệu từ toán hạng nguồn sang toán hạng đích  Kích thƣớc của 2 toán hạng phải giống nhau Ví dụ: Thanh ghi Thanh ghi MOV AX, BX Đích Ngăn nhớ Nguồn chung đoạn MOV AL, 'A' Thanh ghi Có Có Có MOV BH, 120 chung ; MOV DS, 0A000h ; SAI Thanh ghi đoạn Có Có Có MOV AX, 0A000h Ngăn nhớ Có Có Không MOV DS, AX Hằng Có Không Có ; MOV Bien_2, Bien_1; SAI MOV AL, Bien_1 MOV Bien_2, AL 534
  20. Một số lệnh cơ bản (tiếp) . Lệnh XCHG (Exchange): XCHG đích, nguồn  Hoán đổi nội dung 2 toán hạng cho nhau  Kích thƣớc của 2 toán hạng phải giống nhau Ví dụ: Thanh ghi Đích Ngăn nhớ XCHG AX, BX Nguồn chung XCHG AH, Byte_1 Thanh ghi Có Có XCHG Word_1, BX chung Ngăn nhớ Có Không ; XCHG Word_1, Word_2 ; SAI MOV AX, Word_1 MOV BX, Word_2 MOV Word_1, BX MOV Word_2, AX 535
  21. Các lệnh ADD và SUB . Cú pháp: ADD đích, nguồn ; đích  đích + nguồn SUB đích, nguồn ; đích  đích - nguồn Ví dụ: Thanh ghi MOV AX, 50 Đích Ngăn nhớ Nguồn chung MOV BX, 30 Thanh ghi ADD BX, 10 ; BX = 40 Có Có chung SUB AX, BX ; AX = 10 Ngăn nhớ Có Không ; ADD Byte_1, Byte_2 ; SAI MOV AL, Byte_1 Hằng Có Có ADD AL, Byte_2 MOV Byte_1, AL 536
  22. Các lệnh INC, DEC và NEG . Cú pháp: INC đích ; đích  đích + 1 DEC đích ; đích  đích – 1 NEG đích ; đích  - đích (lấy bù 2 của đích) Toán hạng đích là thanh ghi hoặc ngăn nhớ . Ví dụ: MOV AX, 20 ; AX = 20 INC AX ; AX = 21 = 0000000000010101b NEG AX ; AX = 1111111111101011b DEC AX ; AX = FFEAh 537
  23. Bài tập Giả sử A và B là các biến kiểu Word, hãy thực hiện các phép gán sau đây bằng hợp ngữ: 1.A := B 2.A := 10 – A; 3.A := B – A * 2; 538
  24. 7. Cấu trúc chƣơng trình . Chƣơng trình mã máy khi đƣợc thực thi sẽ chiếm 3 vùng nhớ cơ bản trong bộ nhớ chính:  Vùng nhớ lệnh (Code)  Vùng dữ liệu (Data)  Vùng ngăn xếp (Stack) . Chƣơng trình hợp ngữ cũng đƣợc tổ chức tƣơng tự nhƣ vậy. . Mã lệnh, dữ liệu và ngăn xếp đƣợc cấu trúc nhƣ các đoạn chƣơng trình. 539
  25. Các chế độ bộ nhớ . Kích thƣớc của đoạn mã và dữ liệu trong chƣơng trình đƣợc chỉ định bằng cách chỉ ra chế độ bộ nhớ nhờ chỉ thị biên dịch .MODEL . Cú pháp: .Model Kieu_bo_nho . Chế độ bộ nhớ thƣờng dùng khi lập trình hợp ngữ là SMALL. 540
  26. Các chế độ bộ nhớ (tiếp) Kiểu Mô tả TINY Mã lệnh và dữ liệu gói gọn trong một đoạn Mã lệnh trong một đoạn SMALL Dữ liệu trong một đoạn Mã lệnh chiếm nhiều hơn một đoạn MEDIUM Dữ liệu trong một đoạn Mã lệnh trong một đoạn COMPACT Dữ liệu chiếm nhiều hơn một đoạn Mã lệnh chiếm nhiều hơn một đoạn LARGE Dữ liệu chiếm nhiều hơn một đoạn Không có mảng nào lớn hơn 64 KB Mã lệnh chiếm nhiều hơn một đoạn HUGE Dữ liệu chiếm nhiều hơn một đoạn Các mảng có thể lớn hơn 64 KB 541
  27. Đoạn dữ liệu (Data Segment) . Đoạn dữ liệu chứa tất cả các khai báo biến. . Các khai báo hằng cũng thƣờng để ở đây. . Để khai báo đoạn dữ liệu ta dùng chỉ thị .DATA . Ví dụ: .Data Bien_1 db 10 Bien_2 dw 0FEDCh TBao db 'Xin chao ban', '$' Nam equ 2006 542
  28. Đoạn ngăn xếp (Stack Segment) . Cú pháp: .STACK Kich_thuoc . Kich_thuoc: là số Byte của Stack (nếu không chỉ định Kich_thuoc thì ngầm định là 1KB) . Ví dụ: .Stack 100h 543
  29. Đoạn mã lệnh (Code Segment) . Đoạn mã lệnh đƣợc khai báo với chỉ thị .CODE . Bên trong đoạn mã, các dòng lệnh đƣợc tổ chức dƣới dạng 1 chƣơng trình chính và các chƣơng trình con (nếu cần). . Ví dụ: .Code Main Proc ; các lệnh của CT chính Main EndP 544
  30. Cấu trúc chƣơng trình thông dụng .Model Small .Stack 100h .Data ; khai báo biến, hằng ở đây .Code Main Proc ; các lệnh của chƣơng trình chính ở đây Main EndP ; các chƣơng trình con khác ở đây End Main 545
  31. 8. Chƣơng trình EXE và COM . Có 2 loại chƣơng trình mã máy có thể thực thi đƣợc trong DOS, đó là chƣơng trình .EXE và .COM  Chƣơng trình EXE: . Ở đầu file chƣơng trình có 1 vùng thông tin gọi là Header . Khi thực thi, CS, DS và SS trỏ đến 3 phân đoạn khác nhau  Chƣơng trình COM: . File chƣơng trình có kích thƣớc nhỏ gọn (< 64KB), chứa cả mã lệnh và dữ liệu . Khi thực thi, CS, DS và SS trỏ đến cùng 1 phân đoạn . DOS sẽ chọn 1 địa chỉ phân đoạn gọi là PSP (Program Segment Prefix) làm địa chỉ cơ sở để tải chƣơng trình. . PSP thƣờng có kích thƣớc là 256 Byte (=100h), chứa các thông tin liên quan đến chƣơng trình đƣợc thực thi. 546
  32. Thực thi chƣơng trình EXE . Nội dung file EXE đƣợc tải vào bộ nhớ bắt đầu từ địa chỉ PSP:0100h. . Sau đó các địa chỉ phân đoạn đƣợc tái định vị nhờ các thông tin đƣợc đọc từ Header nằm ở đầu file EXE. . Sau khi chƣơng trình EXE lấy quyền điều khiển:  DS và ES trỏ đến PSP (chứ không phải đoạn dữ liệu) => Trong chƣơng trình hợp ngữ ta cần thay đổi DS (và ES) để trỏ đến đúng đoạn dữ liệu.  CS, IP, SS và SP đƣợc đặt theo những giá trị chỉ ra trong EXE Header. 547
  33. Khung chƣơng trình EXE .Model Small .Stack 100h .Data ; khai báo biến và hằng ở đây .Code Main Proc mov ax, @Data mov ds, ax ; khởi tạo DS trỏ đến đoạn Data ; mov es, ax ; bỏ dấu ; để khởi tạo ES = DS ; thân chương trình mov ah, 4Ch ; hàm thoát về DOS int 21h Main EndP End Main 548
  34. Thực thi chƣơng trình COM . Nội dung file COM đƣợc tải vào bộ nhớ bắt đầu từ địa chỉ PSP:0100h. . Sau khi file .COM đƣợc nạp vào bộ nhớ:  CS, DS, ES và SS đƣợc đặt cùng giá trị với PSP  SP trỏ đến cuối đoạn PSP (thƣờng thì SP = 0FFFEh)  IP đƣợc đặt là 100h 549
  35. Khung chƣơng trình COM .Model Tiny Offset .Code 0000h Org 100h Đoạn đầu chƣơng trình (PSP) Start: 0100h JMP CONTINUE IP jmp Continue Dữ liệu thƣờng nằm ở đây ; khai báo dữ liệu ở đây Continue: CONTINUE: Main Proc (chiều tiến của lệnh và dữ liệu) M ; thân chương trình FFFEh (chiều tiến của ngăn xếp) SP int 20h ; Về DOS Main EndP End Start 550
  36. 9. Vào-ra đơn giản . CPU có thể trao đổi dữ liệu với các thiết bị ngoại qua các cổng vào-ra nhờ các lệnh IN và OUT. . Cách vào-ra đơn giản hơn là dùng các dịch vụ ngắt có sẵn của BIOS hoặc DOS. . Ta thƣờng cần thực hiện các thao tác trao đổi dữ liệu với bàn phím và màn hình dùng hàm DOS. . Lệnh INT (Interrupt): INT N  Là lệnh gọi CTC phục vụ ngắt số hiệu N (N từ 0 ÷ 255)  Dịch vụ ngắt số 21h chứa nhiều hàm tiện ích của DOS. 551
  37. Lệnh nạp địa chỉ hiệu dụng . Lệnh LEA (Load Effective Address): LEA thanh_ghi_chung, ngan_nho  Lấy địa chỉ offset của ngăn nhớ nạp vào thanh ghi  Ví dụ: LEA DX, Thong_Bao MOV DX, offset Thong_Bao ; lệnh cùng chức năng 552
  38. Một số hàm vào-ra của DOS . Khi gọi dịch vụ ngắt của DOS bằng lệnh Int 21h thì AH chứa số hiệu dịch vụ hàm. . Hàm 01h (chờ ngƣời sử dụng vào 1 phím)  Vào: . AH = 01h  Ra: . AL = mã ASCII nếu 1 phím kí tự đƣợc nhấn = 0 nếu 1 phím điều khiển hay chức năng đƣợc nhấn  Ví dụ: MOV AH, 1 INT 21h 553
  39. Một số hàm vào-ra của DOS (tiếp) . Hàm 02h (hiện 1 kí tự hay điều khiển)  Vào: . AH = 02h . DL = mã ASCII của kí tự hiển thị hay điều khiển  Ra: . AL = mã ASCII của kí tự hiển thị hay điều khiển  Ví dụ: MOV AH, 2 MOV DL, 'A' ; viết ra kí tự 'A' INT 21h MOV DL, 10 ; điều khiển con trỏ xuống dòng INT 21h MOV DL, 13 ; điều khiển con trỏ về đầu dòng INT 21h 554
  40. Một số hàm vào-ra của DOS (tiếp) . Hàm 09h (hiện 1 chuỗi kí tự)  Vào: . AH = 09h . DS:DX = địa chỉ của chuỗi kí tự có kí tự kết thúc là '$'  Ra: không  Ví dụ: ThongBao DB 'Chao cac ban$' ; giả sử DS = địa chỉ đoạn của ThongBao MOV AH, 9 LEA DX, ThongBao ; hoặc MOV DX, OFFSET ThongBao INT 21h 555
  41. 10. Các ví dụ . Ví dụ 1: Chƣơng trình "Hello World" bằng hợp ngữ. . Ví dụ 2: Lập trình thực hiện các công việc sau:  Hiển thị thông báo : 'Hãy gõ vào một chữ cái thƣờng: '  Vào chữ cái thƣờng  Xuống dòng, về đầu dòng  Hiển thị thông báo : 'Chữ cái hoa tƣơng ứng là: '  Hiển thị chữ cái hoa tƣơng ứng  Thoát về DOS. 556
  42. Ví dụ 1 .Model Small .Stack 100h .Data TBao db 'Hello World$' ; kết thúc bằng '$' .Code Main Proc mov ax, @Data mov ds, ax ; DS trỏ đến đoạn Data HienTB: mov ah, 9 ; hàm hiện chuỗi lea dx, TBao ; DS:DX chuỗi TBao int 21h ; gọi hàm Thoat: mov ah,4Ch ; hàm thoát về DOS int 21h Main EndP End Main 557
  43. Ví dụ 2 .Model Small mov ah, 2 ; hiện kí tự .Stack 100 mov dl, 10 ; LF .Data int 21h TB1 db 'Hay go vao mot chu cai thuong: $' mov dl, 13 ; CR TB2 db 'Chu cai hoa tuong ung la: $' int 21h .Code mov ah, 9 ; hiện chuỗi Main Proc lea dx, TB2 ; TB2 mov ax, @Data int 21h mov ds, ax ; DS trỏ đến đoạn Data mov ah, 2 ; hiện kí tự mov ah, 9 ; hàm hiển thị chuỗi mov dl, bl lea dx, TB1 ; DS:DX chuỗi TB1 sub dl, 20h ; chữ HOA int 21h int 21h mov ah, 1 ; hàm nhập kí tự mov ah,4Ch ; về DOS int 21h int 21h mov bl, al ; lưu kí tự vào BL Main EndP End Main 558
  44. 11. Dịch và chạy chƣơng trình . Nếu dùng MASM:  Viết chƣơng trình nguồn, ghi ra file .ASM (chẳng hạn là BAITAP.ASM)  Dịch mã nguồn: MASM BAITAP.ASM . Nếu không có lỗi thì ta có file BAITAP.OBJ . Nếu có lỗi thì xem thông báo lỗi và đến dòng xuất hiện lỗi để sửa  Liên kết: LINK BAITAP.OBJ . Nếu không có lỗi thì ta có file BAITAP.EXE  Nếu mã nguồn viết theo dạng .COM thì cần chuyển từ file .EXE sang dạng COM bằng lệnh: EXE2BIN BAITAP.EXE BAITAP.COM  Thực hiện file BAITAP.EXE (hoặc BAITAP.COM) 559
  45. Dịch và chạy chƣơng trình (tiếp) . Nếu dùng TASM:  Viết chƣơng trình nguồn, ghi ra file .ASM (chẳng hạn là BAITAP.ASM)  Dịch mã nguồn: TASM BAITAP.ASM . Nếu không có lỗi thì ta có file BAITAP.OBJ . Nếu có lỗi thì xem thông báo lỗi và đến dòng xuất hiện lỗi để sửa  Liên kết: . File EXE: TLINK BAITAP.OBJ /X . File COM: TLINK BAITAP.OBJ /T /X  Thực hiện file BAITAP.EXE (hoặc BAITAP.COM) 560
  46. Nội dung file TEXE.BAT @echo off if not "A%1"=="A" goto ok echo Syntax: TEXE Filename goto End :OK if not exist %1.asm goto End echo NPB's Assembly Compiler echo Compiling : %1.asm tasm %1.asm if not exist %1.obj goto End tlink %1.obj /x if not ErrorLevel 0 goto End del %1.obj :End 561
  47. Sử dụng file TEXE.BAT . File TEXE.BAT chứa các lệnh gọi 2 file TASM.EXE và TLINK.EXE để dịch 1 chƣơng trình .ASM ra dạng file .EXE . Giả sử ta có file chƣơng trình BAITAP.ASM . Gõ lệnh sau: TEXE BAITAP (Chú ý: không gõ "BAITAP.ASM") . Nếu chƣơng trình viết không có lỗi thì ta sẽ có file BAITAP.EXE 562
  48. Bài tập 1 . Dữ liệu của 1 chƣơng trình hợp ngữ đƣợc khai báo dƣới dạng: DATA SEGMENT mem1 dw 500 mem2 dw -50 vec2 db 10, 20, -10, -20, -30, -40 DATA ENDS . Hãy xác định nội dung của AX (Hexa) sau khi thực hiện đoạn lệnh sau: mov bx, 1 mov ax, SEG vec2 mov es, ax mov ax, es:[bx] a) 01F4 b) 0A14 c) F4FF d) 14F6 e) CE01 563
  49. Bài tập 1 (tiếp) Offset mem1 F4h 0 01h 1 mem2 CEh 2 FFh 3 vec2 0Ah 4 14h 5 F6h 6 ECh 7 E2h 8 D8h 9 564
  50. Bài tập 2 . Dữ liệu của 1 chƣơng trình hợp ngữ đƣợc khai báo dƣới dạng: DATA SEGMENT mem1 dw 500 mem2 dw -50 vec1 db 1, 2, 3, 4, 8, 7 vec2 db 10, 20, -10, -20, -30, -40 DATA ENDS . Hãy xác định nội dung của CX (Hexa) sau khi thực hiện đoạn lệnh sau: mov bx, OFFSET vec1 mov cx, 3[bx] a) 0304 b) 0408 c) F3F4 d) 0203 e) 0804 565
  51. Bài tập 2 (tiếp) Offset mem1 F4h 0 01h 1 mem2 CEh 2 FFh 3 vec1 01h 4 02h 5 03h 6 04h 7 08h 8 07h 9 vec2 14h A F6h B ECh C E2h D D8h E 566
  52. Bài tập 3 . Lập trình thực hiện các công việc sau:  Hiển thị thông báo : 'Hãy gõ vào một chữ số: '  Vào một chữ số  Xuống dòng, về đầu dòng  Hiển thị thông báo : 'Chữ số bù 9 là: '  Hiển thị chữ số bù 9 tƣơng ứng  Thoát về DOS. 567
  53. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 568
  54. 5.2. Các cấu trúc lập trình với hợp ngữ 1. Các lệnh liên quan 2. Cấu trúc điều kiện 3. Cấu trúc lặp 569
  55. 1. Các lệnh liên quan . Các cấu trúc lập trình:  Tuần tự  Điều kiện  Lặp . Các cấu trúc điều kiện và lặp trong hợp ngữ đƣợc tạo bởi phần lớn là các lệnh sau:  Lệnh so sánh CMP  Lệnh nhảy không điều kiện JMP  Các lệnh nhảy có điều kiện  Các câu lệnh lặp 570
  56. Lệnh so sánh CMP . Cú pháp: CMP đích, gốc . Đích và gốc không đồng thời là ngăn nhớ, ngoài ra đích không đƣợc là hằng số. . Lệnh CMP sẽ thực hiện trừ thử đích cho gốc (hơi giống lệnh SUB) nhƣng không thay đổi giá trị của đích mà chỉ cập nhật thanh ghi cờ. . Theo sau lệnh CMP thƣờng là các lệnh nhảy có điều kiện. 571
  57. Lệnh nhảy không điều kiện JMP . Cú pháp: JMP Target . Chuyển điều khiển không điều kiện đến Target . Target có thể là nhãn lệnh, tên thanh ghi hoặc nội dung ngăn nhớ. . Các dạng của lệnh nhảy:  Nhảy ngắn (short): IP  IP + (giá trị có dấu 8 bit thay cho Target) . JMP SHORT NhanLenh  Nhảy gần (near): IP  IP + (giá trị có dấu 16 bit thay cho Target) . JMP NEAR NhanLenh  Nhảy xa (far): IP  Target_Ofs; CS  Target_Seg . NhanLenh LABEL FAR . JMP FAR NhanLenh  Gián tiếp: IP  thanh ghi / bộ nhớ (và CS  thanh ghi / bộ nhớ) . JMP NEAR PTR BX ; IP  BX . JMP WORD PTR [BX] ; IP  [BX] . JMP DWORD PTR [BX] ; IP  [BX] và CS  [BX+2] 572
  58. Các lệnh nhảy có điều kiện . Có nhiều lệnh nhảy có điều kiện với cú pháp chung là: JMPđk NhanLenh . Nhảy trong phạm vi khoảng cách từ -128 ÷ 127 byte. . Các kí hiệu cần nhớ:  J : Jump (nhảy)  N : Not (không )  Z : cờ ZF; C : cờ CF; O : cờ OF; S : cờ SF; P : cờ PF  A : Above (lớn hơn – so sánh số không dấu)  B : Below (nhỏ hơn – so sánh số không dấu)  G : Greater (lớn hơn – so sánh số có dấu)  L : Less (nhỏ hơn – so sánh số có dấu)  E : Equal (bằng) 573
  59. Nhảy hai bƣớc . Các lệnh nhảy có điều kiện có bƣớc nhảy rất ngắn (khoảng cách từ -128 đến 127 byte) . Muốn nhảy đến nhãn lệnh ở xa thì cần thực hiện qua 2 bƣớc:  Bƣớc 1: nhảy đến một nhãn lệnh trung gian ở gần đó.  Bƣớc 2: từ nhãn lệnh trung gian này sử dụng lệnh JMP để nhảy đến nhãn lệnh ở xa. 574
  60. Các lệnh nhảy so sánh số có dấu Ký hiệu Chức năng Điều kiện nhảy Nhảy nếu lớn hơn JG / JNLE ZF=0 và SF=OF Nhảy nếu không nhỏ hơn hoặc bằng Nhảy nếu lớn hơn hoặc bằng JGE / JNL SF=OF Nhảy nếu không nhỏ hơn Nhảy nếu nhỏ hơn JL / JNGE SF OF Nhảy nếu không lớn hơn 575
  61. Các lệnh nhảy so sánh số không dấu Ký hiệu Chức năng Điều kiện nhảy Nhảy nếu lớn hơn JA / JNBE ZF=0 và CF=0 Nhảy nếu không nhỏ hơn hoặc bằng Nhảy nếu lớn hơn hoặc bằng JAE / JNB CF=0 Nhảy nếu không nhỏ hơn Nhảy nếu nhỏ hơn JB / JNAE CF=1 Nhảy nếu không lớn hơn hoặc bằng Nhảy nếu nhỏ hơn hoặc bằng JBE / JNA ZF=1 hoặc CF=1 Nhảy nếu không lớn hơn 576
  62. Các lệnh nhảy điều kiện đơn Ký hiệu Chức năng Điều kiện nhảy Nhảy nếu bằng JE / JZ ZF=1 Nhảy nếu bằng 0 Nhảy nếu không bằng JNE / JNZ ZF=0 Nhảy nếu khác 0 JC Nhảy nếu có nhớ CF=1 JNC Nhảy nếu không có nhớ CF=0 JO Nhảy nếu tràn OF=1 JNO Nhảy nếu không tràn OF=0 JS Nhảy nếu kết quả âm SF=1 JNS Nhảy nếu kết quả không SF=0 JP / JPE Nhảy nếu cờ chẵn PF=1 JNP / JPO Nhảy nếu cờ lẻ PF=0 JCXZ Nhảy nếu thanh ghi CX = 0 CX=0 577
  63. Các câu lệnh lặp . Lệnh LOOP:  Cú pháp: LOOP NhanLenh  Lặp lại các lệnh từ NhanLenh đến hết lệnh LOOP cho đến khi CX = 0  Sau mỗi lần lặp CX tự động giảm 1  NhanLenh cách xa lệnh LOOP không quá -128 byte  Thông thƣờng CX đƣợc gán bằng số lần lặp trƣớc khi vào vòng lặp.  Ví dụ: MOV AL, 0 ; gán AL = 0 MOV CX, 16 ; số lần lặp LAP: INC AL ; tăng AL thêm 1 LOOP LAP ; lặp 16 lần, AL = 16 578
  64. Các câu lệnh lặp (tiếp) . Lệnh LOOPE / LOOPZ:  Cú pháp: LOOPE NhanLenh LOOPZ NhanLenh  Lặp lại các lệnh từ NhanLenh đến hết lệnh LOOPE / LOOPZ cho đến khi CX = 0 hoặc ZF = 0  Phạm vi tác dụng và điều kiện CX: giống lệnh LOOP . Lệnh LOOPNE / LOOPNZ:  Cú pháp: LOOPNE NhanLenh LOOPNZ NhanLenh  Lặp lại các lệnh từ NhanLenh đến hết lệnh LOOPNE / LOOPNZ cho đến khi CX = 0 hoặc ZF = 1  Phạm vi tác dụng và điều kiện CX: giống lệnh LOOP 579
  65. Ví dụ 1 . Nhận các kí tự '0' từ bàn phím cho đến khi nhận đủ 20 lần hoặc kí tự nhập vào khác '0'. . Mã lệnh: MOV AH, 1 ; hàm nhập kí tự MOV CX, 20 ; lặp tối đa 20 lần DocKiTu: INT 21h ; nhận 1 kí tự CMP AL, '0' ; so sánh với '0' LOOPZ DocKiTu ; lặp lại DocKiTu 580
  66. Ví dụ 2 . Nhận các kí tự từ bàn phím cho đến khi nhận đủ 20 kí tự hoặc kí tự nhập vào là ENTER. . Mã lệnh: MOV AH, 1 ; hàm nhập kí tự MOV CX, 20 ; lặp tối đa 20 lần DocKiTu: INT 21h ; nhận 1 kí tự CMP AL, 13 ; so sánh với ENTER LOOPNZ DocKiTu ; lặp lại DocKiTu 581
  67. 2. Cấu trúc điều kiện . Các cấu trúc điều kiện thông dụng:  IF THEN  IF THEN ELSE  CASE OF : : : Else END 582
  68. a. Cấu trúc IF THEN . IF THEN . Dạng lệnh: CMP ; suy ra từ JMPđksai BoQua ; các lệnh thực hiện BoQua: 583
  69. Ví dụ lệnh IF THEN . Gán BX = giá trị tuyệt đối của AX . Thuật giải: BX := AX If BX < 0 Then BX := -BX EndIf . Mã lệnh: MOV BX, AX CMP BX, 0 JNL BoQua NEG BX BoQua: 584
  70. b. Cấu trúc IF THEN ELSE . IF THEN ELSE . Dạng lệnh: CMP ; suy ra từ JMPđksai Viec2 ; các lệnh thực hiện JMP TiepTuc Viec2: ; các lệnh thực hiện TiepTuc: 585
  71. Ví dụ lệnh IF THEN ELSE . AL và BL đang chứa mã ASCII của 2 kí tự. Hãy hiển thị ra màn hình kí tự có mã ASCII nhỏ hơn. Thuật giải: If AL tới Viec2 MOV DL, AL ; chuyển kí tự trong AL vào DL JMP TiepTuc ; tới TiepTuc Viec2: MOV DL, BL ; chuyển kí tự trong BL vào DL TiepTuc: INT 21h ; hiện kí tự trong DL 586
  72. c. Cấu trúc CASE OF CMP ; suy ra từ = JMPđkđúng Viec_1 CMP ; suy ra từ = JMPđkđúng Viec_2 CMP ; suy ra từ = JMPđkđúng Viec_N ; trường hợp còn lại => thực hiện việc N+1 JMP TiepTuc Viec_1: ; thực hiện việc 1 JMP TiepTuc Viec_2: ; thực hiện việc 2 JMP TiepTuc Viec_N: ; thực hiện việc N TiepTuc: 587
  73. Ví dụ lệnh CASE OF . Kiểm tra nếu AX 0 thì gán BX = 1 Thuậ t giải: Mã lệnh chƣơng trình: Case AX Of CMP AX, 0 ; so sánh AX với 0 tới SoAM =0: BX := 0 JE BangKhong ; AX = 0 => tới BangKhong Else MOV BX, 1 ; TH còn lại, gán BX = 1 BX := 1 JMP TiepTuc ; kết thúc xử lý End SoAm: MOV BX, -1 ; gán BX = -1 JMP TiepTuc ; kết thúc xử lý BangKhong: MOV BX, 0 ; gán BX = 0 TiepTuc: 588
  74. d. Điều kiện chứa AND . If AND Then . Dạng lệnh: CMP ; suy ra từ JMPđksai BoQua CMP ; suy ra từ JMPđksai BoQua ; thực hiện BoQua: 589
  75. Ví dụ . Đọc 1 kí tự, nếu là chữ cái hoa thì hiển thị. Thuật giải: Đọc 1 kí tự (vào AL) If (AL >= ‘A’) AND (AL BoQua CMP AL, ‘Z’ ; so sánh kí tự với ‘Z’ JA BoQua ; kí tự > ‘Z’ => BoQua MOV AH, 2 ; hàm hiện kí tự MOV DL, AL ; DL chứa kí tự cần hiện INT 21h ; hiện kí tự trong DL BoQua: 590
  76. e. Điều kiện chứa OR . If OR Then . Dạng lệnh: CMP ; suy ra từ JMPđkđúng ThucHien CMP ; suy ra từ JMPđkđúng ThucHien JMP BoQua ThucHien: ; thực hiện BoQua: 591
  77. Ví dụ . Đọc 1 kí tự, nếu là 'y' hoặc 'Y' thì hiển thị lại, nếu không phải thì thoát chƣơng trình. Thuật giải: Đọc 1 kí tự (vào AL) If (AL = ‘y’) OR (AL = ‘Y’) Then Hiển thị kí tự trong AL Else Thoát chương trình End 592
  78. Ví dụ (tiếp) Mã lệnh chƣơng trình: MOV AH, 1 ; hàm đọc kí tự INT 21h ; AL chứa kí tự đọc được CMP AL, ‘y’ ; so sánh kí tự với ‘y’ JE HienThi ; kí tự = ‘y’ => Hiển thị CMP AL, ‘Y’ ; so sánh kí tự với ‘Y’ JE HienThi ; kí tự = ‘Y’ => Hiển thị JMP Thoat ; các TH khác => Thoat HienThi: MOV AH, 2 ; hàm hiện kí tự MOV DL, AL ; DL chứa kí tự cần hiện INT 21h ; hiện kí tự trong DL JMP TiepTuc ; tiếp tục Thoat: MOV AH, 4Ch ; thoát khỏi chương trình INT 21h TiepTuc: 593
  79. 3. Cấu trúc lặp . Các cấu trúc lặp thông dụng:  FOR DO  REPEAT UNTIL  WHILE DO 594
  80. a. Lệnh lặp FOR . FOR DO . Dạng lệnh: ; JCXZ BoQua ; nếu CX = 0 thì không lặp VongLap: LOOP VongLap BoQua: 595
  81. Ví dụ . Hiển thị ra màn hình 80 dấu '*' . Mã lệnh: MOV CX, 80 ; số kí tự cần hiện MOV AH, 2 ; hàm hiện kí tự MOV DL, '*' ; kí tự cần hiện là * HienSao: INT 21h ; hiện kí tự LOOP HienSao ; lặp lại 80 lần 596
  82. b. Lệnh lặp REPEAT UNTIL . REPEAT UNTIL . Dạng lệnh: VongLap: ; thân vòng lặp CMP ; suy ra từ JMPđksai VongLap 597
  83. Ví dụ 1 . Đọc vào các kí tự cho đến khi gặp ENTER . Mã lệnh: MOV AH, 1 ; hàm đọc kí tự DocKiTu: INT 21h ; đọc 1 kí tự vào AL CMP AL, 13 ; kí tự là ENTER ? JNE DocKiTu ; sai => lặp tiếp 598
  84. Ví dụ 2 – REPEAT lồng với FOR . Hiển thị ra 5 dòng, mỗi dòng gồm 50 dấu '*' . Mã lệnh: MOV BL, 5 ; số dòng cần hiện HienDong: MOV CX, 50 ; hiện 50 dấu * trên 1 dòng MOV AH, 2 ; hàm hiện kí tự MOV DL, '*' ; DL = kí tự cần hiện VietSao: INT 21h ; gọi hàm hiện kí tự trong DL LOOP VietSao ; lặp lại cho đến khi đủ 50 '*' MOV DL, 10 ; xuống dòng INT 21h MOV DL, 13 ; về đầu dòng INT 21h DEC BL ; giảm số dòng cần phải hiện tiếp JNZ HienDong ; chưa hết 5 dòng => quay lại 599
  85. c. Lệnh lặp WHILE DO . WHILE DO . Dạng lệnh: VongLap: CMP ; suy ra từ JMPđksai DungLap ; sai thì dừng ; thực hiện JMP VongLap ; lặp lại DungLap: 600
  86. Ví dụ . Nhập 1 dòng kết thúc bằng ENTER. Đếm số kí tự đã đƣợc nhập. . Mã lệnh: MOV DX, 0 ; khởi tạo bộ đếm = 0 MOV AH, 1 ; hàm đọc kí tự DocKiTu: INT 21h ; đọc 1 kí tự vào AL CMP AL, 13 ; kí tự đó là ENTER ? JE DungLap ; đúng => DungLap INC DX ; sai => tăng bộ đếm lên 1 JMP DocKiTu ; lặp lại DungLap: 601
  87. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 602
  88. 5.3. Các lệnh logic, dịch và quay 1. Các lệnh logic 2. Các lệnh dịch 3. Các lệnh quay 4. Vào-ra số nhị phân và Hexa 603
  89. 1. Các lệnh logic . Các phép toán logic: a b a AND b a OR b a XOR b a NOT a 0 0 0 0 0 0 1 0 1 0 1 1 1 0 1 0 0 1 1 1 1 1 1 0 . Các lệnh logic: AND, OR, XOR, NOT, TEST 604
  90. Các lệnh AND, OR và XOR . Cú pháp:  AND đích, nguồn ; đích  đích AND nguồn  OR đích, nguồn ; đích  đích OR nguồn  XOR đích, nguồn ; đích  đích XOR nguồn  TEST đích, nguồn ; Phép AND nhƣng không thay đổi đích . Chú ý:  Toán hạng nguồn: hằng số, thanh ghi hay ngăn nhớ  Toán hạng đích: thanh ghi hay ngăn nhớ  Hai toán hạng không đƣợc đồng thời là ngăn nhớ . Ảnh hƣởng tới các cờ:  SF, ZF, PF phản ánh kết quả của lệnh  AF không xác định  CF = OF = 0 605
  91. Các ví dụ . VD 1: Đổi mã ASCII của 1 chữ số thành số tƣơng ứng.  Giả sử AL chứa kí tự (chẳng hạn '5' – mã ASCII là 35h)  Cần chuyển AL về giá trị chữ số (là 5)  Thực hiện: SUB AL, 30h hoặc AND AL, 0Fh . VD 2: Đổi chữ thƣờng thành chữ hoa.  Giả sử DL chứa kí tự chữ thƣờng, cần chuyển về chữ hoa.  Thực hiện: SUB DL, 20h hoặc AND DL, 0DFh . VD 3: Xóa thanh ghi AX về 0.  Thực hiện: XOR AX, AX . VD 4: Kiểm tra xem AX có bằng 0 hay không?  Thực hiện: OR AX, AX ; AX = 0 ZF = 1 606
  92. Lệnh NOT . Cú pháp: NOT đích . Lệnh này không ảnh hƣởng đến cờ 607
  93. Lệnh TEST . Cú pháp: TEST đích, nguồn . Thực hiện phép toán AND nhƣng không thay đổi đích mà chỉ cập nhật các cờ. . Các cờ bị tác động:  SF, ZF, PF phản ánh kết quả của lệnh  AF không xác định  CF = OF = 0 . Ví dụ: Kiểm tra tính chẵn lẻ của AL  AL chẵn bit LSB của = 0  Thực hiện: TEST AL, 1 ; AL chẵn ZF = 1 608
  94. 2. Các lệnh dịch . Các lệnh dịch và quay có 2 dạng:  Dịch (hoặc quay) 1 vị trí: Lệnh đích, 1  Dịch (hoặc quay) N vị trí: Lệnh đích, CL ; với CL = N 609
  95. Các lệnh dịch trái . Dịch trái số học (SAL – Shift Arithmetically Left) và dịch trái logic (SHL – Shift (Logically) Left):  SAL đích, 1 hoặc SAL đích, CL  SHL đích, 1 hoặc SHL đích, CL . Lệnh SAL và SHL là tƣơng đƣơng . Tác động vào các cờ:  SF, PF, ZF phản ánh kết quả  AF không xác định  CF chứa bit cuối cùng đƣợc dịch ra khỏi đích  OF = 1 nếu kết quả bị thay đổi dấu trong phép dịch cuối cùng CF MSB LSB 0 Lệnh SAL / SHL 610
  96. Các lệnh dịch phải . Dịch phải logic: SHR – Shift (Logically) Right  Cú pháp: SHR đích, 1 SHR đích, CL  Các cờ bị tác động nhƣ là lệnh dịch trái  Minh họa: MSB LSB CF 0 611
  97. Các lệnh dịch phải (tiếp) . Dịch phải số học: SAR – Shift Arithmetically Right  Cú pháp: SAR đích, 1 SAR đích, CL  Các cờ bị tác động nhƣ là lệnh SHR  Minh họa: MSB LSB CF 612
  98. 3. Các lệnh quay . Các dạng lệnh quay:  ROL : quay trái  ROR : quay phải  RCL : quay trái qua cờ nhớ  RCR : quay phải qua cờ nhớ . Tác động vào các cờ:  SF, PF, ZF phản ánh kết quả  AF không xác định  CF chứa bit cuối cùng bị dịch ra khỏi toán hạng  OF = 1 nếu kết quả bị thay đổi dấu trong lần quay cuối cùng 613
  99. Minh họa các lệnh quay CF MSB LSB Lệnh ROL CF MSB LSB Lệnh RCL MSB LSB CF Lệnh ROR MSB LSB CF Lệnh RCR 614
  100. Ví dụ . Xác định giá trị của AX và BX dƣới dạng Hexa sau khi thực hiện đoạn chƣơng trình sau: MOV CX, 16 MOV AX, 5A6Bh LAP: ROL AX, 1 RCR BX, 1 LOOP LAP 615
  101. 4. Vào-ra số nhị phân và Hexa . Các thao tác:  Nhập số nhị phân  In số nhị phân  Nhập số Hexa  In số Hexa 616
  102. a. Nhập số nhị phân . Đọc các bit nhị phân từ bàn phím (kết thúc nhập bằng ENTER), chuyển thành số nhị phân rồi lƣu vào BX. . Thuật giải: Xóa BX (là thanh ghi chứa kết quả) Nhập 1 kí tự ('0' hoặc '1') WHILE kí tự <> Enter DO Đổi kí tự ra giá trị nhị phân Dịch trái BX Chèn giá trị nhận đƣợc vào bit LSB của BX Nhập kí tự END WHILE 617
  103. Đoạn lệnh nhập số nhị phân XOR BX, BX ; Xóa BX MOV AH, 1 ; Hàm nhập ký tự INT 21h ; Nhập ký tự NhapKyTu: CMP AL, 13 ; Là phím ENTER? JE DungNhap ; Đúng kết thúc nhập AND AL, 0Fh ; Sai đổi ra giá trị nhị phân SHL BX, 1 ; Dành chỗ cho bit mới tìm được OR BL, AL ; Chèn bit này vào cuối BX INT 21h ; Nhập tiếp ký tự khác JMP NhapKyTu ; Lặp lại DungNhap: 618
  104. b. In số nhị phân . In giá trị ở BX ra màn hình dƣới dạng số nhị phân. . Thuật giải: FOR 16 lần DO Quay trái BX (bit MSB của BX đƣợc đƣa ra CF) IF CF = 1 THEN Đƣa ra '1' ELSE Đƣa ra '0' END IF END FOR . Có thể dùng lệnh ADC: ADC đích, nguồn đích  đích + nguồn + CF 619
  105. Mã lệnh MOV CX, 16 ; số bit cần hiện MOV AH, 2 ; hàm hiện kí tự Print: ROL BX, 1 ; quay trái BX CF = MSB MOV DL, 0 ; DL = 0 ADC DL, 30h ; DL  30h + CF INT 21h ; in kí tự trong DL LOOP Print ; lặp lại 16 lần 620
  106. c. Nhập số Hexa . Đọc các kí tự Hexa từ bàn phím (tối đa 4 chữ số, chỉ nhập các chữ số và các chữ cái hoa, kết thúc nhập bằng ENTER). Chuyển thành số Hexa tƣơng ứng rồi lƣu vào BX. . Thuật giải: Xóa BX (là thanh ghi chứa kết quả) Nhập kí tự Hexa WHILE kí tự <> Enter DO Đổi kí tự ra nhị phân Dịch trái BX 4 lần Chèn giá trị mới vào 4 bit thấp nhất của BX Nhập kí tự tiếp END WHILE 621
  107. Đoạn lệnh nhập số Hexa XOR BX, BX ; Xóa BX MOV CL, 4 ; Số lần dịch trái BX MOV AH, 1 ; Hàm nhập kí tự INT 21h ; Nhập 1 kí tự AL = mã ASCII VongLap: CMP AL, 13 ; Kí tự vừa nhập là Enter? JE KetThucLap ; Đúng Kết thúc CMP AL, '9' ; So sánh với '9' JG ChuCai ; Lớn hơn là chữ cái hoa AND AL, 0Fh ; Không lớn hơn đổi chữ số ra nhị phân JMP ChenBit ; Rồi chèn vào cuối BX ChuCai: SUB AL, 37h ; Đổi chữ cái ra giá trị nhị phân ChenBit: SHL BX, CL ; Dịch trái BX để dành chỗ cho c/s mới OR BL, AL ; Chèn chữ số mới vào 4 bit thấp của BX INT 21h ; Nhận tiếp kí tự từ bàn phím JMP VongLap ; Lặp lại KetThucLap: 622
  108. d. In số Hexa . Đƣa giá trị Hexa 4 chữ số trong BX ra màn hình. . Thuật giải: FOR 4 lần DO Chuyển BH vào DL (giá trị cần in nằm trong BX) Dịch phải DL 4 vị trí IF DL < 10 THEN Đổi thành kí tự '0' '9' ELSE Đổi thành kí tự 'A' 'F' END IF Đƣa kí tự ra Quay trái BX 4 vị trí END FOR 623
  109. Mã lệnh MOV CX, 4 MOV AH, 2 InHexa: MOV DL, BH SHR DL, 1 SHR DL, 1 SHR DL, 1 SHR DL, 1 CMP DL, 9 JA ChuCai ADD DL, 30h JMP TiepTuc ChuCai: ADD DL, 37h TiepTuc: INT 21h ROL BX, 1 ROL BX, 1 ROL BX, 1 ROL BX, 1 LOOP InHexa 624
  110. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 625
  111. Ngăn xếp và thủ tục 1. Ngăn xếp 2. Thủ tục 3. Các ví dụ 626
  112. 1. Ngăn xếp . Ngăn xếp (Stack):  Vùng nhớ tổ chức theo cấu trúc LIFO dùng để cất giữ thông tin.  Chiều của Stack từ đáy lên đỉnh ngƣợc với chiều tăng của địa chỉ. . Khai báo ngăn xếp: .STACK kich_thuoc . Ví dụ: .Stack 100h  Khi chƣơng trình đƣợc thực thi thì: . SS : chứa địa chỉ đoạn ngăn xếp . SP : chứa địa chỉ offset của đỉnh ngăn xếp. Ban đầu ngăn xếp rỗng nên 0100h cũng là địa chỉ của đáy ngăn xếp (=0100h). 627
  113. Lệnh PUSH và PUSHF . Lệnh PUSH dùng để cất 1 dữ liệu 16 bit vào trong ngăn xếp. . Cú pháp: PUSH nguồn  nguồn là 1 thanh ghi 16 bit hoặc 1 từ nhớ (2 Byte) . Các bƣớc thực hiện:  SP  SP – 2  Một bản sao của toán hạng nguồn đƣợc chuyển vào địa chỉ xác định bởi SS:SP (toán hạng nguồn không đổi) . Lệnh PUSHF cất nội dung của thanh ghi cờ vào trong ngăn xếp. 628
  114. Ví dụ về lệnh PUSH . Xác định nội dung các Byte nhớ trong Stack. .Stack 100h Start: ; lệnh đầu tiên của chương trình MOV AX, 1234h MOV BX, 5678h PUSH AX PUSH BX 629
  115. Ví dụ (tiếp) Offset Offset Offset 0000 0000 0000 . . . . . . . . . 00FC 00FC 00FC 78h SP 00FD 00FD 00FD 56h 00FE 00FE 34h SP 00FE 34h 00FF 00FF 12h 00FF 12h 0100 Đáy Stack SP 0100 Đáy Stack 0100 Đáy Stack Ban đầu Sau lệnh PUSH AX Sau lệnh PUSH BX 630
  116. Lệnh POP và POPF . Lệnh POP dùng để lấy ra 1 từ dữ liệu bắt đầu từ đỉnh ngăn xếp. . Cú pháp: POP đích  đích là 1 thanh ghi 16 bit (trừ IP) hoặc 1 từ nhớ . Các bƣớc thực hiện:  Nội dung của từ nhớ ở địa chỉ xác định bởi SS:SP đƣợc chuyển tới toán hạng đích.  SP  SP + 2 . Lệnh POPF đƣa vào thanh ghi cờ nội dung của từ nhớ ở đỉnh ngăn xếp. 631
  117. Ví dụ về lệnh POP . Xác định nội dung các Byte nhớ trong Stack. .Stack 100h Start: ; lệnh đầu tiên của chương trình MOV AX, 1234h MOV BX, 5678h PUSH AX PUSH BX POP CX POP DX 632
  118. Ví dụ (tiếp) Offset Offset Offset 0000 0000 0000 . . . . . . . . . 00FC 78h SP 00FC 78h 00FC 78h 00FD 56h 00FD 56h 00FD 56h 00FE 34h 00FE 34h SP 00FE 34h 00FF 12h 00FF 12h 00FF 12h 0100 Đáy 0100 Đáy 0100 Đáy SP SP 00FCh SP 00FEh SP 0100h CX ? CX 5678h CX 5678h DX ? DX ? DX 1234h Sau lệnh PUSH BX Sau lệnh POP CX Sau lệnh POP DX 633
  119. Một số lƣu ý . Các lệnh PUSH, PUSHF, POP và POPF không ảnh hƣởng đến các cờ. . Các lệnh trên chỉ thao tác với các WORD. . Các lệnh sau là không hợp lệ:  PUSH AH ; thanh ghi 8 bit  POP DL ; thanh ghi 8 bit  PUSH 2 ; giá trị hằng số 634
  120. Bài tập . Dữ liệu của 1 chƣơng trình hợp ngữ đƣợc khai báo dƣới dạng: DATA SEGMENT mem1 dw 500 mem2 dw -50 vec1 db 1, 2, 3, 4, 8, 7 vec2 db 10, 20, -10, -20, -30, -40 DATA ENDS . Hãy xác định nội dung của DX (Hexa) sau khi thực hiện đoạn lệnh sau: push mem1 push mem2 mov bp, sp mov dx, [bp]+2 a) FFCE b) 0000 c) 01F4 d) FFFF 635
  121. Bài tập 2 (tiếp) Offset mem1 F4h 0 Offset 01h 1 0000 mem2 CEh 2 . FFh 3 . vec1 01h 4 . 02h 5 i-4 CEh SP 03h 6 04h 7 i-3 FFh 08h 8 i-2 F4h 07h 9 i-1 01h vec2 14h A F6h B i Đáy ECh C E2h D D8h E 636
  122. 2. Thủ tục . Ngoài thủ tục chính, ta có thể khai báo và sử dụng các thủ tục khác. . Khai báo thủ tục: Tên_thủ_tục PROC Kiểu_thủ_tục RET Tên_thủ_tục ENDP . Trong đó:  Tên_thủ_tục: do ngƣời lập trình định nghĩa  Kiểu_thủ_tục: . NEAR : gọi thủ tục ở trong cùng 1 đoạn . FAR : gọi thủ tục ở đoạn khác 637
  123. Lệnh CALL . Là lệnh gọi chƣơng trình con (thủ tục) . Thông dụng: CALL Tên_thủ_tục . Các bƣớc thực hiện:  Thủ tục NEAR . SP ¬ SP – 2 . Cất nội dung của IP (địa chỉ quay về) vào Stack . Nạp địa chỉ của lệnh đầu tiên của chƣơng trình con vào IP  Thủ tục FAR . SP ¬ SP – 2 . Cất nội dung của CS vào Stack . SP ¬ SP – 2 . Cất nội dung của IP vào Stack . Nạp vào CS và IP địa chỉ đầu của chƣơng trình con 638
  124. Lệnh RET . Là lệnh trở về từ chƣơng trình con . Các bƣớc thực hiện:  Trở về kiểu NEAR . IP ¬ word nhớ đỉnh Stack . SP ¬ SP + 2  Trở về kiểu FAR (RETF) . IP ¬ word nhớ đỉnh Stack . SP ¬ SP + 2 . CS ¬ word nhớ tiếp . SP ¬ SP + 2 639
  125. Truyền dữ liệu giữa các thủ tục . Các thủ tục của hợp ngữ không có danh sách tham số đi kèm nhƣ các ngôn ngữ lập trình bậc cao. . Ngƣời lập trình phải nghĩ ra cách truyền dữ liệu giữa các thủ tục. . Các cách truyền dữ liệu thông dụng:  Truyền qua thanh ghi  Sử dụng biến toàn cục  Truyền địa chỉ của dữ liệu  Sử dụng ngăn xếp (thƣờng dùng trong các NNLT bậc cao) 640
  126. 3. Các ví dụ . VD1: Nhập 1 chuỗi kí tự kết thúc bởi ENTER. Hiện chuỗi kí tự viết theo thứ tự ngƣợc lại ở dòng tiếp theo. . VD2: Cài đặt các thủ tục viết số nhị phân và số Hexa ra màn hình. 641
  127. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 642
  128. 5.5. Các lệnh nhân, chia 1. Các lệnh MUL và IMUL 2. Các lệnh DIV và IDIV 3. Vào-ra số thập phân 643
  129. 1. Các lệnh MUL và IMUL . Có sự khác nhau giữa phép nhân các số không dấu với phép nhân các số khác dấu. . Lệnh nhân cho các số không dấu: MUL nguồn . Lệnh nhân cho các số có dấu: IMUL nguồn . Các lệnh trên làm việc với byte (cho KQ là 1 word) hoặc word (cho KQ là 1 double word) . nguồn (thanh ghi / ngăn nhớ) đƣợc coi là số nhân, nếu nguồn là giá trị:  8 bit: AX  AL x nguồn . Số bị nhân là số 8 bit chứa trong AL . Tích là số 16 bit chứa trong AX  16 bit: DXAX  AX x nguồn . Số bị nhân là số 16 bit chứa trong AX . Tích là số 16 bit chứa trong DXAX 644
  130. Ảnh hƣởng đến các cờ . SF, ZF, AF, PF : không xác định . Sau lệnh MUL:  CF = OF = 0 nếu nửa cao của kết quả = 0  CF = OF = 1 trong các trƣờng hợp còn lại . Sau lệnh IMUL:  CF = OF = 0 nếu nửa cao của kết quả chỉ chứa các giá trị của dấu  CF = OF = 1 trong các trƣờng hợp còn lại . Nói cách khác, CF = OF = 1 nghĩa là kết quả quá lớn để chứa trong nửa thấp (AL hoặc AX) của tích. 645
  131. 2. Các lệnh DIV và IDIV . Phép chia không dấu: DIV số_chia . Phép chia có dấu: IDIV số_chia . Chia số 16 bit (trong AX) cho số chia 8 bit hoặc chia số 32 bit (trong DXAX) cho số chia 16 bit. . Thƣơng và số dƣ có cùng kích thƣớc với số chia.  Số chia 8 bit: AL chứa thƣơng, AH chứa số dƣ  Số chia 16 bit: AX chứa thƣơng, DX chứa số dƣ . Số dƣ và số chia có cùng dấu. . Nếu số chia = 0 hoặc thƣơng nằm ngoài khoảng xác định thì BXL thực hiện INT 0 (lỗi chia cho 0). . Các cờ không xác định sau phép chia. 646
  132. Sự mở rộng dấu của số bị chia . Trong phép chia cho Word, số bị chia đƣợc đặt trong DXAX ngay cả khi nó có thể chứa vừa trong AX. Khi đó DX phải đƣợc chuẩn bị nhƣ sau:  Với lệnh DIV, DX phải đƣợc xóa về 0.  Với lệnh IDIV, DX đƣợc lấp đầy bằng bit dấu của AX. Phép biến đổi này đƣợc thực hiện bởi lệnh CWD. . Trong phép chia cho Byte, số bị chia đƣợc đặt trong AX ngay cả khi nó có thể chứa vừa trong AL. Khi đó AH phải đƣợc chuẩn bị nhƣ sau:  Với lệnh DIV, AH phải đƣợc xóa về 0.  Với lệnh IDIV, AH đƣợc lấp đầy bằng bit dấu của AL. Phép biến đổi này đƣợc thực hiện bởi lệnh CBW. 647
  133. 3. Vào-ra số thập phân . Các thao tác:  In số thập phân  Nhập số thập phân 648
  134. a. In số thập phân . In số nguyên có dấu trong AX ra màn hình dƣới dạng số thập phân. . Thuật giải: IF AX < 0 THEN In ra dấu ' ' AX := số bù 2 của AX END IF Lấy dạng thập phân của từng chữ số trong AX Đổi các chữ số này ra kí tự rồi in ra màn hình 649
  135. In số thập phân (tiếp) . Lấy dạng thập phân của từng chữ số trong AX: Đếm := 0 REPEAT Chia số bị chia cho 10 ; số bị chia ban đầu = AX Cất số dƣ vào trong Stack Đếm := Đếm + 1 UNTIL Thƣơng = 0 . Đổi các chữ số ra kí tự rồi in ra màn hình: FOR Đếm lần DO Lấy từng chữ số từ Stack Đổi ra kí tự In kí tự đó ra màn hình END FOR 650
  136. b. Nhập số thập phân . Thuật giải (đơn giản): Tổng := 0 Đọc 1 kí tự ASCII REPEAT Đổi kí tự ra giá trị thập phân Tổng := Tổng * 10 + giá trị nhận đƣợc Đọc kí tự UNTIL kí tự vừa nhận = Enter 651
  137. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 652
  138. 5.6. Các lệnh thao tác chuỗi 1. Cờ định hƣớng 2. Chuyển một chuỗi 3. Lƣu kí tự vào chuỗi 4. Nạp kí tự của chuỗi 5. Tìm kí tự trong chuỗi 6. So sánh chuỗi 7. Tổng kết thao tác chuỗi 653
  139. 1. Cờ định hƣớng . Cờ định hƣớng DF (Direction Flag) xác định hƣớng cho các thao tác chuỗi. . Các thao tác chuỗi đƣợc thực hiện thông qua 2 thanh ghi chỉ số SI và DI. . Nếu DF = 0 thì SI và DI đƣợc xử lý theo chiều tăng của địa chỉ bộ nhớ (từ trái qua phải trong chuỗi). . Nếu DF = 1 thì SI và DI đƣợc xử lý theo chiều giảm của địa chỉ bộ nhớ (từ phải qua trái trong chuỗi). 654
  140. Các lệnh CLD và STD . Lệnh CLD (Clear Direction Flag): xóa cờ hƣớng CLD ; xóa DF = 0 . Lệnh STD (Set Direction Flag): thiết lập cờ hƣớng STD ; thiết lập DF = 1 . Các lệnh này không ảnh hƣởng đến các cờ khác. 655
  141. 2. Chuyển một chuỗi . Bài toán: giả sử có 2 chuỗi đƣợc định nghĩa nhƣ sau: .DATA STRING1 DB 'BACH KHOA' STRING2 DB 9 DUP (?) . Cần chuyển nội dung của chuỗi STRING1 (chuỗi nguồn) sang chuỗi STRING2 (chuỗi đích). 656
  142. Các lệnh liên quan . Lệnh: MOVSB (Move String Byte)  Chuyển 1 phần tử 1 byte của chuỗi gốc (trỏ bởi DS:SI) sang 1 phần tử của chuỗi đích (trỏ bởi ES:DI).  Sau khi thực hiện: . SI và DI tăng thêm 1 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI và DI giảm đi 1 nếu cờ hƣớng DF = 1 (dùng lệnh STD) . Lệnh: MOVSW (Move String Word)  Chuyển 1 phần tử 1 word (2 byte) của chuỗi gốc (trỏ bởi DS:SI) sang 1 phần tử của chuỗi đích (trỏ bởi ES:DI).  Sau khi thực hiện: . SI và DI tăng thêm 2 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI và DI giảm đi 2 nếu cờ hƣớng DF = 1 (dùng lệnh STD) 657
  143. Các lệnh liên quan (tiếp) . Để chuyển nhiều kí tự ta cần sử dụng các lệnh lặp. . Lệnh: REP  Lặp lại lệnh viết sau đó cho đến khi CX = 0  Mỗi lần lặp CX giảm đi 1 số lần lặp phải gán trƣớc vào CX. Ví dụ: MOV CX, 5 REP MOVSB ; chuyển 5 byte từ chuỗi nguồn đến chuỗi đích . Lệnh: REPE/REPZ  Lặp lại lệnh viết sau đó cho đến khi CX = 0 hoặc ZF = 0 . Lệnh: REPNE/REPNZ  Lặp lại lệnh viết sau đó cho đến khi CX = 0 hoặc ZF = 1 658
  144. Ví dụ MOV AX, @DATA MOV DS, AX ; khởi tạo DS MOV ES, AX ; và ES đều trỏ đến đoạn dữ liệu DATA LEA SI, STRING1 ; SI trỏ đến chuỗi nguồn LEA DI, STRING2 ; DI trỏ đến chuỗi đích CLD ; Xóa cờ hƣớng MOV CX, 9 ; Số byte cần chuyển REP MOVSB ; Chuyển 9 byte từ STRING1 sang STRING2 659
  145. Giải thích ví dụ SI SI STRING1 'B' 'A' 'C' 'H' ' ' 'K' 'H' 'O' 'A' STRING1 'B' 'A' 'C' 'H' ' ' 'K' 'H' 'O' 'A' Offset 0 1 2 3 4 5 6 7 8 Offset 0 1 2 3 4 5 6 7 8 DI DI STRING2 STRING2 'B' 'A' Offset 9 10 11 12 13 14 15 16 17 Offset 9 10 11 12 13 14 15 16 17 Trƣớc khi thực hiện các lệnh MOVSB Sau khi thực hiện lệnh MOVSB thứ 2 SI STRING1 'B' 'A' 'C' 'H' ' ' 'K' 'H' 'O' 'A' STRING1 'B' 'A' 'C' 'H' ' ' 'K' 'H' 'O' 'A' Offset 0 1 2 3 4 5 6 7 8 Offset 0 1 2 3 4 5 6 7 8 DI SI DI STRING2 'B' STRING2 'B' 'A' 'C' 'H' ' ' 'K' 'H' 'O' 'A' Offset 9 10 11 12 13 14 15 16 17 Offset 9 10 11 12 13 14 15 16 17 18 Sau khi thực hiện lệnh MOVSB thứ 1 Sau khi thực hiện lệnh MOVSB thứ 9 660
  146. 3. Lƣu kí tự vào chuỗi . Lệnh: STOSB (Store String Byte from AL)  Chuyển nội dung thanh ghi AL sang 1 phần tử (1 byte) đƣợc trỏ bởi ES:DI của chuỗi đích.  Sau khi thực hiện: . DI tăng thêm 1 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . DI giảm đi 1 nếu cờ hƣớng DF = 1 (dùng lệnh STD) . Lệnh: STOSW (Store String Word from AX)  Chuyển nội dung thanh ghi AX sang 1 phần tử (2 byte) đƣợc trỏ bởi ES:DI của chuỗi đích.  Sau khi thực hiện: . DI tăng thêm 2 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . DI giảm đi 2 nếu cờ hƣớng DF = 1 (dùng lệnh STD) 661
  147. Ví dụ 1 . Lƣu 5 kí tự 'A' vào đầu chuỗi STRING2 MOV AX, @DATA MOV ES, AX ; ES trỏ đến đoạn dữ liệu DATA LEA DI, STRING2 ; ES:DI trỏ đến đầu chuỗi STRING2 CLD ; Xóa cờ hƣớng MOV CX, 5 ; Số kí tự cần lƣu MOV AL, 'A' ; Kí tự cần lƣu vào chuỗi REP STOSB ; Lặp lƣu 5 lần kí tự 'A' vào STRING2 662
  148. Ví dụ 2 . Nhập các kí tự từ bàn phím rồi lƣu vào chuỗi STRING cho đến khi nhập đủ 20 kí tự hoặc gặp phím ENTER. MOV AX, @DATA MOV ES, AX ; ES trỏ đến đoạn dữ liệu DATA LEA DI, STRING ; ES:DI trỏ đến đầu chuỗi STRING CLD ; Xóa cờ hƣớng MOV CX, 20 ; Số kí tự tối đa đƣợc nhập từ bàn phím XOR BX, BX ; Khởi tạo số kí tự đƣợc nhập ban đầu = 0 MOV AH, 1 ; Hàm nhập kí tự từ bàn phím DocKiTu: INT 21h ; Nhập 1 kí tự AL chứa mã ASCII của kí tự CMP AL, 13 ; Là phím ENTER ? JZ DungNhap ; Dừng nhập STOSB ; Nếu không phải thì lƣu AL vào chuỗi STRING INC BX ; Tăng số đếm số kí tự đƣợc nhập LOOP DocKiTu ; Lặp lại (tối đa 20 lần) DungNhap: 663
  149. 4. Nạp kí tự của chuỗi . Lệnh: LODSB (Load String Byte into AL)  Chuyển 1 phần tử (1 byte) đƣợc trỏ bởi DS:SI của chuỗi nguồn vào thanh ghi AL.  Sau khi thực hiện: . SI tăng thêm 1 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI giảm đi 1 nếu cờ hƣớng DF = 1 (dùng lệnh STD) . Lệnh: LODSW (Load String Word into AX)  Chuyển 1 phần tử (2 byte) đƣợc trỏ bởi DS:SI của chuỗi nguồn vào thanh ghi AX.  Sau khi thực hiện: . SI tăng thêm 2 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI giảm đi 2 nếu cờ hƣớng DF = 1 (dùng lệnh STD) 664
  150. Ví dụ . Giả sử STR1 và STR2 là các chuỗi có độ dài là 40 kí tự. Viết đoạn chƣơng trình chuyển các kí tự chữ hoa từ STR1 sang STR2. MOV AX, @DATA MOV DS, AX ; khởi tạo DS MOV ES, AX ; và ES đều trỏ đến đoạn dữ liệu DATA LEA SI, STR1 ; SI trỏ đến chuỗi nguồn STR1 LEA DI, STR2 ; DI trỏ đến chuỗi đích STR2 CLD ; Xóa cờ hƣớng MOV CX, 40 ; Số kí tự của STR1 cần xét (độ dài xâu STR1) XOR BX, BX ; Khởi tạo số kí tự thực sự đƣợc chuyển ban đầu = 0 VongLap: LODSB ; Nạp 1 kí tự của STR1 vào AL CMP AL, 'A' ; Nếu AL 'Z' không phải là chữ hoa JA LapTiep ; thì xét kí tự tiếp theo STOSB ; Nếu AL là chữ cái hoa thì cất vào chuỗi STR2 INC BX ; Tăng số đếm số chữ cái hoa LapTiep: LOOP VongLap ; Lặp lại, xét kí tự tiếp theo của STR1 665
  151. 5. Tìm kí tự trong chuỗi . Lệnh: SCASB (Scan String Byte)  Trừ thử nội dung của AL cho 1 byte đích đang đƣợc trỏ bởi ES:DI, không thay đổi giá trị AL mà chỉ cập nhật cờ.  Sau khi thực hiện: . DI tăng thêm 1 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . DI giảm đi 1 nếu cờ hƣớng DF = 1 (dùng lệnh STD) . Lệnh: SCASW (Scan String Word)  Trừ thử nội dung của AX cho 1 word đích đang đƣợc trỏ bởi ES:DI, không thay đổi giá trị AX mà chỉ cập nhật cờ.  Sau khi thực hiện: . DI tăng thêm 2 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . DI giảm đi 2 nếu cờ hƣớng DF = 1 (dùng lệnh STD) 666
  152. Ví dụ 1 . Cho 1 chuỗi đƣợc khai báo nhƣ sau: .DATA STRING1 DB 'ABC' . Khảo sát đoạn chƣơng trình sau: MOV AX, @DATA MOV ES, AX CLD LEA DI, STRING1 MOV AL, 'B' SCASB SCASB 667
  153. Ví dụ 1 (tiếp) Trƣớc khi thực hiện lệnh SCASB DI AL ZF STRING1 'A' 'B' 'C' 'B' ? Offset 0 1 2 (Không xác định) Sau khi thực hiện lệnh SCASB thứ 1 DI AL ZF STRING1 'A' 'B' 'C' 'B' 0 Offset 0 1 2 (Không thấy) Sau khi thực hiện lệnh SCASB thứ 2 DI AL ZF STRING1 'A' 'B' 'C' 'B' 1 Offset 0 1 2 (Tìm thấy) 668
  154. Ví dụ 2 . Tìm chữ cái 'A' đầu tiên trong chuỗi STRING2 có độ dài 40 kí tự. . Đoạn chƣơng trình: MOV AX, @DATA MOV ES, AX ; ES trỏ đến đoạn dữ liệu CLD ; Xóa cờ hƣớng LEA DI, STRING2 ; ES:DI trỏ đến chuỗi đích STRING2 MOV CX, 40 ; Độ dài chuỗi STRING2 MOV AL, 'A' ; AL chứa kí tự cần tìm REPNE SCASB ; Tìm cho đến khi thấy hoặc CX=0 . Ra khỏi đoạn chƣơng trình:  Nếu ZF = 1 thì ES:[DI-1] là kí tự 'A' đầu tiên tìm thấy  Nếu ZF = 0 thì trong chuỗi STRING2 không chứa kí tự 'A' 669
  155. 6. So sánh chuỗi . Lệnh: CMPSB (Compare String Byte)  Trừ thử 1 byte ở địa chỉ DS:SI cho 1 byte ở địa chỉ ES:DI, kết quả không đƣợc lƣu lại mà chỉ cập nhật cờ.  Sau khi thực hiện: . SI, DI tăng thêm 1 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI, DI giảm đi 1 nếu cờ hƣớng DF = 1 (dùng lệnh STD) . Lệnh: CMPSW (Compare String Word)  Trừ thử 1 word ở địa chỉ DS:SI cho 1 word ở địa chỉ ES:DI, kết quả không đƣợc lƣu lại mà chỉ cập nhật cờ.  Sau khi thực hiện: . SI, DI tăng thêm 2 nếu cờ hƣớng DF = 0 (dùng lệnh CLD) . SI, DI giảm đi 2 nếu cờ hƣớng DF = 1 (dùng lệnh STD) 670
  156. Ví dụ . Cho 2 chuỗi đƣợc khai báo nhƣ sau: .DATA STRING1 DB 'ABC' STRING2 DB 'ACB' . Khảo sát đoạn chƣơng trình sau: MOV AX, @DATA MOV DS, AX MOV ES, AX CLD LEA SI, STRING1 LEA DI, STRING2 CMPSB CMPSB CMPSB 671
  157. Ví dụ (tiếp) Trƣớc lệnh CMPSB thứ 1 Sau lệnh CMPSB thứ 1 SI SI ZF ZF STRING1 'A' 'B' 'C' ? STRING1 'A' 'B' 'C' 1 Offset 0 1 2 Offset 0 1 2 DI DI SF SF STRING2 'A' 'C' 'B' ? STRING2 'A' 'C' 'B' 0 Offset 3 4 5 Offset 3 4 5 Sau lệnh CMPSB thứ 2 Sau lệnh CMPSB thứ 3 SI ZF ZF STRING1 'A' 'B' 'C' 0 STRING1 'A' 'B' 'C' 0 Offset 0 1 2 Offset 0 1 2 DI SI DI SF SF STRING2 'A' 'C' 'B' 1 STRING2 'A' 'C' 'B' 0 Offset 3 4 5 Offset 3 4 5 672
  158. 7. Tổng kết thao tác chuỗi Toán hạng Toán hạng Lệnh Dạng byte Dạng word nguồn đích Chuyển chuỗi DS : SI ES : DI MOVSB MOVSW Lƣu kí tự vào AL hay AX ES : DI STOSB STOSW chuỗi Nạp kí tự của DS : SI AL hay AX LODSB LODSW chuỗi Tìm kí tự trong AL hay AX ES : DI SCASB SCASW chuỗi So sánh chuỗi DS : SI ES : DI CMPSB CMPSW (Không lưu KQ) 673
  159. Nội dung chƣơng 5 5.1. Mở đầu về lập trình hợp ngữ 5.2. Các cấu trúc lập trình với hợp ngữ 5.3. Các lệnh logic, lệnh dịch và lệnh quay 5.4. Ngăn xếp và thủ tục 5.5. Các lệnh nhân, chia 5.6. Các lệnh thao tác chuỗi 5.7. Một số ví dụ 674
  160. 5.7. Một số ví dụ . Bài tập 1:  Đọc 1 chuỗi kí tự từ bàn phím cho đến khi gặp phím ENTER.  Hiện các kí tự vừa nhập theo chiều ngƣợc lại. . Bài tập 2:  Nhập nội dung chuỗi STR1 có tối đa 40 kí tự từ bàn phím. Quá trình nhập kết thúc khi gặp phím ENTER.  Duyệt qua chuỗi STR1, chuyển các kí tự chữ hoa sang chuỗi STR2.  Hiển thị nội dung chuỗi STR2 ra màn hình. 675
  161. Một số ví dụ (tiếp) . Bài tập 3: Dùng vòng lặp hiển thị ra hình vẽ sau: * . Bài tập 4: Dùng vòng lặp hiển thị ra hình vẽ sau: * 676