You are on page 1of 6

BÀI THỰC HÀNH 04

Xử lí STACK và PROC trong ASM


I. Yêu cầu :
- Tham khảo cách hoạt động của STACK và PROC

II. Giới thiệu về STACK


1. STACK : là một cấu trúc dữ liệu một chiều. Các phần tử cất vào và lấy ra theo phương
thức LIFO (Last In First Out). Mỗi chương trình phải dành ra một khối bộ nhớ để làm
ngăn xếp bằng khai báo STACK. Ví dụ : .STACK 100H
2. PUSH và PUSHF : dùng để thêm một phần tử vào ngăn xếp.
 Cú pháp : PUSH nguồn : đưa nguồn vào đỉnh ngăn xếp
PUSHF : cất nội dung thanh ghi cờ vào ngăn xếp
Chú ý : - Ở đây nguồn là một thanh ghi 16 bit hay một từ nhớ
3. POP và POPF : dùng để lấy một phần tử ra khỏi ngăn xếp.
 Cú pháp : POP đích : đưa nguồn vào đỉnh ngăn xếp
POPF : cất nội dung ở đỉnh ngăn xếp vào thanh ghi cờ
Chú ý : - Ở đây đích là một thanh ghi 16 bit (trừ thanh ghi IP) hay một từ nhớ
- Các lệnh PUSH, PUSHF, POP và POPF không ảnh hưởng tới các cờ
4. Ví dụ minh họa : dùng STACK trong thuật toán đảo ngược thứ tự như sau :
; Nhập chuỗi kí tự
Khởi động bộ đếm
Đọc một kí tự
WHILE kí tự <> 13 DO
Cất kí tự vào STACK
Tăng biến đếm
Đọc một kí tự
END_WHILE
; Hiển thị đảo ngược
FOR biến đếm lần DO
Lấy một kí tự từ STACK
Hiển thị nó
END_FOR
III. Làm quen với PROC
1. Khai báo PROC :
<tên proc> PROC [(NEAR/FAR)]
; thân thủ tục
………………..
RET
<tên proc> ENDP
Chú ý : Các thủ tục của hợp ngữ không có danh sách tham số vào và ra. Do vậy để liên
lạc giữa các thủ tục ta nên dùng thanh ghi và thêm vào các chú thích ở đầu thủ tục.
2. CALL và RET :
 Cú pháp : CALL tên thủ tục / địa chỉ của thủ tục
Lệnh CALL sẽ thực hiện như sau :
- Cất địa chỉ trở về (nằm trong thanh ghi CS: IP) vào ngăn xếp.
- IP sẽ được gán địa chỉ offset lệnh đầu tiên của PROC
- Trở về khi gặp lệnh RET pop_N. (sẽ thực hiện lệnh POP N lần trước khi trở
về).
- Giá trị CS: IP trở về sẽ được POP ra từ ngăn xếp
3. Ví dụ minh hoạ về STACK, CALL/RET : chương trình in một số nguyên (16 bit) ra màn
hình
PrintNum10 PROC
; số nguyên N nằm trong AX
PUSH BX CX DX
MOV CX, 0 ; so lan push (so ky tu)
laysodu:
XOR DX, DX ; cho DX = 0 trước khi chia
MOV BX, 10
DIV BX ; số dư trong DX, phần nguyên trong AX
PUSH DX ; lưu phần dư vào stack
INC CX
CMP AX, 0 ; đã hết chưa?
JNZ laysodu ; chưa hết, lấy số dư tiếp
MOV AH, 2
inso:
POP DX
ADD DL, '0'
INT 21H
LOOP inso
POP DX CX BX
RET
ENDP PrintNum10

IV. Các bài tập


1. Cài đặt thuật toán đảo ngược chuỗi kí tự bằng hợp ngữ.
2. 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) không
hợp lệ.
HD : 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ệ.
3. Tính giá trị biểu thức đã nhập ở bài tập 2 theo thứ tự từ trái sang phải.
4. Viết thủ tục in một số thập phân sang dạng Hexa. ví dụ : nhập vào 100 thì in ra là 64H

BÀI THỰC HÀNH 05


Xử lí mảng trong ASM
I. Yêu cầu :
- Hiểu biết các khái niệm về địa chỉ segment và offset.

II. Mảng một chiều : là một dãy thứ tự các phần tử có cùng một kiểu.
1. Khai báo :
 Mảng kí tự : ví dụ : MSG DB ‘abcdef’
 Mảng số : ví dụ : AW DW 10, 20, 30, 40, 50, 60
Trong đó địa chỉ của biến mảng gọi là địa chỉ cơ sở (base). Địa chỉ các phần tử là offset.
Chú ý : Ta có thể định nghĩa một mảng có các phần tử giống nhau nhờ vào toán tử
DUP, ví dụ : khai báo sau
repeat DB 100 DUP(0) có nghĩa là khai báo một mảng 100 phần tử, có
giá trị khởi tạo bằng 0.
2. Các chế độ địa chỉ
 Chế độ địa chỉ thanh ghi : trong chế độ này offset của toán hạng chứa trong
thanh ghi đóng vai trò như một con trỏ trỏ đến các ô nhớ. Thanh ghi dùng được là BX,
DI, SI. Ví dụ : SI chứa địa chỉ offset 0100h có giá trị 1234h khi đó khi thi hành lệnh sau
MOV AX, [SI] CPU sẽ kiểm tra địa chỉ từ nhớ (word) tại DS: 0100h sau đó
chuyển giá trị 1234h của ô nhớ này cho AX. Chú ý điều này khác với lệnh MOV AX, SI
 Chế độ địa chỉ cơ sở (base) và địa chỉ chỉ số (index) : trong chế độ này địa chỉ
offset của các toán hạng nhận được bằng cách cộng một độ dịch với nội dung của thanh
ghi. Các thanh ghi sẽ là BX, BP, SI, DI. Nếu ta dùng thanh ghi BX, SI, DI thì DS sẽ
chứa địa chỉ segment, còn nếu dùng BP thì SS sẽ chứa địa chỉ segment.
Ví dụ : giả sử W là một mảng word, BX chứa giá trị 4. Khi đó MOV AX, W[BX] sẽ
chuyển nội dung phần tử có địa chỉ W + 4 vào AX, đây là phần tử thứ 3 trong mảng
 Chế độ địa chỉ trực tiếp : khi đó địa chỉ của toán hạng sẽ được ghi tường minh
dưới dạng thanh_ghi_ segment : [thanh_ghi_pointer] . Xem ví dụ sau :
MOV AX, ES : [SI] nếu SI chứa địa chỉ 0100h thì địa chỉ toán hạng trong
trường hợp này là ES: 0100h.
III. Mảng hai chiều :
1. Khai báo : tương tự như mảng một chiều, xem ví dụ sau :
A DB 10, 20, 30, 40
DB 50, 60, 70, 80
DB 90, 100, 110, 120 sẽ khai báo một mảng A có 3 hàng x 4 cột
Chú ý : nếu mảng A có N phần tử trên mỗi hàng và mỗi phần tử có kích thước S byte
thì địa chỉ hàng thứ i (tinh tu 0) sẽ bắt đầu tại vị trí : A + i * N * S .
2. Các chế độ địa chỉ : gần như tương tự như trường hợp một chiều
Ví dụ : giả sử W là một mảng byte, BX chứa giá trị 2 và SI chứa 4. Khi đó lệnh sau
MOV AX, W[BX][SI] sẽ chuyển nội dung phần tử có địa chỉ W + 2 + 4 vào
AX, lệnh trên cũng tương đương như lệnh MOV AX, W[BX + SI]
IV. Bài tập về mảng :
1. Cài đặt chương trình sắp xếp lại mảng theo thứ tự tăng dần với số phần tử n nhập vào từ bàn
phím và n < 256.
2. Giả thiết rằng có một record kiểu mảng như sau :
BANGDIEM DB ‘ngọc lan ‘, 10 , 8 , 8 , 10
DB ‘kiều nga ‘, 8 , 8 , 9 , 10
DB ‘thu hiền ‘, 9 , 8 , 10 , 10
DB ‘ngọc thuý ‘, 8 , 7 , 8, 10
DB ‘thanh hằng ‘, 10 , 8 , 6, 10
trong đó mỗi tên chiếm 12 bytes. Hãy viết chương trình in ra tên của mỗi học sinh cùng với số
điểm trung bình của cô ta (làm tròn)

HD bài 1.
Giả sử ta có một mảng A kiểu DW gồm 5 phần tử như sau
.DATA
A DW 10, 50 , 30 , 20 , 40 ; có 5 phần tử
Khi đó chương trình sắp xếp mảng tăng dần như sau :

Giải thuật sắp xếp bằng hai vòng for Cài đặt bằng hợp ngữ
int temp; // biến trung gian LEA SI, A ; lấy phần tử A[0]
for (int i = 0; i < 5; i++) MOV CX , 5 ; số phần tử của mảng
for (int j = i; j < 5; j ++) FOR_I :
if (A[i] >= A[j]) { PUSH CX
temp = A[i]; // hoán đổi vị trí MOV DI, SI
FOR_J :
A[i] = A[j]; // A[i], A[j]
MOV AX, [DI] ;Lấy gtrị A[j]
A[j] = temp;
CMP [SI], AX ;Ktra A[i],A[j]
} JLE CONTINUE_J ;Nếu A[i] >= A[j]
XCHG [SI], AX ; Hdoi A[i],A[j]
MOV [DI], AX
CONTINUE_J:
ADD DI, 2
LOOP FOR_J ; vòng lặp j
POP CX
ADD SI, 2
LOOP FOR_I ; vòng lặp i

HD bài 2. Để tính được điểm trung bình của từng sinh viên thì ta phải biết được từng điểm của
sinh viên đó. Ta nên xem BANGDIEM là một mảng hai chìêu, do họ và tên chiếm 12 byte nên
điểm từng môn của sinh viên sẽ ứng với phần tử thứ [12] -> [15] trên từng dòng. Tính tồng
từng phần tử tương tự như bài 1 rồi chia cho 4 để ra điểm trung bình từng sinh viên.

BÀI THỰC HÀNH 06


Xử lí chuỗi trong trong ASM
I. Nhập xuất chuỗi :
 Hiển thị một chuỗi : AH = 09, ngắt 21H
Vào : DX = địa chỉ offset của chuỗi. Chuỗi phải kết thúc bằng kí tự ‘$’.
Chú ý : thay vì dùng lệnh MOV OFFSET ta có thể dùng lệnh LEA
 Nhập vào một chuỗi : AH = 0AH, ngắt 21H
Vào : DS:DX = địa chỉ của buffer, trong đó buffer[0] là kích thước tối đa của chuỗi,
buffer[1] sẽ là kích thước dữ liệu nhập.
Trả về : Chuỗi buffer chứa nội dung nhập vào từ buffer[2] trở đi
Yêu cầu xem thêm các chức năng AH = 3FH và AH = 40H của ngắt 21H.
IV. Thao tác trên chuỗi :
 Cờ định hướng (Direction Flag) : xác định hướng cho các thao tác chuỗi. Để DF = 0
ta dùng lệnh CLD (duyệt tăng), ngược lại để DF = 1 ta dùng lệnh STD (duyệt giảm).
 Chuyển một chuỗi :
1. MOVSB : chuyển nội dung của byte được định bởi DS:SI đến byte được chỉ
bởi ES: DI. Sau đó SI và DI tự động tăng lên 1 nếu cờ DF = 0 hay
giảm 1 nếu DF = 1
2. Lệnh REP : thực hiện lệnh ở toán hạng đi sau REP CX lần.
Ví dụ : nếu CX = 3 thì REP MOVSB sẽ tương đương với 3 lệnh MOVSB.
3. Ví dụ minh họa : 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 LEA DI, STR2 ; đầu STR2


STR1 DB ‘HELLO’ STD ; xác định hướng giảm
STR2 DB 5 DUP(‘?’) MOV CX, 5
.CODE move :
MOV AX, @DATA MOVSB
MOV DS, AX ADD DI,2; + 2 do DI bị giảm
MOV ES, AX ; 1 sau lệnh MOVSB
LEA SI, STR1+5; cuối STR1 LOOP move ; ………….

 Lưu chuỗi :
1. STOSB : chuyển nội dung của thanh ghi AL đến byte được định bởi ES:DI
Sau đó SI và DI tự động tăng lên 1 nếu cờ DF = 0 hay giảm 1 nếu DF = 1
2. STOSW : tương tự như STOSB nhưng sẽ lưu nội dung của AX và DF sẽ tăng
hoặc giảm 2 đơn vị.
3. Ví dụ minh họa : Đọc và lưu một chuỗi kí tự bằng chức năng AH = 1, ngắt 21H
… ……
; Vào : DI = chứa offset của chuỗi
; Ra : DI = chứa nội dung chuỗi vừa nhập, BX = kích thước chuỗi
CLD ; đặt lại cờ DF theo hướng tăng
XOR BX, BX ; gán BX = 0
MOV AH, 1
INT 21H
while1 :
CMP AL, 0DH ; kí tự xuống dòng
JE end_while1 ; kết thúc nhập
CMP AL, 8H ; ki tự Backspace
JNE else1 ; không phải thì lưu vào chuỗi
DEC DI ; lùi con trỏ 1 kí tự
DEC BX ;
JMP read ; đọc kí tự khác
else1 :
STOSB
INC BX
read :
INT 21H
JMP while1
endwhile :
…………. ; thoát khỏi vòng lặp

 Nạp và duyệt một chuỗi


1. LODSB : chuyển nội dung của byte được định bởi DS:SI vào AL sau đó tăng
(hoặc giảm) SI 1 đơn vị.
2. LODSW : tương tự nhưng chuyển nội dung vào AX và tăng hoặc giảm SI 2 đơn vị
3. SCASB : tìm nội dung chứa trong AL 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 đơn vị. Thông thường ta thương sử dụng SCASB với REPNE như sau :
MOV CX, ? ; số lần thực hiện
MOV AL, ? ; kí tự cần tìm
REPNE SCASB ; lặp lại việc tìm cho đến khi tìm thấy.
IV. So sánh chuỗi
 So sánh chuỗi :
1. CMPSB : 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 đơn vị.
2. CMPSW : tương tự nhưng tăng hoặc giảm SI và DI 2 đơn vị
3. REPE/REPNE CMPSW: thực hiện việc so sánh CMPSB (hoặc CMPSW) CX lần.

.data cld ; đặt hướng tăng


buff1 db 'abcdefgh' mov cx , 5
buff2 db 'abde' lea si , buff1
.code lea di , buff2
mov ax, @data repe cmpsb
mov ds, ax jne khacnhau
mov es, ax ;ngược lại giống nhau

 Tìm chuỗi con trong một chuỗi :


Thuật toán :
Thông báo / Đọc chuỗi con SUBST
Thông báo / Đọc chuỗi chính MAINST
Nếu (chiều dài của MAINST = 0) OR (chiều dài của SUBST = 0) OR
(SUBST dài hơn MAINST) thì SUBST không phải là chuỗi con của MAINST
Ngược lại :
Vị trí bắt đầu START = offset MAINST
Tính vị trí dừng STOP = START + chiều dài MAINST - chiều dài SUBST
Cuối Nếu
Vòng Lặp
So sánh các kí tự tương ứng trong MAINST bắt đầu từ START và SUBST
Nếu tất cả các kí tự đều giống nhau thì SUBST tìm thấy trong MAINST
Ngược lại START = START + 1
Lặp cho đến khi (SUBST tìm thấy) hoặc (START > STOP)
Hiển thị kết quả
V. Bài tập về chuỗi :
1. Viết chương trình cho nhập vào một chuỗi, in ra các từ trên các dòng khác nhau. Sau đó đếm
xem có bao nhiêu từ ‘hello’.

You might also like