Cấu trúc máy tính - Chương 5: Lập trình hợp ngữ với 8088
Bạn đang xem 20 trang mẫu của tài liệu "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:
- cau_truc_may_tinh_chuong_5_lap_trinh_hop_ngu_voi_8088.pdf
Nội dung text: Cấu trúc máy tính - Chương 5: Lập trình hợp ngữ với 8088
- Cấu trúc máy tính Chương 5 LẬP TRÌNH HỢP NGỮ VỚI 8088 1
- 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 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. Bài tập 2
- 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. Cấu trúc chương trình 7. Dịch và chạy chương trình 8. Một số lệnh cơ bản 9. Vào-ra đơn giản 10. Các ví dụ 3
- 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. 4
- 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ữ. 5
- 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 Macro Assembler: . Các tệp: MASM.EXE, LINK.EXE, EXE2BIN.EXE TASM – Turbo Assembler: . Các tệp: TASM.EXE, TLINK.EXE . Chương trình biên dịch, mô phỏng lập trình hợp ngữ Intel 8086: Emulator 8086 6
- 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 7
- 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 8
- Ý nghĩa các trường trong lệnh . (1) 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). . (2) 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). 9
- Ý nghĩa các trường trong lệnh . (3) 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ả đó. . (4) Trường chú thích: Bắt đầu bằng dấu ";" theo sau đó là lời giải thích. 10
- 3. Dữ liệu của chương trình . Hợp ngữ cho phép biểu diễn dữ liệu 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 11
- Các chỉ thị định nghĩa dữ liệu Chỉ thị 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) 12
- 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] 13
- 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] 14
- 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 15
- 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ớ 16
- 6. Cấu trúc chương trình hợp ngữ . 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. 17
- 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. 18
- 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 19
- Đ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 20
- Đ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 21
- Đ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 22
- 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 23
- 7. 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) 24
- 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) 25
- Sử dụng Emulator 8086 . Cho phép: Viết mã hợp ngữ Mô phỏng/Debug 26
- 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 27
- 8. 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 28
- 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 29
- 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 30
- 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 31
- 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; 32
- 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. 33
- 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 34
- 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 35
- 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 36
- 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 37
- 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. 38
- 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 39
- 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 40
- 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 41
- 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 42
- 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 43
- 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 44
- 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. 45
- 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 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. Bài tập 46
- 5.2. Các cấu trúc lập trình hợp ngữ 1. Các lệnh liên quan 2. Cấu trúc rẽ nhánh 3. Cấu trúc lặp 47
- 1. Các lệnh liên quan . Các cấu trúc lập trình: Tuần tự Rẽ nhánh (điều kiện) Lặp . Các cấu trúc rẽ nhánh và lặp trong hợp ngữ được tạo bằng cách sử dụng 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 48
- 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. 49
- 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 . JMP NhanLenh 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] 50
- 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) 51
- 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. 52
- 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 53
- 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 54
- 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 55
- 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 56
- 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 57
- 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 58
- 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 59
- 2. Tạo cấu trúc rẽ nhánh . Các cấu trúc rẽ nhánh thông dụng (giả mã): IF THEN IF THEN ELSE CASE OF : : : Else END 60
- a. Cấu trúc IF THEN . IF THEN . Triển khai trong hợp ngữ: CMP ; suy ra từ JMPđksai BoQua ; các lệnh thực hiện BoQua: 61
- 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: 62
- b. Cấu trúc IF THEN ELSE . IF THEN ELSE . Triển khai trong hợp ngữ: 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: 63
- 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 Viec 1: 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 64
- 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: 65
- 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: 66
- 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: 67
- 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: 68
- 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: 69
- 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 70
- 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: 71
- 3. Cấu trúc lặp . Các cấu trúc lặp thông dụng (giả mã): FOR DO REPEAT UNTIL WHILE DO 72
- a. Lệnh lặp FOR . FOR DO . Triển khai trong hợp ngữ: ; JCXZ BoQua ; nếu CX = 0 thì không lặp VongLap: LOOP VongLap BoQua: 73
- 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 74
- b. Lệnh lặp REPEAT UNTIL . REPEAT UNTIL . Triển khai trong hợp ngữ: VongLap: ; thân vòng lặp CMP ; suy ra từ JMPđksai VongLap 75
- 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 76
- 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 77
- 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: 78
- 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: 79
- 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. Bài tập 80
- 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 81
- 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 82
- 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 83
- 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 84
- Lệnh NOT . Cú pháp: NOT đích . Lệnh này không ảnh hưởng đến cờ 85
- 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 86
- 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 87
- 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 88
- 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 89
- 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 90
- 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 91
- 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 92
- 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 MOV BX, AX LAP: ROL AX, 1 RCR BX, 1 LOOP LAP 93
- 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 94
- 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 95
- Đ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: 96
- 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 97
- 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 98
- 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 99
- Đ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: 100
- 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 101
- 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 102
- 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. Bài tập 103
- Ngăn xếp và thủ tục 1. Ngăn xếp 2. Thủ tục 3. Các ví dụ 104
- 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). 105
- 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. 106
- 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 107
- 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 108
- 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. 109
- 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 110
- 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 111
- 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ố 112
- 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 113
- 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 114
- 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 115
- 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 116
- 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 117
- 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) 118
- 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. 119
- 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. Bài tập 120
- 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 121
- 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 122
- Ả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. 123
- 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. 124
- 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. 125
- 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 126
- 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 127
- 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 128
- 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 129
- 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. Bài tập 130
- 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 131
- 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). 132
- 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. 133
- 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). 134
- 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) 135
- 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 136
- 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 137
- 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 138
- 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) 139
- 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 140
- 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: 141
- 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) 142
- 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 143
- 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) 144
- 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 145
- 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) 146
- 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' 147
- 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) 148
- 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 149
- 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 150
- 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) 151
- 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. Bài tập 152
- 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. 153
- 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: * 154