49
TRƯỜNG CAO ĐẲNG KINH TẾ KỸ THUẬT SÀI GÒN KHOA: ĐIỆN – ĐIỆN TỬ - CNTT TÀI LIỆU THỰC HÀNH CẤU TRÚC MÁY TÍNH

251_tai Lieu Thuc Hanh Ctmt-sv

Embed Size (px)

Citation preview

Page 1: 251_tai Lieu Thuc Hanh Ctmt-sv

TRƯỜNG CAO ĐẲNG KINH TẾ KỸ THUẬT SÀI GÒN

KHOA: ĐIỆN – ĐIỆN TỬ - CNTT

TÀI LIỆU THỰC HÀNH

CẤU TRÚC MÁY TÍNH

Page 2: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 1

TỔNG QUAN VỀ PHẦN MỀM MÔ PHỎNG 8086MICROCESOR EMULATOR (EMU 8086)

1. Mục đích :

Giúp sinh viên khảo sát các vấn đề về sử dụng phần mềm Emu8086 để mô phỏng hoạt động của vi xử lý 8086.

2. Thiết bị sử dụng: - Máy vi tính- Phần mềm Emu 80863. Giới thiệu:

Phần mềm Emu8086 là phần mềm cho phép mô phỏng hoạt động của vi xử lý 8086 bao gồm các câu lệnh cơ bản của 8086, xử lý ngắt mềm, giao tiếp với thiết bị ngoại vi, …… Các phiên bản mới của Emu 8086 có thể được download tại địa chỉ của trang web: www.emu8086.com

3.1 Các chức năng soạn thảo, dịch và thực hiện chương trình.

Dưới đây màn hình cho phép người sử dụng viết một chương trình hợp ngữ hoặc chạy thử một ví dụ có sẳn:

Page 3: 251_tai Lieu Thuc Hanh Ctmt-sv

New: tạo một chương trình mới, khi đó người dùng sẽ được hỏi xem sẽ tạo file chương trình dạng nào: COM, EXE, BIN hay BOOT.

Open: mở một file chương trình nguồn hợp ngữ.

Samples: Liệt kê các chương trình mẫu có sẳn do chương trình mô phỏng cung cấp.

Save: Lưu chương trình nguồn

Compile: dịch file chương trình nguồn

Emulate: Cho phép thực hiện chương trình nguồn. các trạng thái của quá trình thực hiện chương trình được hiển thị trên màn hình mô phỏng dưới đây.

Calculator: người dùng có thể nhập vào một biểu thức với các số là: có dấu, số dạng word hao85c dạng byte để tính toán. Kết quả tính toán được hiển thị một trong các dạng số thập phân, nhị phân, hexa hoặc số bát phân (cơ số 8)

Convertor: Bộ chuyển đổi giữa các cơ số.

Page 4: 251_tai Lieu Thuc Hanh Ctmt-sv

Hình: Màn hình mô phỏng chương trình

Các chức năng chính:

Load: Tải chương trình. Trước khi thực hiện thì chương trình sẽ được tải vào trong bộ nhớ. Chương trình có thể ở dạng các file thực hiện được như EXE, COM, BIN, BOOT hoặc dưới dạng file nguồn ASM.

Reload: người dùng có thể tải lại 1 chương trình.

Single Step: chạy chương trình theo chế độ từng lệnh. Với chế độ này người dùng có thể quan sát trạng thái các thanh ghi, bộ nhớ trong…

Run: chế độ chạy tất cả các lệnh trong chương trình

Trên màn hình người dùng có thể quan sát trạng thái các thanh ghi và đoạn bộ nhớ sử dụng cho đoạn mã lệnh của chương trình.

Phần registers mang nội dung của các thanh ghi trong đó các thanh ghi AX, BX, CX, DX được chia làm 2 nửa : phân cao (H) và phân thấp (L). ngoài ra , ta có thể xem nội dung các thanh ghi đoạn, con trỏ lệnh, ngăn xếp …

Phần bộ nhớ lưu trữ đoạn mã chương trình. Địa chỉ đoạn ( dạng hexa) được lưu trong thanh ghi CS. Danh sách địa chỉ offset được hiển thị dưới dạng hexa và thập phân.

Page 5: 251_tai Lieu Thuc Hanh Ctmt-sv

Ngoài ra người dùng có thể xem: Kết quả hiển thị lên màn hình ( nhắp chuột vào nút Screen) Mã nguồn của chương trình ( nhắp chuột vào nút Source) Trạng thái ALU (nhắp chuột vào nút ALU) Nội dung ngăn xếp (nhắp chuột vào nút Stack) Nội dung của thanh ghi cờ (nhắp chuột vào nút FLAG)

3.2 Các chương trình mẫu:

Emu8086 cung cấp cho người dùng 54 chương trình mẫu. chúng rất có ích cho người học lập trình hợp ngữ. từ các chương trình đơn giản như Hello world cho đến một số chương trình thao tác với một số thiết bị ngoại vi điển hình như màn hình, máy in… Để chạy thử các chương trình mẫu này , người dùng nhắp chuột vào nút Samples/ more Samples để chọn ra 1 file chương trình để chạy thử.

Bài thực hành số 2

Mục đích Làm quen với ngôn ngữ lập trình Assembly

Biết cách viết, dịch, chạy và chẩn lỗi (debug) một vài chương trình đơn giản

Tóm tắt lý thuyếtHợp ngữ (assembler) là ngôn ngữ bậc thấp, giúp cho người lập trình không phải ghi nhớ mã

máy (opcode) mà sử dụng các từ ngữ gợi nhớ (pseudo-code) gần với ngôn ngữ tự nhiên để miêu tả công việc cần thực hiện. Tuy vậy, assembler rất gần với ngôn ngữ máy, đòi hỏi người lập trình phải hiểu biết tương đối đầy đủ về cấu trúc phần cứng máy tính.

Với mỗi kiểu kiến trúc của bộ vi xử lý, có một bộ lệnh riêng, do đó, có một ngôn ngữ assembler riêng cho nó. Ở đây, chúng ta nghiên cứu assembler cho các bộ vi x ử l ý Intel thuộc họ x86. Các chương trình sẽ được viết cho chế độ thực (real mode) trong DOS và được biên dịch bằng Turbo Assembler.

Cấu trúc thông thường của một chương trình hợp ngũ

.model <Khai báo kiểu chương trình>

.stack <Khai báo kích thước ngăn xếp>

.data<Khai báo dữ liệu>

.code<Các lệnh>

Page 6: 251_tai Lieu Thuc Hanh Ctmt-sv

end

Ví dụ: Chương trình sau in ra màn hình dòng chữ “Hello !”

.model small

.stack 100h

.datas DB “Hello !$” ; khai báo xâu kí tự cần in

.codemov AX,@data ; lấy địa chỉ data segment ghi vào

DSmov DS,AX ; Vì model small, đây cũng là địa

chỉ; segment của xâu s

; xuất chuỗimov DX, OFFSET s ; lấy địa chỉ offset ghi vào DXmov AH , 9int 21h ; gọi hàm 9, ngắt 21h để in

mov AH, 4Ch ; Thoát khỏi chương trìnhint 21h

end

Lưu ý:- Mọi chương trình đều phải có đoạn code thoát khỏi chương trình, nếu không chương

trình sẽ không dừng khi hết chương trình của mình.

Khai báo biến trong hợp ngữ

Cú pháp:<tên biến> D<Kiểu DL> <giá trị khởi tạo>

hoặc<tên biến> D<Kiểu DL> <số phần tử> dup(<giá trị khởi tạo>)

Các kiểu dữ liệu: B (1 byte), W (2 bytes), D (4 bytes)Nếu không khởi tạo, dùng dấu hỏi “?”

Ví dụ:

Khai báo trong C Khai báo trong hợp ngữchar ch; ch DB ? char ch = ‘a’; ch DB ‘a’char ch = 5; ch DB 5char s[]=”\nhello world!” s DB 10,13,”hello world!$”int i=100; i DW 100long l; l DD ?char a[] = {1,2,3}; a DB 1,2,3char a[100]; a DB 100 dup(?)char a[100][50]; a DB 100 dup(50 dup(?))

Page 7: 251_tai Lieu Thuc Hanh Ctmt-sv

Dịch, liên kết, chạy và chẩn lỗi chương trình từ dấu nhắc DOS

Cần có các file: tasm.exe (dịch), tlink.exe (liên kết), td.exe (chẩn lỗi). Các bước như sau:

B1. Thiết lập đường dẫn

path = %path%;<đường dẫn đến thư mục chứa các file kể trên>

B2. Biên dịch từ file .ASM sang file .OBJ

Tasm <tên file chương trình>.ASM

B3. Biên dịch từ file .OBJ sang file .EXE

Tlink <tên file>.OBJ

B4: chạy chương trình:

<tên file>.EXE

B5: chẩn lỗi (nếu cần thiết)

Td <tên file>.EXE

Để tự động hóa, ta có thể tạo file .BAT chứa các lệnh trên.

Ví dụ:

Tạo file RunASM.bat trong cùng thư mục với tập tin .ASM với nội dung như sau :

tasm %1 tlink %1%1

(%1 là lấy tham số thứ nhất trong command line)Sau đó để biên dịch, liên kết và thực thi chương trình hello.ASM ta chỉ cần gõ :

RunASM hello

Công cụ EditPlus

Đây là công cụ soạn thảo văn bản tiện dụng, cho phép tự động đổi màu chữ theo cú pháp. Ngoài ra còn có thể thiết đặt phím tắt để gọi các tiện ích khác. Để dùng cho soạn thảo chương trình assembler, cần copy file định nghĩa cú pháp vào thư mục cài đặt và đăng kí sử dụng nó cho những file có tên mở rộng “.asm”.

B0. Cấu hình Edit Plus

B1. Biên dịch file .ASM : nhấn Ctrl + 1 sẽ biên dịch file đang soạn thảo thành .OBJ

B2. Liên kết : nhấn Ctrl + 2 sẽ biên dịch file .OBJ thành .EXE

B3. Chạy chương trình : nhấn Ctrl + 3 sẽ chạy chương trình .EXE

Page 8: 251_tai Lieu Thuc Hanh Ctmt-sv

B4. Chẩn lỗi chương trình : nhấn Ctrl + 4 sẽ debug chương trình .EXE

Lưu ý: - Để tránh phiền phức khi làm việc với Turbo Assembler, tránh đặt tên thư mục có chứa

khoảng trắng.- Trước khi nhấn Ctrl + 1 lần đầu tiên, nhớ lưu chương trình với tên cần thiết.

Một số lệnh cơ bản

MOV des,src : chép dữ liệu từ src sang desINC des : tăng des một đơn vịDEC des : giảm des một đơn vịADD des,src : des = des + srcSUB des,src : des = des – srcINT num : gọi ngắt

Bài tập

Bài 1. Viết CT nhập vào 1 ký tự, xuất ra ký tự đóVí dụ:

Moi ban nhap 1 ky tu: bKy tu vừa nhập: b

Bài 2. Viết chương trình xuất ra màn hình một số dòng.Ví dụ: De chay duoc 1 CT hop ngu ban can thuc hien cac buoc sau:

Dich file ASM thanh file OBJLien ket file OBJ thanh file EXEChay file EXE

Bài 3. Viết CT nhập vào 1 ký tự, xuất ra ký tự liền trước và liền sau.Ví dụ:

Moi ban nhap 1 ky tu: bKy tu lien truoc: aKy tu lien sau: c

Bài 4. Viết CT nhập vào 1 ký tự thường. In ra ký tự HoaVí dụ:

Moi ban nhap 1 ky tu: bKy tu Hoa: B

Bài 5. Viết CT nhập vào 1 ký tự hoa. In ra ký tự thườngVí dụ:

Moi ban nhap 1 ky tu: B

Page 9: 251_tai Lieu Thuc Hanh Ctmt-sv

Ky tu thường: b

Bài 6. Viết chương trình nhập vào 2 số nguyên dương x1, x2 (1 x2 < x1 < 9). Xuất ra kết quả các phép tính: x1-1, x1 +2, x1+x2, x1-x2

Ví dụ:x1 = 5x2 = 3x1 – 1 = 4x1 + 1 = 6x1 + x2 = 8x1 – x2 = 7

Mở rộng 1. Tự tìm hiểu xem hàm nào trong ngắt 21h dùng để nhập một xâu kí tự ? Ngoài ngắt 21h,

còn ngắt nào có thể dùng để nhập xuất từ bàn phím ? (dùng NortonGuide hoặc TechHelp). 2. Viết chương trình nhập tên và in ra màn hình câu “Hello ” + tên đã nhập.3. Tìm hiểu xem tại sao không có lệnh MOV x1, x2 (x1,x2 là hai biến trong bộ nhớ)4. Hai lệnh “INC AX” và “ADD AX, 1” khác nhau chỗ nào ?

Hướng dẫnBài 1. Để nhập 1 một ký tự sử dụng hàm 1 của ngắt 21h, để xuất, sử dụng hàm 2.

Ví dụ:mov AH,1int 21h ; kết quả trong AL

mov DL,AL ; kí tự cần xuất trong DLmov AH,2int 21h

Bài 2. Cặp kí tự xuống dòng là 10,13. Có thể khai báo nhiều xâu kí tự hoặc chung một xâu.Ví dụ: Msg3 DB 10,13,9,“1. Dich file ASM thanh file OBJ.$”Msg4 DB 10,13,9,“2. Lien ket file OBJ thanh file EXE.$”

Hoặc

Msg34 DB 10,13,9,“1. Dich file ASM thanh file OBJ.”DB 10,13,9,“2. Lien ket file OBJ thanh file EXE.$”

Bài 4,5. Kí tự hoa và kí tự thường của cùng một chữ cái tiếng Anh cách nhau 20h. Do đó, để chuyển đổi chữ hoa thành chữ thường và ngược lại, chỉ cần dùng lệnh ADD, SUB.

Bài 6. Để chuyển đổi các kí tự ‘0’ – ‘9’ thành số 0 – 9 chỉ cần thực hiện phép trừ đi 48 (mã của ‘0’). Sau khi thực hiện phép tính, chuyển đổi thành kí tự và in ra màn hình (có thể dùng biểu diễn Hex).

Page 10: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 3

Lệnh so sánh – Lệnh nhảy – Lệnh lặp

Mục đích Hiểu cách so sánh hai số trong hợp ngữ Hiểu cách thay đổi thứ tự thực hiện các lệnh Biết cách sử dụng các lệnh so sánh, nhảy và lặp

Tóm tắt lý thuyết

Lệnh so sánh

Trong hợp ngữ, muốn so sánh hai số, ta phải thực hiện một phép toán số học hoặc logic trên hai số đó và căn cứ vào các bit trong thanh ghi cờ rồi đưa ra kết luận. Để làm việc này, có thể dùng lệnh CMP và TEST.

Bản chất của lệnh CMP Des,Src là lệnh SUB Des,Src (thực hiện phép tính Des – Src) nhưng kết quả của phép tính không được lưu vào Des như trong lệnh SUB.

Ví dụ: so sánh hai số nguyên dươngMOV AH,1MOV AL,2CMP AH,AL

Sau khi thực hiện hai lệnh trên, cờ Carry (CF) bật, báo hiệu rằng AH < AL

Bản chất của lệnh TEST Des,Src là lệnh AND Des,Src (thực hiện phép tính Des AND Src) nhưng kết quả của phép tính không được lưu vào Des như trong lệnh AND.

Ví dụ: kiểm tra hai bit cuối cùng của AL

Page 11: 251_tai Lieu Thuc Hanh Ctmt-sv

TEST AL,3 ; 3h = 11bNếu cờ Zero (ZF) bật, có nghĩa là cả hai bit 0 và 1 của AL đều bằng 0.

Lệnh nhảy

Thông thường, khi một lệnh (instruction) được thực hiện, giá trị của thanh ghi IP (instruction pointer) được tự động cập nhật để trỏ đến lệnh kế tiếp. Ngoài ra, nội dung của thanh ghi IP chỉ có thể bị thay đổi thông qua một số lệnh đặc biệt. Đó là: các lệnh nhảy (J*), lệnh lặp (LOOP*), lệnh gọi hàm (call, ret), lệnh gọi ngắt (int, iret). Các lệnh này được xếp vào nhóm “Lệnh điều khiển luồng” (Program flow control instructions). Trong bài thực hành này, chúng ta sẽ học cách sử dụng các lệnh nhảy và các lệnh lặp.

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

JMP <target>

Có các trường hợp sau: JMP SHORT <tên nhãn> (short jump). Khi đó trong mã lệnh lưu 1 byte

khoảng cách (offset) giữa vị trí hiện tại và vị trí cần nhảy đến. Kiểu này chỉ nhảy trong phạm vi từ –128 đến +127 byte so với vị trí hiện tại.Ví dụ: JMP SHORT Calculate

JMP <tên nhãn> (near jump). Khi đó trong mã lệnh lưu 2 byte khoảng cách (offset) giữa vị trí hiện tại và vị trí cần nhảy đến. Kiểu này nhảy tùy ý trong phạm vi segment.Ví dụ: JMP Calculate

JMP FAR PTR <tên nhãn> (far jump). Khi đó trong mã lệnh lưu offset và segment của vị trí cần nhảy đến. Kiểu này nhảy đến bất kì chỗ nào.Ví dụ: JMP FAR PTR Calculate

JMP <con trỏ 2 byte> (near indirect jump). Khi đó trong mã lệnh lưu địa chỉ offset của một ô nhớ. Khi thực hiện, IP sẽ được gán bằng giá trị lưu tại địa chỉ này. Có thể kết hợp dùng với định vị chỉ số.

Ví dụ:myPointer DW Prepare, Calculate, Check, Output

...MOV bx,2 ; chỉ số trong mảng con trỏSHL bx,1 ; nhân đôiJMP myPointer[bx]...

Prepare: ; công việc 0...

Calculate: ; công việc 1...

Check: ; công việc 2 – nơi cần nhảy đến

...Output: ; công việc 3

...

Page 12: 251_tai Lieu Thuc Hanh Ctmt-sv

JMP <con trỏ 4 byte> (far indirect jump). Tương tự trường hợp trên, nhưng con trỏ gồm cả segment và offset. Chỉ khác ở khai báo con trỏ

Ví dụ:myPointer DD Prepare, Calculate, Check, Output

...MOV bx,1 ; chỉ số trong mảng con trỏMOV cl,2SHL bx,cl ; nhân 4JMP myPointer[bx]...

Prepare: ; công việc 0...

Calculate: ; công việc 1 – nơi cần nhảy đến

...

JMP <thanh ghi 2 byte> (indirect jump via regs). Nhảy đến địa chỉ lưu trong thanh ghi AX.

Ví dụ:MOV ax, offset Calculate...JMP ax ; (IP ← AX)

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

J.... <Label>

Các lệnh nhảy có điều kiện bắt đầu bằng chữ J sau đó là các chữ cái biểu thị điều kiện (ví dụ JGE ah,5: Jump if Greater than or Equal, nhảy nếu AH lớn hơn hay bằng 5), tiếp sau là một tên nhãn. Tùy thuộc vào trạng thái các cờ hiệu mà bộ vi xử lý có thực hiện việc nhảy đến nhãn hay không.

Đối với bộ vi xử lý 80286 trở xuống, lệnh nhảy có điều kiện có độ dài 2 byte, byte đầu tiên chứa mã lệnh, byte thứ hai chứa khoảng cách tương đối từ lệnh đến nhãn, vì vậy <Label> trong lệnh nhảy có điều kiện phải nằm trong khoảng từ -128 đến 127 so với vị trí lệnh nhảy. Muốn nhảy xa hơn ta phải dùng kết hợp lệnh nhảy không điều kiện JMP

Từ 80386 trở lên, bộ lệnh được bổ sung, cho phép sử dụng lệnh nhảy có điều kiện có độ dài 4 byte, do đó <Label> có quyền nằm tùy ý trong cùng phạm vi segment.

Khi sử dụng lệnh nhảy có điều kiện sau khi thực hiện phép so sánh, phải đặc biệt lưu ý toán hạng trong phép so sánh là số có dấu (signed) hay không có dấu (unsigned) để lựa chọn lệnh cho phù hợp.

Ví dụ:

Page 13: 251_tai Lieu Thuc Hanh Ctmt-sv

MOV AH,AL ; AL hiện bằng 128CMP AH,1JGE Greater ; AH > 1 nhưng không nhảy ????. . .

Greater:

Một số lệnh nhảy có điều kiện thường dùng (tham khảo thêm trong SGK trang 81): JE, JZ (nhảy nếu bằng). JA (nhảy nếu lớn hơn, không dấu), JG (nhảy nếu lớn hơn, có dấu), JB (nhảy nếu

nhỏ hơn, không dấu), JL (nhảy nếu nhỏ hơn, có dấu). JAE (nhảy nếu lớn hơn hay bằng, không dấu), JGE (nhảy nếu lớn hơn hay bằng,

có dấu), JBE (nhảy nếu nhỏ hơn hay bằng, không dấu), JLE (nhảy nếu nhỏ hơn hay bằng, có dấu).

JNE, JNZ (nhảy nếu không bằng).

Ví dụ: nếu AL là số nguyên không dấu thì đoạn chương trình ở trên phải sửa lại như sau:MOV AH,ALCMP AH,1JAE Greater. . .

Greater:

Lệnh lặp

Bằng cách dùng các lệnh nhảy có thể tạo ra vòng lặp. Tuy nhiên, để viết chương trình tiện lợi và ngắn gọn, có thể dùng thêm các lệnh lặp như LOOP, LOOPZ,…

Lệnh LOOP <Label> tự động giảm CX một đơn vị, sau đó kiểm tra xem CX có bằng 0, nếu không bằng thì nhảy đến nhãn <Label>

Lệnh LOOPZ <Label> tự động giảm CX một đơn vị, sau đó kiểm tra xem CX có bằng 0 hoặc cờ ZF có bật không, nếu cả hai điều này không xảy ra thì nhảy đến nhãn <Label>

Ví dụ: Nhập mảng A gồm 10 ký tự

MOV SI, 0 ; chỉ số mảngMOV CX, 10 ; số lần lặp

LAP:;nhập ký tựMOV AH, 1INT 21HMOV A[SI], ALINC SI

; xuất ký tựMOV AH, 2INT 21H

LOOP LAP

Page 14: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài tậpBài 1. Viết chương trình cho nhập 1 ký tự từ màn hình và xuất câu thông báo chào buổi sáng, buổi trưa hay buổi chiều tương ứng với ký tự nhậpvào là 'S', 's', 'T', 't', 'C', 'c'.

Bài 2. Nhập 2 số nguyên dương thuộc N,M thuộc [0..9], nhập 1 ký tự Char. Xuất ra màn hình ma trận gồm N dòng và M cột gồm ký tự Char.

Ví dụ: N=3, M=4, C='*' * * * *

* * * ** * * *

Bài 3. Nhập 2 số nguyên dương A, B. Tính A/B, A*B (không dùng lệnh DIV, MUL)Ví dụ: A=18, B=3

Tính A/B: 18 - 3 - 3 - 3 - 3 - 3 - 3 = 0, vậy A/B = 6 (tổng số lần A trừ B cho đến khi A = 0).Tính A*B = 18 + 18 + 18 = 54

Bài 4. Tìm USCLN của 2 số nguyên dương N, M nhập từ bàn phím. Kiểm tra N,M có là hai số nguyên tố cùng nhau không?

Ví dụ: N = 15, M = 6 => USCLN(15, 6) = 3Ví dụ: N = 3, M = 5 => USCLN(3, 5) = 1 => 3, 5 là 2 số nguyên tố cùng nhau.

Bài 5. Dùng lệnh lặp, viết chương trình nhập vào 1 chuỗi ký tự. Sau khi nhập xong đếm xem chuỗi có bao nhiêu ký tự. Xuất số ký tự có trong chuỗi.

Ví dụ: S = "Hello world !" ==> Số kí tự trong chuỗi là 13.

Bài 6. Nhập vào 2 chuỗi số, đổi 2 chuỗi thành số, sau đó cộng hai số, đổi ra chuỗi và xuất chuỗi tổng.

Ví dụ: S1 = "123" => N1 = 123S2 = "456" => N2 = 456N = N1 + N2 = 123 + 456 = 579 => S = "579" (xuất S ra màn hình)

Bài 7. Viết chương trình cho phép nhập vào một chuỗi S.Đổi tất cả ký tự thường thành ký tự hoa.Đổi tất cả ký tự hoa thành ký tự thường.

Bài 8. Nhập và xuất mảng 1 chiều. Tìm phần tử max, min, tính tổng các phần tử trong mảng.Ví dụ: N = 5

A[N] = {3,1,2,7,4} => max = 7, min = 1, tổng = 17.

Bài 9. Cài đặt thuật toán Bubble Sort dùng ASM.

Thuật toán Bubble Sort theo ngôn ngữ C như sau:for (int i = 0; i< N-1; i++)

for(int j=N-1;j > i; j--)if(a[j] < a[j-1])

Hoan_Vi (a[j], a[j-1]);

Bài 10. Nhập và xuất mảng A hai chiều. a. Tính tổng các phần tử trên đường chéo chính, đường chéo phụ.

Page 15: 251_tai Lieu Thuc Hanh Ctmt-sv

b. Đếm số phần tử 0 và phần tử khác 0 trong mảng.c. Tìm phần tử max của mỗi dòng, mỗi cột. Tính tổng của mỗi dòng, mỗi cột.d. Nhập 1 mảng hai chiều B, tạo một mảng hai chiều C có các phần tử trên dòng chẵn

bằng với các phần tử trên dòng chẵn của A, các phần tử trên dòng lẻ bằng các phần tử trên dòng lẻ của B.

Mở rộng 5. Trong bài tập 5, làm sao để đếm số từ có trong chuỗi kí tự?6. Trong bài tập 10, làm sao để thể hiện một menu cho phép người dùng chọn trong các kí tự

từ ‘a’ đến ‘d’ sau đó thực hiện công việc ứng với chữ cái đó.

Hướng dẫnBài 1. Xem ví dụ:

.MODEL SMALL

.STACK 100H

.DATACBS DB "CHAO BUOI SANG$"CBT DB "CHAO BUOI TRUA$"CBC DB "CHAO BUOI CHIEU$"

.CODEMOV AX, @DATAMOV DS, AX

;nhập 1 ký tự bất kỳMOV AH, 1INT 21H

CMP AL, 'S'JE CHAO_BUOI_SANG

CMP AL, 's'JE CHAO_BUOI_SANG

CMP AL, 'T'JE CHAO_BUOI_TRUA

CMP AL, 't'JE CHAO_BUOI_TRUA

CMP AL, 'C'JE CHAO_BUOI_CHIEU

CMP AL, 'c'JE CHAO_BUOI_CHIEU

CHAO_BUOI_SANG:LEA DX, CBSMOV AH,9INT 21HJMP THOAT

CHAO_BUOI_TRUA:LEA DX, CBTMOV AH,9INT 21H

Page 16: 251_tai Lieu Thuc Hanh Ctmt-sv

JMP THOAT

CHAO_BUOI_CHIEU:LEA DX, CBCMOV AH,9INT 21HJMP THOAT

THOAT:MOV AH, 4CHINT 21H

END

Bài 3. Để nhập một số nguyên, có thể làm như sau: đầu tiên nhập xâu kí tự chứa các số từ 0 đến 9, sau đó đổi từng kí tự ra số và nhân với các lũy thừa tương ứng của 10 và cộng lại.Bài 9. Xem ví dụ sau: Lặp gồm 2 vòng lặp (xếp mảng A có N phần tử tăng dần)

MOV N, 10 ;giả sử mảng A gồm N ký tự, trong ví dụ này N=10

MOV CX, N DEC CXMOV SI, 0

FOR_I:PUSH CXMOV CX, NMOV DI, 0MOV DL, A[SI]

FOR_J:

CMP DL, A[DI]JB LAPMOV BL, A[DI]MOV A[DI], DLMOV A[SI], BLMOV DL, A[SI]

LAP:INC DI

LOOP FOR_J

INC SIPOP CX

LOOP FOR_I

Page 17: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 4

Ngăn xếp – Thủ tục – Macro

Mục đích Hiểu được cơ chế hoạt động của ngăn xếp, quá trình gọi một thủ tục. Biết cách sử dụng ngăn xếp, khai báo và gọi thủ tục. Biết cách tạo và sử dụng macro.

Tóm tắt lý thuyết

Ngăn xếp1. Một số lưu ý:

Ngăn xếp (Stack) là vùng nhớ đặc biệt được truy cập theo cơ chế “vào trước ra sau” (LIFO – Last In First Out), nghĩa là dữ liệu nào đưa vào sau sẽ được lấy ra trước.

Ngăn xếp gồm nhiều phần tử, mỗi phần tử là một từ (2 bytes). Vị trí của ngăn xếp trong bộ nhớ được xác định bởi cặp thanh ghi SS:SP (SS chứa

địa chỉ đoạn, SP chứa địa chỉ ô của đỉnh ngăn xếp). Khi chưa sử dụng, ngăn xếp rỗng, vị trí được xác định bởi SP lúc đó là đáy ngăn xếp.

2. Khai báo: .STACK <kích thước của ngăn xếp>

Ví dụ: khai báo một vùng ngăn xếp có kích thước 256 bytes:.STACK 100h

Page 18: 251_tai Lieu Thuc Hanh Ctmt-sv

3. Các thao tác: Đưa trị vào (đỉnh) ngăn xếp:

PUSH <nguồn> ; đưa nguồn (thanh ghi hay từ nhớ ; 16 bit) vào đỉnh ngăn xếp

PUSHW <hằng> ; đưa trực tiếp một hằng16 bit vào ; đỉnh ngăn xếp

PUSHF ; đưa nội dung thanh ghi cờ vào đỉnh ; ngăn xếp

Lấy trị (ở đỉnh) ra khỏi ngăn xếp:POP <đích> ; lấy giá trị (2 bytes) ở đỉnh ngăn xếp

; đưa vào đích (thanh ghi (trừ thanh ; ghi IP) hay từ nhớ 16 bit)

POPF ; lấy giá trị (2 bytes) ở đỉnh ngăn xếp ; đưa vào thanh ghi cờ

Chú ý : Các lệnh PUSH, PUSHF, POP và POPF không ảnh hưởng tới các cờ.

Ví dụ: Chương trình xuất chuỗi ngược dùng stack:

Page 19: 251_tai Lieu Thuc Hanh Ctmt-sv

.model small

.stack 100h

.datamsg1 DB 'Nhap vao 1 chuoi: $'msg2 DB 10,13,'Chuoi nghich

dao la: $'.code

mov ax,@datamov ds,ax

mov ah,9lea dx,msg1int 21h

mov cx,0nhap:

mov ah,1int 21hcmp al,13je thongbaoxuatxor ah,ahpush axinc cxjmp nhap

thongbaoxuat:mov ah,9lea dx,msg2int 21h

xuat:pop axmov dl,almov ah,2int 21hloop xuat

mov ah,4chint 21h

END

1. Khai báo

2. Nhập lần lượt a,b,c đưa vào ngăn xếp: Nhập ký tự ‘a’:

00 61

Nhập ký tự ‘b’:

00 6200 61

Nhập ký tự ‘c’:

00 6300 6200 61

3. Xuất các giá trị trong ngăn xếp

Xuất ký tự ‘c’:

00 6300 6200 61

Xuất ký tự ‘b’:

00 6200 61

Xuất ký tự ‘a’:

00 61

000h…0FCh0FCh

SS:SP

…0FCh0FChSS:SP

000h

…0FCh0FChSS:SP

000h

100h

000h…0FCh0FCh

100hSS:SP

…0FCh0FCh

SS:SP

000h

100h

…0FCh0FCh

SS:SP 000h

100h

…0FCh0FCh

SS:SP 000h

100h

100h

100h

Page 20: 251_tai Lieu Thuc Hanh Ctmt-sv

Thủ tục

1. Khai báo:<Tên thủ tục> PROC <Kiểu>;kiểu là NEAR(mặc định) hay FAR

; thân thủ tục……………RET

<Tên thủ tục> ENDPThủ tục thường được viết ở cuối chương trình.

2. Gọi thủ tục:CALL <Tên thủ tục>CALL <Địa chỉ> ; địa chỉ là thanh ghi hoặc vùng nhớ chứa địa chỉ

; thủ tục3. Hoạt động của lời gọi thủ tục:

Khi thực hiện lời gọi thủ tục (CALL) thì: Địa chỉ ô của lệnh kế lệnh CALL (*) sẽ được cất vào ngăn xếp Địa chỉ ô của lệnh đầu tiên trong thủ tục được đưa vào IP

Khi thực hiện lệnh RET để quay về trình gọi thì: Địa chỉ trong ngăn xếp được lấy ra và được vào IP.

Do đó, nếu trong thủ tục có thao tác với ngăn xếp thì trong thủ tục, trước khi thao tác với ngăn xếp ta nên lưu lại địa chỉ (*) ở trên (chính là giá trị hiện thời trong ngăn xếp) để quay trở về trình gọi. Xem mô tả trong ví dụ sau.

Page 21: 251_tai Lieu Thuc Hanh Ctmt-sv

Ví dụ: Nhập xuất chuỗi kí tự

.model small

.stack 100h

.codeCALL NhapCALL Xuat

mov ah,4chint 21h

;---------------------------------------------------Nhap PROC

pop bxmov ah,2mov dl,’?’int 21hxor cx,cx

nhap:mov ah,1int 21hcmp al,13je ketthucnhappush axinc cxjmp nhap

ketthucnhap:push bxRET

Nhap ENDP;---------------------------------------------------Xuat PROC

pop bxmov ah,2mov dl,13int 21hmov dl,10int 21hjcxz ketthucxuat

xuat:pop dxint 21hloop xuat

ketthucxuat:push bxRET

Xuat ENDPEND

1. Khai báo

2. Gọi thủ tục Nhap

CALL Xuat

IP = địa chỉ ô lệnh “pop bx”3. Lưu lại địa chỉ quay về

BX = địa chỉ lệnh “CALL Xuat”

4. Nhập ký tự a,b:

00 6200 61

5. Trả lại địa chỉ quay về

BX = địa chỉ lệnh “CALL Xuat”

CALL Xuat00 6200 61

6. Kết thúc thủ tục Nhập:

00 6200 61

IP = địa chỉ ô lệnh “CALL Xuat”

Lời gọi thủ tục xuất (CALL Xuat) cũng hoạt động tương tự như trên.

000h…0FCh0FCh

100hSS:SP

…0FCh0FChSS:SP

000h

100h

000h…0FCh0FCh

100hSS:SP

…0FCh0FCh

SS:SP

000h

100h

000h…0FCh0FCh

100h

SS:SP

000h…

0FCh

100h

0FChSS:SP

Page 22: 251_tai Lieu Thuc Hanh Ctmt-sv

Macro

1. Một số lưu ý: Khi chúng ta có nhiều đoạn code giống nhau, chúng ta có thể sử dụng macro để

thay thế, giống như chúng ta dùng define ở trong C. Bản chất là thay thế lời gọi macro bằng các lệnh trong thân macro. Các macro nên phục hồi những thanh ghi mà nó sử dụng trừ những thanh ghi

chứa kết quả.2. Khai báo:

<tên macro> MACRO <các đối số> ; thân macro

…………… ENDM

3. Hai cách sử dụng macro Tạo macro trực tiếp trong chươnng trình:

Các macro thường được khai báo ở đầu chương trình trước phần .code. Ví dụ: Xuất một chuỗi ra màn hình sử dụng macro

.model small

.stack 100h

.datachuoi1 db “hello”,10,13,’$’chuoi2 db “bye”,10,13,’$’

@xuatchuoi macro chuoilea dx,chuoimov ah,9int 21h

endm

.code…@xuatchuoi chuoi1@xuatchuoi chuoi2…

end

Xây dựng thư viện các macro: Tạo 1 thư viện (tập tin) chứa các macro include vào chương trình (thường trước phần .code) bằng lệnh include Ví dụ: Xuất một chuỗi ra màn hình sử dụng thư viện macro

THUVIEN.INC@xuatchuoi macro chuoi

Page 23: 251_tai Lieu Thuc Hanh Ctmt-sv

lea dx,chuoimov ah,9int 21h

endm

TestMacro.asm.model small.stack 100h.data

chuoi1 db “hello”,10,13,’$’chuoi2 db “bye”,10,13,’$’

INCLUDE THUVIEN.INC

.code…@xuatchuoi chuoi1@xuatchuoi chuoi2…

end

4. Các thành phần cục bộ của macro: Trong macro, ta cũng có thể khai báo các biến, nhãn cục bộ để tránh gây ra lỗi khi

gọi macro nhiều lần. Cú pháp :

LOCAL <danh sách các nhãn, các biến cục bộ> Ví dụ: Xuất một chuỗi hằng ra màn hình sử dụng macro với biến cục bộ

.model small

.stack 100h

@xuatchuoi macro chuoi LOCAL chuoicucbo, nhancucbo .data

chuoicucbo db chuoi,’$’ .code

lea dx,chuoicucbomov ah,9int 21h

endm

.code…

nhancucbo:…

Page 24: 251_tai Lieu Thuc Hanh Ctmt-sv

@xuatchuoi <“hello”,10,13>@xuatchuoi ”bye”…

end

Lưu ý: nếu cần truyền chuỗi phức tạp thì ta cần sử dụng <…> để báo cho trình biên dịch biết đây là một đối số.

Bài tập

Bài 1: Viết chương trình kiểm tra một biểu thức đại số có chứa các dấu ngoặc (như (), [] và {}) là hợp lệ hay không hợp lệ .

Ví dụ: (a + [b – { c * ( d – e ) } ] + f)

là hợp lệ nhưng(a + [b – { c * ( d – e )] } + f)

là không hợp lệ.

Bài 2: Tính giá trị biểu thức đã nhập ở bài tập 2 theo thứ tự từ trái sang phải.

Bài 3: Viết lại các bài tập tuần trước dưới dạng các thủ tục

Bài 4: Xây dựng một thư viện các macro

Mở rộng7. Có những cách nào để truyền tham số cho thủ tục ? để nhận kết quả trả về ? 8. Thử viết một thủ tục đệ quy.9. Tìm hiểu cách phân chia chương trình thành nhiều file và cách biên dịch, liên kểt chúng.

Hướng dẫnBài 1. dùng ngăn xếp để PUSH các dấu ngoặc trái ( ‘(‘, ’{‘, ‘[‘ ) vào ngăn xếp. Nếu gặp dấu ngoặc phải ( ‘)’, ‘}’, ‘]’ ) thì POP từ stack ra. Nếu không POP được, hoặc POP ra không đúng loại với dấu ngoặc phải -> không hợp lệ . Ngược lại là biểu thức hợp lệ.

Page 25: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 5

Làm việc với số nguyên

Mục đích Biết sử dụng các phép toán logic, số học Biết cách đổi giữa các cơ số nhị phân, thập phân và thập lục phân

Tóm tắt lý thuyết

Phép toán trên bit

1. NOT : lệnh này đổi tác tố đích thành số bù. Không có cờ nào bị ảnh hưởng2. AND (OR hoặc XOR) : AND (OR, XOR) Đích, nguồn

Tất cả các cờ đều bị ảnh hưởng Chú ý : AND dùng để xóa các bit. OR dùng để bật các bit. XOR dùng để đảo bit.

3. Các lệnh dịch bit SHL và SHR : dịch các bit của toán hạng đích sang trái (hoặc phải) một hay nhiều bit.

SHL (SHR) Đích, 1 hoặc SHL (SHR) Đích, CL CL là số lần dịch bit.Việc dịch bit trái (phải) tương ứng với phép nhân (chia) cho lũy thừa 2. Chú ý : Hiện tượng tràn số có thể xảy ra và cờ CF chứa bit cuối cùng bị dịch ra khỏi toán hạng.Để dịch bit với các số âm ta nên dùng SAL hoặc SAR tương ứng.

4. Các lệnh quay ROL và ROR : dịch các bit của toán hạng đích sang trái (phải) một hay nhiều bit theo vòng tròn.

ROL (ROR) Đích, 1 hoặc ROL (ROR) Đích, CL CL là số lần quay bit, cờ CF sẽ chứa giá trị bit bị dịch ra khỏi toán hạng. Chú ý : Để dịch bit qua cờ nhớ ta dùng RCL hoặc RCR tương ứng. Ví dụ : Sử dụng lệnh ROL để đếm số bit 1 trong thanh ghi BX

XOR AX,AX MOV CX,16

TOP : ROL BX, 1 JNC NEXT ; kiểm tra có phải là bit 0 không INC AX ; nếu không phải thì tăng số bit 1

NEXT: LOOP TOP ; lặp cho đến khi làm xong

Lệnh số học

1. Cộng ADD, ADC : ADD (ADC) đích , nguồn Ví dụ : ADD AL , 10H -> AL = AL + 10H 2. Trừ SUB, SBB : SUB (SBB) đích , nguồn Ví dụ : SUB BL, 10H -> BL = BL – 10H Chú ý : Các phép toán cộng trừ trực tiếp giữa các ô nhớ là không hợp lệ. Ngoài ra ta cũng có thể sử dụng INC hoặc DEC để cộng hoặc trừ 1 đơn vị vào nội dung một ô nhớ hoặc một thanh ghi.

3. Nhân MUL, IMUL: MUL (IMUL) nguồn Lệnh MUL thực hiện phép nhân không dấu, còn IMUL là lệnh nhân có dấu. Nếu nguồn là byte (8 bit) thì kết quả chứa trong AX và AX = AL * nguồn. Nếu nguồn là word (16

Page 26: 251_tai Lieu Thuc Hanh Ctmt-sv

bit) thì kết quả chứa trong DX:AX và DX:AX = AX * nguồn. Nếu nguồn là double (32 bit) thì kết quà chứa trong EDX:EAX và EDX:EAX = EAX * nguồn.

4. Chia DIV, IDIV : DIV (IDIV) số chia Lệnh DIV thực hiện chia không dấu, còn IDIV là lệnh chia có dấu. Nếu số chia là byte (8 bit) thì số bị chia là AX và kết quả gồm: phần dư = AH, phần thương = AL. Nếu số chia là word (16 bit) thì số bị chia là DX:AX và kết quả gồm phần dư = DX, phần thương = AX. Nếu số chia là double thì sô bị chia là EDX:EAX và kết quả gồm phần dư = EDX, phần thương = EAX. Chú ý : phải xoá giá trị DX hoặc EDX trước khi nhân, hoặc chia.

Bài tập

1. Viết chương trình (VCT) đổi một số dạng thập phân sang thập lục phân.Ví dụ: Nhập một số hệ 10 : 26 Dạng thập lục phân: 1A

2. VCT nhập một số hệ thập phân rồi xuất ra biểu diễn dạng nhị phân của nó.Ví dụ: Nhập số hệ 10: 26 Dạng nhị phân: 11010

3. VCT đổi một số dạng thập lục phân sang sang thập phân.Ví dụ: Nhập số hệ thập lục phân: 1a (hoặc 1A) Dạng thập phân của nó là: 26

4. VCT đổi một số dạng thập lục phân sang nhị phân Ví dụ: Nhập số hệ thập lục phân: 1a (hoặc 1A) Dạng biểu diễn nhị phân là : 00011010

5. VCT đổi một số dạng nhị phân sang thập phânVí dụ: Nhập một số nhị phân: 11010 Dạng thập phân là: 26

6. VCT đổi một số dạng nhị phân sang thập lục phânVí dụ: Nhập một số nhị phân: 11010 Dạng thập lục phân là: 1A

7. VCT “echo” với yêu cầu: nhập vào số nguyên dương n và một kí tự bất kì, sau đó trên màn hình xuất hiện n lần kí tự đó.Ví dụ: Nhập một kí tự: k Nhập số lần n : 5 Kết quả : kkkkk.

8. VCT nhập vào hai số nguyên dương. Tính tổng, hiệu, tích, thương (phép div) và phần dư khi chia 2 số nguyên (phép mod)Ví dụ: Nhập số thứ nhất : 14 Nhập số thứ hai : 16 Tổng hai số là : 30 Hiệu: -2 Tích: 224 Thương: 0 Phần dư: 14

Mở rộng1. Tìm hiểu về BCD. Viết chương trình nhập 2 số nguyên ở hệ 10, chuyển sang BCD, tính

tổng, hiệu và in kết quả ở hệ 10.2. Liệu có thể viết chương trình tính được 20!, 30!, kết quả in ra ở dạng hex ? dạng cơ số

10 ?

Page 27: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 6

Làm việc với xâu kí tự

Mục đích Biết sử dụng các phép toán trên chuỗi Biết làm một số thao tác với xâu kí tự (tìm kiếm, đếm từ, chuyển hoa / thường …. )

Tóm tắt lý thuyết

Cờ hướng DF (Direction Flag) : xác định hướng xử lí chuỗi. Khi DF = 0 (dùng lệnh CLD) chuỗi được xử lí tăng dần, ngược lại DF = 1 (lệnh STD) chuỗi được xử lí giảm dần.

Con trỏ chuỗi: DS:SI – địa chỉ nguồn và ES:DI – địa chỉ đích Các lệnh trên chuỗi :

1. MOVSB (MOVSW) : chuyển nội dung của byte (word) được định bởi DS:SI đến byte (word) được chỉ bởi ES: DI. Sau đó SI và DI tự động tăng lên 1 (hoặc 2) nếu cờ DF = 0 hay giảm 1 (hoặc 2) nếu DF = 1

Ví dụ: giả sử cần chép nội dung chuỗi thứ nhất : ‘HELLO’ vào chuỗi thứ hai theo thứ tự ngược lại ta làm như sau :

.DATA STR1 DB ‘HELLO’ STR2 DB 5 DUP(‘?’)

.CODE MOV AX, @DATAMOV DS, AXMOV ES, AX LEA SI, STR1+4 ; cuối STR1 LEA DI, STR2 ; đầu STR2STD ; định hướng xử lí giảm MOV CX, 5

move : MOVSB ADD DI,2 ; + 2 do DI bị giảm

; 1 sau lệnh MOVSBLOOP move

2. STOSB (STOSW): chuyển nội dung của thanh ghi AL (AX) đến byte

(word) được định bởi ES:DI. Sau đó DI tự động tăng lên 1 (hoặc 2) nếu cờ DF = 0 hay giảm 1 (hoặc 2) nếu DF = 1.

Ví dụ: Đọc và lưu một chuỗi kí tự bằng chức năng AH = 1, ngắt 21H

NhapChuoi PROC ;Vào: DI = chứa offset của chuỗi ;Ra: DI = nội dung chuỗi vừa nhập ; BX = kích thước chuỗi

Page 28: 251_tai Lieu Thuc Hanh Ctmt-sv

CLD ; đặt cờ DF theo hướng tăng XOR BX, BX ; gán BX = 0MOV AH, 1 INT 21H

while1 : CMP AL, 13 ; nếu gõ ENTER JE end_while1 ; kết thúc nhập CMP AL, 8 ; nếu gõ BSJNE else1 ;không phải lưu chuỗi DEC DI ;ngược lại lùi 1 kí tự DEC BX ;giảm kích thước chuỗi JMP read ; đọc kí tự khác

else1: STOSB INC BX

read: INT 21H JMP while1

end_while1: ; thoát khỏi vòng lặp

4. LODSB (LODSW) : chuyển nội dung của byte (word) được định bởi DS:SI vào AL (hoặc AX) sau đó tăng (hoặc giảm) SI 1 (hoặc 2) đơn vị. 5. SCASB (SCASW): tìm nội dung chứa trong AL (hoặc AX) có trong chuỗi định bởi ES:DI hay không. Nếu tìm thấy thì cờ ZF sẽ được bật. Sau mỗi lần thực hiện con trỏ DI sẽ tăng hoặc giảm 1 (hoặc 2) đơn vị. 6. CMPSB (CMPSW) : so sánh byte tại DS:SI và byte tại ES:DI, sau đó tăng (hoặc giảm) SI và DI 1 (hoặc 2) đơn vị.

Bài tập

9. VCT nhập một chuỗi kí tự và in ra chuỗi theo thứ tự ngược lại. In chiều dài chuỗi.Ví dụ : Nhập chuỗi : abcd Chuỗi kết quả: dcba Chiều dài chuỗi: 4

10. VCT nhập họ tên .Sau đó biến tất cả thành chữ hoa rồi in ra. Biến tất cả thành chữ thường rồi in ra.Ví dụ: Nhập vào chuỗi : Thanh cHi khanG Chuỗi Hoa : THANH CHI KHANG Chuỗi kết quả thường: thanh chi khang

11. Nhập một chuỗi kí tự tính tần số xuất hiện của các nguyên âm.Ví dụ : Nhập chuỗi : Thanh Chi Khang Số lần xuất hiện của các nguyên âm là: 3

12. VCT nhập hai chuỗi, liệt kê các kí tự có mặt trong hai chuỗi.Ví dụ: Nhập chuỗi: computer và chuỗi : informatic

Các kí tự có mặt trong hai chuỗi : o, m, t, r

13. Nhập vào hai chuỗi kí tự, so sánh hai chuỗi (= > < ). Ví dụ: Chuỗi thứ nhất: forn Chuỗi thứ hai : form

Kết quả : Chuỗi thứ nhất > chuỗi thứ hai. 14. Nhập vào hai chuỗi kí tự, kiểm tra chuỗi thứ nhất là chuỗi con chuỗi tthứ hai không, không

phân biệt hoa thường.Ví dụ: Chuỗi thứ nhất : form Chuỗi thứ hai: inFoRMatic Kết quả : Chuỗi thứ nhất là con chuỗi thư hai

Page 29: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 7

Lập trình bàn phím

Mục đích Hiểu được cách thức hoạt động của bàn phím Biết cách sử dụng một số hàm liên quan đến bàn phím của ngắt 16h (BIOS ) và ngắt 21h

(DOS)

Tóm tắt lý thuyết

Nguyên tắc hoạt động của bàn phím

Bàn phím cho máy PC có nhiều loại: 83 phím, 84 phím, 101 phím,… Bên trong mỗi bàn phím là chip điều khiển 8049 và 8042. Khi một phím được nhấn (up-to-down) hay được thả (down-to-up), chip điều khiển ghi nhận phím đó bằng một (hoặc một vài) mã số (gọi là mã quét, scan code) và gửi mã này ra cổng 60h, đồng thời tạo tín hiệu ngắt IRQ1.

Ví dụ:- Khi phím chữ ‘a’ được nhấn rồi thả ra, ta nhận được 2 mã quét tương ứng là: 1E và 9E.

Thông thường, mã thả (up-code) bằng mã nhấn (down-code) cộng thêm 80h.- Tương tự, đối với Left-Control, 2 mã quét là 1D và 9D- Tuy nhiên, với Right-Control, ta nhận được 4 mã quét: 0E 1D (khi nhấn) và 0E 9D (khi

thả).

Tín hiệu IRQ1 gây ra ngắt 09h. Ngắt 09h này có nhiệm vụ chuyển đổi mã quét thành mã ASCII và lưu trữ vào bộ đệm bàn phím. Các chương trình có nhu cầu nhận thông tin từ bàn phím có thể sử dụng các hàm của ngắt 21h hoặc 16h để đọc bộ đệm này mà không cần quan tâm đến giá trị của mã quét.

Ví dụ: một chương trình nào đó chỉ cần dùng ngắt 16h, hàm 01 để kiểm tra xem người sử dụng có gõ dấu chấm câu (nhấn phím ‘.’) hay không mà không quan tâm đến đó là phím dấu chấm ở phần keypad (scan code = 53) hay là ở phần các phím cơ bản (scan code = 34).

Khi được gọi, trình phục vụ ngắt 09h sẽ đọc cổng 60h để lấy mã quét. Nếu phím được nhấn thuộc loại phím thường (ví dụ như các phím chữ a, b,…) mã quét sẽ được dịch ra mã ASCII tương ứng. Sau đó, giá trị của mã quét và mã ASCII được lưu vào bộ đệm bàn phím. Bộ đệm này có địa chỉ 0040h:001Eh, kích thước 16 word, được tổ chức như một mảng vòng với con trỏ đầu (head) lưu tại địa chỉ 0040h:001Ah, con trỏ cuối (tail) lưu tại địa chỉ 0040h:001Ch. Nếu phím được nhấn là loại phím mở rộng (ví dụ như F1, F2,…), trong bộ đệm sẽ lưu giữ số 0 và mã mở rộng của phím đó.

Ví dụ: Giả sử NumLock đang là OFF, bộ đệm bàn phím đang trống (head = tail = 0041Eh), khi lần lượt ấn các phím ‘a’, F10, ‘·’, ‘NumLock’, ‘·’keypad, ‘NumLock’, ‘·’keypad, ‘Delete’ bộ đệm sẽ có nội dung như sau:

Page 30: 251_tai Lieu Thuc Hanh Ctmt-sv

↓ 0041Ch a F10 · · (kp) · (kp) Delete

61 1E

00 44

2E 34

2E 53

00 53

E0 53

head ↑ tail ↑

Lưu ý rằng, việc nhấn phím NumLock không sinh ra một thông tin nào trong bộ đệm. Hai phím dấu chấm cho cùng một mã ASCII là 2Eh. Phím Delete cho cùng một mã mở rộng dù được nhấn trong chế độ NumLock là ON hay OFF.

Một số hàm của ngắt 16h (BIOS)AH = 00h. Lấy một phím từ bộ đệm bàn phím. Nếu bộ đệm trống, sẽ chờ cho đến khi một

phím được nhấn. Trả về mã quét trong AH, mã ASCII (hoặc mã mở rộng) trong AL.AH = 01h. Kiểm tra bộ đệm bàn phím. Nếu trống, bật cờ ZF. Nếu không trống, tắt cờ ZF, đọc

phím đầu tiên trong bộ đệm (trỏ đến bởi con trỏ head), trả về mã quét trong AH, mã ASCII (hoặc mã mở rộng) trong AL. Tuy nhiên, phím này không bị lấy ra khỏi bộ đệm.

AH = 02h. Kiểm tra tình trạng các phím đặc biệt. Hàm này trả về byte ở địa chỉ 0040h:0017h. Các bit (I,C,N,S,A,O,L,R) của byte này, tính từ cao xuống thấp, ứng với các phím:Insert CapsLock NumLock ScrollLock Alt Control LeftShift RightShift.Phím nào ở trạng thái ON thì bit tương ứng sẽ bật.

AH = 03h. Thay đổi tốc độ nhận phím. AL = 05h, BH = thời gian đợi trước khi lặp, BL = tần số lặp. BH có thể nhận các giá trị từ 0 (250ms) đến 3 (1000 ms). BL có thể nhận các giá trị từ 0 (30 lần/giây) đến 1Fh (2 lần/giây).

AH = 05h. Giả lập thao tác nhấn phím. CH = mã quét, CL = mã ASCII (hoặc mã mở rộng). Hàm này ghi giá trị của CH và CL vào bộ đệm bàn phím và trả về AL = 0, nếu bộ đệm còn chỗ trống. Trả về AL = 1 nếu không còn chỗ trống.

Một số hàm của ngắt 21h (DOS)AH = 01h. Đợi một phím được nhấn và trả lại mã ASCII của phím đó trong thanh ghi AL,

đồng thời hiển thị kí tự lên màn hình. Nếu đây là phím không có mã ASCII mà chỉ có mã mở rộng thì AL trả về 0. Để nhận được mã mở rộng, cần phải gọi hàm này một lần nữa. Nếu Ctrl-Break được nhấn thì ngắt 23h sẽ được gọi.

AH = 08h. Hàm này chỉ khác hàm 01h ở chỗ không thể hiện lên màn hình kí tự ứng với phím được nhấn.

AH = 07h. Hàm này khác hàm 08h ở chỗ không kiểm tra Ctrl-Break.AH = 0Ah. Nhập từ bàn phím một xâu kí tự có độ dài không quá N kí tự, kết thúc bởi mã 13h

(phím Enter). Vùng bộ nhớ để lưu trữ xâu kí tự phải được chuẩn bị trước ở địa chỉ DS:DX. Byte đầu tiên ở địa chỉ này phải lưu giá trị N. Khi trả về, byte thứ hai lưu độ dài xâu nhận được (không kể kí tự kết thúc 13h, mặc dù kí tự này vẫn được lưu vào vùng nhớ).

AH = 0Ch. Xóa sạch bộ đệm bàn phím và gọi một trong các hàm 01h, 07h, 08h, 0Ah. Trong AL lưu số hiệu của hàm cần gọi.

Bài tậpBài 1. KeyDetection. Sử dụng các hàm liên quan đến bàn phím của ngắt 16h. Viết chương trình kiểm tra xem có phím chữ cái nào được nhấn không, nếu có thì dùng chữ đó để in đầy màn hình. Nếu không thì tiếp tục in đầy màn hình bằng chữ cái được nhấn ở lần trước. Nhấn Esc để kết thúc.

Bài 2. Phím gõ tắt. Sử dụng các hàm liên quan đến bàn phím của ngắt 21h, viết chương trình cho phép nhập từ bàn phím một xâu kí tự độ dài không quá 79. Trong quá trình nhập, nếu người dùng

Page 31: 251_tai Lieu Thuc Hanh Ctmt-sv

nhấn phím F1, chương trình sẽ tự động chèn vào cụm từ “DH KHTN Tp.HCM”, nếu nhấn phím F2 chương trình sẽ tự động chèn vào cụm từ “Khoa CNTT – BM MMT&VT”. Cho phép dùng BackSpace để sửa lỗi. Khi nhập xong, in ra độ dài của xâu kí tự đó.

Mở rộng10. Trong bài tập 1, khi người dùng nhấn một chữ cái nào đó, thì chữ cái đó có lập tức xuất

hiện trên màn hình không ? Có thể giải thích như thế nào về khoảng thời gian trễ này ?11. Trong bài tập 2, làm sao để cho phép ngay sau khi nhấn F1 để thêm cụm từ, có thể nhấn

Esc để bỏ đi cụm từ vừa thêm.12. Để vượt qua giới hạn 79 kí tự trong bài tập 2, cần biết thêm kĩ thuật gì ?13. Viết một chương trình cho phép xem nội dung của bộ đệm bàn phím. Dùng chương trình

đó để quan sát sự thay đổi của bộ đệm khi bấm phím.

Hướng dẫnBài 1. Dùng hàm 01 của ngắt 16h để kiểm tra bộ đệm. Tuy nhiên phải nhớ rằng hàm này không lấy phím được nhấn ra khỏi bộ đệm bàn phím. Vì vậy, sau khi phát hiện có phím được nhấn, có thể gọi hàm 00 để lấy phím ra khỏi bộ đệm.

Ví dụ:

NextKey:;; trong khi chưa có phím nào được nhấn, ; ta xử lí những việc khác ở đây;

mov ah,1 ; kiểm tra bộ đệmint 16hjz NextKey ; vẫn không có gì, quay lạimov ah,0int 16h ; lấy ra khỏi bộ đệm

;; xử lí phím vừa nhận ở đây

jmp NextKey

Bài 2. Tạo một mảng 80 kí tự. Dùng hàm 8 của ngắt 21h để kiểm tra phím nào được nhấn. Nếu là phím có ASCII code khác 0, lưu vào mảng đồng thời in ra màn hình. Nếu là phím đặc biệt, gọi hàm 8 lần nữa để lấy mã mở rộng. Sau đó kiểm tra F1 hay F2 được nhấn để chèn cụm từ cần thiết vào mảng.

Ví dụ: Để xử lí nhập xâu và chèn macro, tham khảo đoạn chương trình sau

mac1 db 'DH KHTN Tp.HCM$'mac2 db 'Khoa CNTT - BM MMT&VT$'

...................NextKey:

mov ah,8 ; chờ nhấn phím, không hiển thịint 21h

Page 32: 251_tai Lieu Thuc Hanh Ctmt-sv

cmp al,0jnz NotSpec ; nếu là phím thườngint 21hcmp al,3bhjz InsMac1cmp al,3chjz InsMac2jmp NextKey

InsMac1:mov bx,offset mac1jmp InsMac

InsMac2:mov bx,offset mac2jmp InsMac

; thêm các macro khác ở đây; ........InsMac:

call Insert ; chèn macro ở DS:BX vào mảngjmp NextKey

NotSpec:;; lưu kí tự vào mảng;

Để cho phép sửa chữa bằng Esc, có thể kiểm tra mã ASCII, nếu là 8, viết ra 3 kí tự có mã ASCII lần lượt là 8,32,8. (3 kí tự này có nghĩa là: lùi con trỏ, viết khoảng trắng để xóa, lùi con trỏ lần nữa). Đồng thời phải giảm giá trị của biến lưu trữ độ dài xâu hiện thời.

Ví dụ: Để bổ sung tính năng dùng BckSpc, tham khảo đoạn chương trình sau:

BckSpc db 8,32,8,'$'...............

cmp al,8jnz InsChar ; nếu không phải BckSpc, lưucmp si,0 ; kiểm tra độ dài xâu hiện thờijz NextKeymov dx,offset BckSpc ; xóa kí tự trên màn hìnhprintStdec si ; xóa trong mảngjmp NextKey

InsChar:cmp si,maxLen ; dài quá 79 ?jz NextKeymov buffer[si],al ; lưu vào mảnginc sijmp NextKey

Ví dụ: Để in ra độ dài xâu vừa nhập (<80, là số nguyên có hai chữ số), có thể viết như sau:

printUInt macropush ax

Page 33: 251_tai Lieu Thuc Hanh Ctmt-sv

push bxpush dxmov bh,10div bhmov bx,axmov dl,bladd dl,48mov ah,2int 21hmov dl,bhadd dl,48mov ah,2int 21hpop dxpop bxpop ax

endm

Không quên kiểm tra độ dài xâu hiện thời trước mỗi thao tác thêm, bớt kí tự trong mảng !

Page 34: 251_tai Lieu Thuc Hanh Ctmt-sv

Bài thực hành số 8

Lập trình màn hình

Mục đích Hiểu được cách tổ chức bộ nhớ màn hình cho chế độ text 80x25 16 màu và chế độ graphic

SVGA 800x600 256 màu Biết truy xuất bộ nhớ bằng ngắt 10h và bằng cách đọc/ghi vào vùng nhớ màn hình

Tóm tắt lý thuyếtTổ chức bộ nhớThông tin thể hiện trên màn hình được quy định bởi dữ liệu ghi trong vùng nhớ màn hình. Dữ

liệu này được tổ chức khác nhau tùy vào chế độ thể hiện (display mode).Trong chế độ 03h (text 16 màu, 80x25) vùng nhớ màn hình bắt đầu từ địa chỉ B800h:0000.

Mỗi màn hình có 80x25 = 2000 kí tự. Mỗi kí tự được lưu trữ bởi 2 byte, byte thứ nhất lưu mã ASCII, byte thứ hai lưu thuộc tính thể hiện (bit 7 : nhấp nháy, bit 6-4 : màu nền, bit 3-0 : màu chữ). Như vậy mỗi màn hình ứng với 4000 byte. Trong chế độ này (03h) ta có thể sử dụng 4 trang màn hình khác nhau, đánh số từ 0 đến 3. Tại mỗi thời điểm chỉ có một trang được hiển thị, các trang khác ẩn nhưng vẫn có thể ghi dữ liệu lên đó. Địa chỉ của trang thứ k là B8000h + k x 1000h, nghĩa là mỗi trang chiếm 4096 byte, mặc dù chỉ 4000 byte là được sử dụng.

Trong chế độ 103h (SVGA, graphic 256 màu, 800x600) vùng nhớ màn hình bắt đầu từ địa chỉ A000h:0000. Mỗi điểm ảnh ứng với 1 byte lưu chỉ số màu. Như vậy, vùng nhớ màn hình trải dài 480000 byte, chia làm nhiều trang. Mỗi trang có kích thước bằng một segment 64KB. Chỉ số màu của điểm ảnh chính là số thứ tự của màu trong bảng màu. Mỗi màu trong bảng màu được xác định bởi 18 bit đại diện cho tỉ lệ 3 thành phần màu (R,G,B), mỗi thành phần 6 bit nhận giá trị từ 0 đến 63. Ở chế độ này, màn hình có thể biểu diễn được 218 màu khác nhau, nhưng tại một thời điểm thì chỉ thể hiện 256 màu khác nhau.

Một số hàm của ngắt 10h (BIOS)AH = 00h. Thay đổi chế độ hiển thị

AL : chế độ hiển thị. Nếu bit 7 bật thì màn hình không bị xóa khi thay đổi chế độ hiển thị.AL = 03h. Chọn chế độ đồ họa 80x25, 16 màu.

AH = 0Fh. Lấy chế độ hiển thị hiện thời. Kết quả:AH : số cộtAL : chế độ hiển thịBH : trang hiện thời

AH = 01h. Thay đổi kích thước con trỏ.CH : dòng quét đầuCL : dòng quét cuối

AH = 02h. Thay đổi vị trí con trỏ. DH : dòngDL : cột BH : trang

AH = 05h. Thay đổi trang thể hiện. AL : trang

AH = 0Ah. In ra kí tự tại vị trí con trỏ. BH : trangAL : mã ASCII

Page 35: 251_tai Lieu Thuc Hanh Ctmt-sv

CX : lặp bao nhiêu lầnAH = 09h. In ra kí tự tại vị trí con trỏ, nhưng cho phép đặt thuộc tính cho kí tự.

BH : trangBL : thuộc tínhAL : mã ASCIICX : lặp bao nhiêu lần

AH = 0Eh. In ra kí tự tại vị trí con trỏ, dịch con trỏ sang vị trí tiếp theo.BH : trangAL : mã ASCII

AX = 4F02h. In ra kí tự tại vị trí con trỏ, dịch con trỏ sang vị trí tiếp theo.BX : chế độ đồ họa ( = 103h : chể độ SVGA 256 màu 800x600)Nếu kết quả trả về trong AX khác với 004Fh thì hệ thống không thể chuyển sang SVGA.

Bài tậpBài 1. ChangePage. Chọn chế độ 03. Trên trang 0, ở tọa độ (8,10) viết dòng chữ “VIET NAM” màu đỏ trên nền trắng. Trên trang 1, ở tọa độ (12,7) viết dòng chữ “QUE HUONG TOI” màu vàng trên nền xanh. Làm biến mất con trỏ. Tạo vòng lặp chuyển qua lại giữa trang 0 và 1 cho đến khi một phím được nhấn.

Bài 2. Vạch màu. Khởi động chế độ 103h (SVGA). Bằng cách truy xuất trực tiếp vùng nhớ màn hình, hãy thể hiện 256 màu trong bảng màu mặc định bằng các vạch màu nằm cạnh nhau, mỗi vạch độ rộng 3 điểm ảnh. Sau khi nhấn phím bất kì, trở về chế độ 03 và kết thúc chương trình.

Mở rộng14. Trong bài tập 1, có nhận xét gì về tốc độ chuyển giữa hai trang ? Có cách nào để đạt được

kết quả tương tự (hai dòng chữ thay nhau xuất hiện) mà tốc độ chuyển đổi nhanh hơn ?15. Thay vì hai dòng chữ chớp tắt như bài tập 1, làm sao để thể hiện hai dòng chữ luân phiên

tiến lại gần nhau, rồi lại lùi xa nhau, rồi lại gần nhau….16. Tìm cách pha lại (định nghĩa lại) bảng màu, để sau khi nhấn Enter các vạch thể hiện trong

bài tập 2 đột nhiên biến thành một dải màu thay đổi từ sáng trắng đến xám, đến đen. Nhấn Enter lần nữa sẽ phục hồi lại dải màu như trước.

17. Nghiên cứu một thuật toán vẽ đường thẳng và viết chương trình vẽ những đoạn thẳng tùy ý trên màn hình.

Hướng dẫnBài 1.

Dùng hàm 05 của ngắt 10h để thay đổi trang.

Ví dụ:mov ah,05h ; set page to viewmov al,0int 10h

Dùng hàm 02 để nhảy đến vị trí cần thiết.

Ví dụ:mov ah,02h ; goto (8,10) on page 0

Page 36: 251_tai Lieu Thuc Hanh Ctmt-sv

mov dh,8mov dl,10mov bh,0int 10h

Để viết chữ có màu và dịch chuyển con trỏ, có thể gọi ngắt 2 lần như sau

Ví dụ:printStA proc

mov al,[si]cmp al,'$'jz Donemov ah,09hmov cx,1int 10hmov ah,0ehint 10hinc sijmp printStA

Done:ret

endp printStA

Để làm biến mất con trỏ, có thể dùng cách sauVí dụ:

mov ch,20h ; Hide cursormov cl,20hmov ah,1int 10h

Để chuyển đổi giữa hai màn hình, có thể viết:

Ví dụ:mov dl,0mov dh,5

next:xor dl,1 ; switch page number 0/1mov ax,dxint 10h ; change pagemov ah,1 ; check key pressedint 16hjz next

Bài 2.

Để chuyển giữa chế độ text và graphic, có thể dùng đoạn chương trình sau

Ví dụ:SVGA_ON proc

Page 37: 251_tai Lieu Thuc Hanh Ctmt-sv

push axpush bxmov ax,4f02hmov bx,103hint 10hpop bxpop axret

endp SVGA_ON

SVGA_OFF procpush axmov ax,0003hint 10hpop axret

endp SVGA_OFF

Để in một điểm ảnh, có thể dùng cách sau:Ví dụ:

push bxmov bx,800xor dx,dxmul bx ; dx:ax = y * 800pop bxadd ax,bx ; ax = ax + xadc dx,0 ; dx = 0 + carrycmp dx,pnjz Writecall SetPagemov pn,dx

Write:mov di,axmov al,cl

stosb