Bây giờ chúng ta đã sẵn sàng để viết thường trình ngắt. Để xác
định xem sự hiển thị thời gian có được kích hoạt hay không ta sử dụng cờ
biến đổi được ON_FLAG. Cờ này được thiết lập bằng 1 khi thời gian
được hiển thị. MAIN là thủ tục ngắt
Tập tin PGM3_3.ASM
;chương trình thường trú bộ nhớ chỉ thời gian
; kích hoạt bằng tổ hợp phím Ctrl+Shift phải
EXTRN INITIALIZE:NEAR,SAVE_SCREEN:NEAR
EXTRN RESTOR_SCREEN:NEAR,SET_CURSOR:NEAR
EXTRN GET_TIME:NEAR
PUBLIC MAIN
110 trang |
Chia sẻ: huongthu9 | Lượt xem: 461 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Giáo trình Hợp ngữ - Nguyễn Hữu Lộc, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
SMALL
.CODE
NoiChuoi PROC
cld ; Chuỗi tăng dần
mov di,SEG ChuoiCuoi
mov es,di
mov di,OFFSET ChuoiCuoi ;ES:DI chỉ đến đích
mov si,ax ; Chuỗi đầu được chép đi
LapChuoi1:
lodsb ; nhận trong chuỗi 1 ký tự
and al,al ; bằng 0?
jz Chuoitiep ;đúng thì chuyển sang chuổi tiếp
stosb ; lưu 1 ký tự vào chuỗi
jmp LapChuoi1
Chuoitiep:
mov si,bx ; Chép chuỗi thứ hai
LapChuoi2:
lodsb ; lấy 1 ký tự từ chuỗi 2
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 54 -
stosb ; giữ ký tự của chuỗi 2 vào
; (kể cả số 0 nếu có)
and al,al ; bằng 0?
jnz LapChuoi2 ; không, nạp ký tự khác
ret ; xong
NoiChuoi ENDP
END
3. Lập thư viện - tạo vĩ lệnh (macro)
Thay vì liên kết các mođun đối tượng riêng biệt để tạo thành
một file .EXE , chúng ta có thể tạo ra một file thư viện của các
mođun đối tượng chứa thủ tục. Khi thư viện được xác định trong
quá trình liên kết, chương trình LINK lấy ra bất kỳ thủ tục nào mà
chương trình cần thư viện và tạo ra file EXE.
Chúng ta có dạng
Tên MACRO {thông số [ ,thông số] }
Lệnh
ENDM
Tạo tập tin văn bản ASCII là thư viện
Ví dụ:
THUVIEN.MAC
Thoat MACRO
MOV AH,4Ch
INT 21h
ENDM
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 55 -
HienCh MACRO Chuoi1
MOV AH,9
LEA DX, Chuoi1
INT 21h
ENDM
Dockt MACRO
MOV AH,1
INT 21h
ENDM
HienKt MACRO
MOV AH,2
INT 21H
ENDM
Ứng dụng: Hiện số nhị phân
EXTRN HienSoNP: NEAR
.MODEL SMALL
.STACK 100H
.DATA
Thongbao1 DB 'Nhập vào một ký tự: $'
Thongbao2 DB 'Mã ASCII số nhị phân: $'
.CODE
INCLUDE THUVIEN.MAC
Batdau PROC
MOV AX, @Data
MOV DS, AX
HienCh Thongbao1
DocKt
HienCh Thongbao2
Call HienSoNP
Thoat
Batdau ENDP
END Batdau
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 56 -
II. CÁC KIỂU ĐỊNH VỊ ĐỊA CHỈ
Chúng ta đã biết, mỗi lệnh đều có 2 phần chính:
Phần phép toán thực hiện (cộng, trừ, dịch chuyển,...)
Phần dữ liệu liên quan. Các dữ liệu này nằm trong các thanh
ghi hoặc trong bộ nhớ.
Để lấy dữ liệu trong bộ nhớ, bộ vi xử lý phải biết địa chỉ và số
byte dùng cho nó.
Sau đây là các loại định vị địa chỉ khác nhau:
1. Kiểu định vị địa chỉ tức thời
Thanh ghi <--- Giá trị tức thời
Một giá trị tức thời (có thể là một hằng) sẽ đưa vào nội dung
của thanh ghi
Ví dụ: MOV AH,12
1- Kiểu định vị địa chỉ trực tiếp:
Thanh ghi <-- bộ nhớ(địa chỉ trực tiếp)
Nội dung của một vùng nhớ được đặt tên sẽ ghi vào trong
thanh ghi 8 bit hoặc 16 bit phụ thuộc vào loại dữ liệu và kích thước
thanh ghi, nếu 2 yếu tố này không bằng nhau thì trình dịch hợp ngữ
sẽ báo lỗi.
Ví dụ:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 57 -
Id1 DB 2 ; 1 byte
Id2 DW 5 ; 1 word = 2 byte
......
MOV AH,Id1
MOV BX,Id2
3. Kiểu định vị địa chỉ nền:
Thanh ghi <-- [BX] địa chỉ nền dựa trên DS
Lấy nội dung trong vùng bộ nhớ địa chỉ DS:[BX] đưa vào
trong thanh ghi. Trong trường hợp này [BX] cho biết là lấy nội dung
của ô nhớ có phần offset của địa chỉ là . Có thể thực hiện với 8 hoặc
16 bit.
Ví dụ: MOV BX,8
MOV AX, [BX]
AX <-- nội dung của vùng nhớ có địa chỉ là DS:0008
4. Kiểu định vị địa chỉ chỉ sốù:
Thanh ghi <-- [SI] hoặc [DI] địa chỉ chỉ số
Kiểu định vị địa chỉ này thường dùng cho chuỗi ký tự hay các
phần tử của mãng. Thường nền là DS.
Ví dụ: MOV SI, 0
MOV AX, [SI]
AX <-- nội dung của vùng bộ nhớ ở địa chỉ DS:0
5- Kiểu định vị địa chỉ nền-chỉ số:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 58 -
Thanh ghi <-- [BX][SI] địa chỉ nền-chỉ số dựa trên
DS
Thanh ghi <-- [BX][DI] địa chỉ nền-chỉ số dựa trên DS
Loại địa chỉ này sử dụng BX và, SI hoặc DI, nền là DS
Ghi chú: người ta có thể dùng qui ước sau:
Thanh ghi <-- [BX+SI]
Ví dụ: MOV BX, 2
MOV SI, 5
MOV AH, [BX] [SI]
AH <-- nội dung của ô nhớ có địa chỉ là DS:7 nghĩa là DS:5+2
6- Kiểu định vị địa chỉ nền-dịch chuyển:
Thanh ghi <-- dữ liệu[BX] địa chỉ nền dựa trên DS
Thanh ghi <-- dữ liệu[BX] địa chỉ nền dựa trên SS
Loại định vị địa chỉ này là tổ hợp của các loại trên.
Ghi chú: Có thể sử dụng qui ước sau:
Thanh ghi <-- [BX+dữ liệu]
Ví dụ:
Id1 DW 5 DUP (?)
....
MOV BX,2
MOV AX, Id1[BX]
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 59 -
AX <-- phần tử thứ 3 của mảng Id1
7. Định vị địa chỉ chỉ số-dịch chuyển:
Thanh ghi <-- dữ liệu[SI]
Thanh ghi <-- dữ liệu[DI]
Loại định vị này là tổ hợp của các loại trên.
Ghi chú: Chúng ta có thể sử dụng qui ước sau:
Thanh ghi <-- [SI+dữ liệu]
Ví dụ: .....
MOV SI,4
MOV AX, [SI+1]
AX <-- nội dung của vùng nhớ tại địa chỉ DS:4+1
8- Kiểu định vị địa chỉ nền-chỉ số-dịch chuyển
Thanh ghi <-- dữ liệu[BX][SI]
Thanh ghi <-- dữ liệu[BX][DI]
Thanh ghi <-- dữ liệu[BP][SI]
Thanh ghi <-- dữ liệu[BP][DI]
Loại định vị này là tổ hợp của các loại trên.
Ghi chú: Có thể sử dụng ký hiệu sau:
Thanh ghi <-- [BX+SI+dữ liệu]
Ví dụ: Id1 DB 15 DUP(?)
.....
MOV BX,5
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 60 -
MOV SI,4
MOV AX, Id1[BX][SI]
AX <-- phần tử thứ 9 của mảng Id1
III. CHƯƠNG TRÌNH ỨNG DỤNG
TẬP TIN - THƯ MỤC
Chúng ta tham khảo một số thủ tục liên quan đến các tập tin
bằng các gọi ngắt 21h:
Tạo một tập tin;
Mở một tập tin;
Đóng một tập tin;
Đọc một tập tin;
Viết vào một tập tin....
a - Cần biết:
. Một số thủ tục sử dụng một từ để mã hoá thuộc tính của tập
tin. Các bit của từ này có ý nghĩa như sau:
Bit Ý nghĩa
0 Chỉ đọc
1 Ẩn
2 Hệ thống
5 Lưu
. Một số thủ tục sử dụng thẻ (handle), đó là một số do hệ điều
hành MSDOS gán cho một tập tin khi mở hoặc tạo tập tin, con số
này sẽ cần thiết trong quá trình đọc, viết, đóng .v.v... tập tin.
Handle DW ?
Chú ý: nếu một chương trình xử lý nhiều tập tin thì phải có
nhiều thẻ, mỗi thẻ ứng với mỗi tập tin.
b - Tạo, mở, đóng tập tin để có thể ghi nôi dung vào tập tin.
.MODEL SMALL
.STACK 100H
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 61 -
.DATA
TBAO1 DB 'Đưa nôi dung văn bản vào: ',13,10,'$'
NOIDUNG DB 10000 DUP(?)
TENTT DB 'A:\THUCTAP.TXT',0
SO DW ?
LFCR DB 13,10,'$'
.CODE
INCLUDE THUVIEN.MAC
MAIN PROC
PRODATA
HIENCH TBAO1
XOR BX,BX
MOV AH,1 ;
LAP1:
INT 21H ;
CMP AL,1AH ; CTRL+Z
JE CONT
MOV NOIDUNG[BX],AL
CMP AL,13 ; ENTER
JNE NHAY1
MOV NOIDUNG[BX],0Dh
INC BX
MOV NOIDUNG[BX],0Ah
LEA DX,LFCR
MOV AH,9
INT 21H
MOV AH,1
NHAY1:
INC BX
JMP LAP1
TIEP: MOV SO,BX
MOV AH,3CH ;
LEA DX,TENTT ; TAO MOT TAP TIN
MOV CX,20H ; THUỘC TI'NH
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 62 -
INT 21H ;
MOV BX,AX
LEA DX,TENTT ;
MOV AL,1 ;
MOV AH,3DH ; MỞ TẬP TIN
INT 21H ;
PUSH AX ; GHI THẺ ĐỂ SỬ DỤNG SAU NÀY
MOV BX,AX
MOV AH,40H ; GHI VÀO TẬP TIN
LEA DX,NOIDUNG; ĐỆM
MOV CX,SO ;SỐ BYTE ĐỌC
INT 21H ;
POP BX ;
MOV AH,3EH ;ĐÓNG TẬP TIN
INT 21H
THOAT
MAIN ENDP
END MAIN
c- Đọc nội dung tập tin
EXTRN WRITE_HEX:NEAR
.MODEL SMALL
.STACK 100H
.DATA
NOIDUNG DB 10000 DUP(?)
TENTT DB 50 DUP (?)
CAUHOI DB 'NHAP DUONG DẪN: '
LFCR DB 10,13,'$'
.CODE
INCLUDE THUVIEN.MAC
MAIN PROC
PRODATA
HIENCH CAUHOI
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 63 -
XOR BX,BX
MOV AH,1
LAP1:
INT 21H
MOV TENTT[BX],AL
INC BX
CMP AL,13
JNE LAP1
DEC BX
MOV TENTT[BX],'0'
HIENCH LFCR
LEA DX,TENTT
MOV AL,2
MOV AH,3DH ; THẺ
INT 21H ;
PUSH AX ; LƯU THẺ
MOV BX,AX ; DỊCH VỤ 3F : BX <-- THẺ
MOV AH,3FH ; ĐỌC TẬP TIN
LEA DX,NOIDUNG;
MOV CX,0FFFFH ; SO BYTE
INT 21H ;
POP BX
PUSH AX ;
CALL DONG
XOR BX,BX
POP CX
TIEP1:
MOV DL,NOIDUNG[BX]
CALL HIENSOTLP
CALL TRONG
INC BX
LOOP TIEP1
THOAT
MAIN ENDP
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 64 -
DONG PROC
MOV AH,3Eh
INT 21h
RET
DONG ENDP
TRONG PROC
PUSH DX
PUSH AX
MOV DL,' '
MOV AH,2
INT 21H
POP AX
POP DX
RET
TRONG ENDP
END MAIN
d-ĐỔI TÊN, XOÁ TẬP TIN
Đổi tên tập tin: Hàm 56h - Ngắt 21h
Xoá tập tin: Hàm 41h - Ngắt 21h
.MODEL SMALL
.STACK 100H
.DATA
VUNGDEM DB 20
LOAI DB ?
TENTT DB 50 DUP (0),0,'$'
DUONG DB '[A:] TEN TAP TIN[.EXT] $'
LOI DB 'KHÔNG THỂ XOÁ TẬP TIN NÀY$'
.CODE
INCLUDE THUVIEN.MAC
MAIN PROC
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 65 -
PRODATA
HIENCH DUONG
MOV AH,0Ah
LEA DX,VUNGDEM
INT 21h
XOR BX,BX
MOV BL,LOAI
ADD BX,OFFSET TENTT
MOV BYTE PTR [BX],0
LEA DX,TENTT
MOV AH,41h
INT 21h
JNC RA
HIENCH LOI
RA: THOAT
MAIN ENDP
END MAIN
e- THAY ĐỔI THUỘC TÍNH - CHÉP TẬP TIN:
THAY ĐỔI THUỘC TÍNH TẬP TIN: Hàm 43h - Ngắt 21h
CHÉP TẬP TIN
.MODEL SMALL
.DATA
BUFFER DB 14
TYPE1 DB 0
FILE1 DB 12 DUP(00),0
FILE2 DB 8 DUP(00),".TXT",0
HANDLE1 DW 0
HANDLE2 DW 0
THONGBAO DB 'VAO TEN PHAI COPY : $'
DATA1 DB 10000 DUP(?)
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 66 -
.STACK 100H
.CODE
INCLUDE THUVIEN.MAC
MAIN PROC
PRODATA
HIENCH THONGBAO
MOV AH,0AH
LEA DX,BUFFER
INT 21H
MOV [FILE1+12],0
MOV CX,08
LEA SI,FILE1
MOV DI, SEG FILE2
MOV ES, DI
LEA DI,FILE2
REP MOVSB
LEA DX,FILE1
MOV AX,3D02H
INT 21H
MOV HANDLE1,AX
MOV DX,OFFSET FILE2
MOV AH,3CH
MOV CX,0
INT 21H
MOV HANDLE2,AX
MOV AH,3FH
MOV CX,10000
MOV DX,OFFSET DATA1
MOV BX,HANDLE1
INT 21H
MOV CX,AX
MOV AH,40H
MOV BX,HANDLE2
INT 21H
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 67 -
MOV AH,3EH
MOV BX,HANDLE1
INT 21H
MOV BX,HANDLE2
INT 21H
THOAT
MAIN ENDP
END MAIN
f. CÁC THƯ MỤC:
Dịch vụ 39h của ngắt 21h sử dụng để tạo thư mục mới
(MKDIR)
Dịch vụ 3Ah của ngắt 21h sử dụng để xoá thư mục (RMDIR)
Dịch vụ 3Bh của ngắt 21h sử dụng để chuyển thư mục
(CHDIR)
IV. TẠO TẬP TIN .COM
Những chương trình trong đó dữ liệu và lệnh đều nằm trong
cùng một phân đoạn đều là những chương trình COM. Điều này có
nghĩa là dung lượng của chương trình có giới hạn là 64KByte. Ngay
từ khi thực hiện chương trình loại này, MSDOS đưa vào bộ nhớ
toàn bộ tập tin này và đặt giá trị ban đầu cho các thanh ghi CS, DS,
SS, ES như nhau. Thanh ghi SP (Stack Pointer) được đặt là FFFEh.
Thanh ghi IP được đặt làø 0100h vì mỗi chương trình đặt ở đầu bộ
nhớ một vùng100h byte (PSP), điều này giải thích vì sao lệnh thứ
nhất của chương trình (điểm vào) phải đặt ở đầu của chương trình
và chúng ta phải sử dụng định hướng biên dịch ORG 100h. Vì vậy
chúng ta có hình ảnh của bộ nhớ như sau:
Offset PSP
100h JMP Batdau
Dữ liệu
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 68 -
IP ---> Batdau:
SP=FFFE Ngăn xếp
1- Dạng của một chương trình COM
.MODEL SMALL
.CODE
ORG 100h
BATDAU:
JMP CHINH
; Đặt dữ liệu ở đây
CHINH PROC
; Các lệnh
MOV AH,4Ch
INT 21h
CHINH ENDP
; Các thủ tục khác
END BATDAU
Ví dụ:
Tập tin KIEMTRA.ASM
.MODEL SMALL
.CODE
ORG 100h
BATDAU:
JMP CHINH
TBAO DB 'Chao cac ban! $'
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 69 -
CHINH PROC
LEA DX,TBAO
MOV AH,09
INT 21h
MOV AH,4Ch
INT 21h
CHINH ENDP
END BATDAU
Hợp dịch chương trình này:
MASM KIEMTRA;
LINK KIEMTRA;
Để chuyển tập tin EXE sang COM sử dụng EXE2BIN
EXE2BIN KIEMTRA KIEMTRA.COM
2- Ưùng dụng tập tin .com
a- Ứng dụng 1:
Xem số đĩa cứng, số đầu từ, số từ trụ, số cung trên rãnh
.MODEL SMALL
.CODE
ORG 100h
BATDAU:
JMP DIACUNG
SODIA DB 10,13,'Số đĩa cứng: $'
SODAU DB 10,13,'Số đầu từ : $'
SOTUTRU DB 10,13,'Số từ trụ : $'
SOCUNG DB 10,13,'Số cung : $'
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 70 -
DIACUNG PROC
MOV AH,8
MOV DL,80H
INT 13H
PUSH CX
PUSH CX
PUSH DX
PUSH DX
LEA DX,SODIA
CALL HIENCHUOI
POP DX
AND DX,00FFH
CALL HIENSOTP
LEA DX,SODAU
CALL HIENCHUOI
POP DX
AND DX,0FF00H
MOV DL,DH
MOV DH,00
ADD DL,1
CALL HIENSOTP
LEA DX,SOTUTRU
CALL HIENCHUOI
POP CX
AND CX,1111111111000000B
XCHG CH,CL
MOV DX,CX
MOV CX,2
ROL DH,CL
ADD DL,2
CALL HIENSOTP
LEA DX,SOCUNG
CALL HIENCHUOI
POP CX
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 71 -
AND CX,0000000000111111B
MOV DX,CX
CALL HIENSOTP
MOV AH,4CH
INT 21H
DIACUNG ENDP
; Những thủ tục khác
END BATDAU
b - Ứng dụng 2: Đọc nội dung của một cung
DOS bắt đầu đọc từ cung 1, từ trụ 0, mặt 1 gọi là cung 0
mỗi rãnh có 17 cung
* Mỗi tập tin chiếm nhiều nhóm cung do vậy phải có một bảng
quản lý tập tin -> FAT File Allocation Table có 16 BIT ->
216=65536 nhóm cung
* Với đĩa mềm:
Mặt 0, rãnh 0, cung 1 -> lưu phần khởi động DOS BOOT
RECORD (DBR)
* Với đĩa cứng:
Bắt đầu là phần MASTER BOOT RECORD (MBR)
PARTITION
sau đó mặt 1, rãnh 0, cung 1 -> lưu phần khởi động DOS BOOT
RECORD (DBR)
Tập tin DIACUNG.ASM
.MODEL SMALL
.CODE
ORG 100h
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 72 -
BATDAU:
JMP DOCCUNG
VUNGDEM DB 512 DUP (?)
DB '$'
THONGBAO DB 'Đọc tốt ',13,10,'$'
BAOLOI DB 'Không thể đọc',13,10,'$'
TRONG DB ' $'
GACH DB ' - $'
DEM DW ?
CHU DW ?
HANG DW ?
LFCR DB 13,10,'$'
DOCCUNG PROC
MOV DS,AX
XOR AX,AX
MOV AH,2
MOV AL,1 ; 1 Cung
MOV DL,1 ; Đĩa mềm B
MOV DH,1 ; Đầu từ 1
MOV CH,0 ; rãnh 0
MOV CL,9 ; cung 9
LEA BX,VUNGDEM
INT 13H
JNC TOT
LEA DX,BAOLOI
MOV AH,9
INT 21H
JMP RA
TOT:
LEA DX,THONGBAO
MOV AH,9
INT 21H
RA:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 73 -
MOV CX,300
MOV DEM,0
MOV CHU,0
MOV HANG,0
LAP9:
MOV BX,DEM
MOV DX,WORD PTR VUNGDEM[BX]
CALL HIENSOTLP
LEA DX,TRONG
CALL HIENCHUOI
INC DEM
INC CHU
INC HANG
CMP CHU,10
JNE TIEP1
MOV CHU,0
CMP HANG,10
JA TIEP1
LEA DX,GACH
CALL HIENCHUOI
TIEP1:
CMP HANG,20
JNE TIEP2
MOV HANG,0
LEA DX,LFCR
CALL HIENCHUOI
TIEP2:
LOOP LAP9
CALL THOAT
DOCCUNG ENDP
; Các thủ tục khác
END BATDAU
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 74 -
c - Ưùng dụng 3:
Ghi 1 cung
.MODEL SMALL
.CODE
ORG 100h
BATDAU:
JMP GHICUNG
VUNGDEM DB 512 DUP (00)
DB '$'
THONGBAO DB 13,10,'Đọc tốt ',13,10,'$'
BAOLOI DB 13,10,'Không thể đọc ',13,10,'$'
NHAP DB 'Gõ vào bàn phím :'
LFCR DB 13,10,'$'
DEM DW ?
GHICUNG PROC
LEA DX,NHAP
CALL HIENCHUOI
MOV DEM,0
MOV AH,1
LAP9:
INT 21H
CMP AL,1AH ; CTRL+Z
JE TIEP1
MOV BX,DEM
MOV VUNGDEM[BX],AL
INC DEM
JNE LAP9
TIEP1:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 75 -
XOR AX,AX
MOV AH,3
MOV AL,1 ; 1 Cung
MOV DL,1 ; Đĩa mềm B
MOV DH,1 ; Đầu từ 1
MOV CH,0 ; Rãnh 0
MOV CL,9 ; Cung 9
LEA BX,VUNGDEM
INT 13H
JNC TOT
LEA DX,BAOLOI
CALL HIENCHUOI
JMP THOATRA
TOT:
LEA DX,THONGBAO
CALL HIENCHUOI
THOATRA:
CALL THOAT
GHICUNG ENDP
;Các thủ tục khác
END BATDAU
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 76 -
CHƯƠNG 7: SỬ DỤNG PHÂN ĐOẠN TOÀN PHẦN
Phương pháp định nghĩa phân đoạn đơn giản hoá mà chúng ta vẫn
thường sử dụng từ trước đến nay đã áp dụng được hầu hết các mục tiêu.
Trong phần này chúng ta xem xét cách định nghĩa phân đoạn tòn phần. Dưới
đây là nguyên nhân chính để sử dụng phương pháp này:
. Với các trình biên dịch phiên bản 5.0 trở về trước chúng ta chỉ có thể
sử dụng phương pháp định nghĩa phân đoạn toàn phần.
. Với phương pháp định nghĩa phân đoạn toàn phần, lập trình viên có
thể điều khiển được thứ tự các phân đoạn , việc kết hợp chúng với nhau và sự
liên kết giữa chúng trong bộ nhớ
I- SỬ DỤNG CÁC ĐỊNH HƯỚNG BIÊN DỊCH
1. Segment
Tên SEGMENT liên kết kết hợp 'lớp'
;
;
Tên ENDS
Ví dụ:
D_SEG SEGMENT
; các dữ liệu
D_SEG ENDS
a - Loại liên kết (align):
PARA Phân đoạn bắt đầu từ phân đoạn trước đó.
BYTE Phân đoạn bắt đầu từ byte trước đó.
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 77 -
WORD Phân đoạn bắt đầu từ từ trước đó.
PAGE Phân đoạn bắt đầu từ trang trước đó.
Mặc định người ta sử dụng loại PARA
Ví dụ:
SEG1 SEGMENT PARA
DB 11h DUP (1)
SEG1 ENDS
SEG2 SEGMENT PARA
DB 10H DUP (2)
SEG2 ENDS
1010:0000 01 01 01 01 01 01 - 01 01 01 01 01
1010:0010 01 00 00 00 00 00 - 00 00 00 00 00
1010:0020 02 02 02 02 02 02 - 02 02 02 02 02
SEG1 SEGMENT PARA
DB 11h DUP (1)
SEG1 ENDS
SEG2 SEGMENT BYTE
DB 10H DUP (2)
SEG2 ENDS
1010:0000 01 01 01 01 01 01 - 01 01 01 01 01
1010:0010 01 02 02 02 02 02 - 02 02 02 02 02
1010:0020 02 00 00 00 00 00 - 00 00 00 00 00
b - Loại kết hợp (combine):
PUBLIC:Những phân đoạn có cùng tên đều gom lại trong cùng một
khối nhớ kế tiếp nhau và thống nhất.
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 78 -
COMMON: Những phân đoạn có cùng tên sẽ gom lại tại một vị trí
bộ nhớ và xếp chồng lên nhau.
STACK: Tác dụng gần như PUBLIC ngoại trừ tất cả các địa chỉ
nhảy bước (offset) của các lệnh và các dữ liệu được tính
tương đối so với thanh ghi SS. SP được đặt ban đầu trỏ
đến cuối phân đoạn.
AT paragraph: Phân đoạn được bắt đầu từ một phân đoạn xác định
Thường người ta sử dụng loại PUBLIC để gom các phân đoạn mã
có cùng tên trong những mođun khác nhau để tạo ra một phân đoạn
duy nhất. Điều này cũng có nghĩa là chúng ta có những thủ tục
NEAR trong chương trình.
c - Loại lớp (class):
Loại lớp chúng ta định nghĩa chỉ ra thứ tự vị trí của các phân đoạn
trong bộ nhớ. Chúng ta cần đặt loại này vào trong dấu nháy ( ' ).
Ví dụ:
Nếu chúng ta định nghĩa THUNHAT.ASM:
C_SEG SEGMENT 'CODE'
; thủ tục chính
C_SEG ENDS
Và trong THUHAI.ASM
C1_SEG SEGMENT 'CODE'
; các thủ tục khác
C1_SEG ENDS
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 79 -
Sau khi thực hiện lệnh
LINK THUNHAT+THUHAI
C1_SEG sẽ nằm sau C_SEG trong bộ nhớ.
2. Định hướng biên dịch assume
Khi một chương trình được hợp dịch, trình hợp dịch phải biết phân
đoạn nào là phân đoạn mã, phân đoạn nào là phân đoạn dữ liệu, phân đoạn
nào là phân đoạn ngăn xếp. Mục tiêu của định hướng biên dịch ASSUME là
liên kết các thanh ghi CS, DS, SS và ngay cả ES vào các phân đoạn đã biết.
II - DẠNG CỦA CHƯƠNG TRÌNH .EXE SỬ DỤNG TRONG CÁC
PHƯƠNG PHÁP CŨ:
S_SEG SEGMENT STACK
DB 100h
S_SEG ENDS
D_SEG SEGMENT
; dữ liệu
D_SEG ENDS
C_SEG SEGMENT
ASSUME CS:C_SEG, SS:S_SEG, DS: D_SEG
MAIN PROC
;Xác định ban đầu DS
MOV AX, D_SEG
MOV DS, AX
; các lệnh khác
MAIN ENDP
; các thủ tục khác
C_SEG ENDS
END MAIN
Một ví dụ chương trình EXE
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 80 -
Đổi ra chữ HOA:
* Tập tin CTR11.ASM
EXTRN CONVERS:FAR
S_SEG SEGMENT STACK
DB 100 DUP (0)
S_SEG ENDS
D_SEG SEGMENT
MSG DB 'Nhập vào một chữ cái thường: $'
D_SEG ENDS
C_SEG SEGMENT
ASSUME CS:C_SEG, DS: D_SEG, SS: S_SEG
MAIN PROC
MOV AX, D_SEG
MOV DS, AX
MOV AH, 09
LEA DX, MSG
INT 21H
MOV AH, 1
INT 21H
CALL CONVERS
MOV AH,4CH
INT 21H
MAIN ENDP
C_SEG ENDS
END MAIN
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 81 -
Tập tin CTR21.ASM
PUBLIC CONVERS
D_SEG SEGMENT
MSG DB 0DH,0AH, 'Chữ HOA là: '
CARAC DB -20h,' $'
D_SEG ENDS
C_SEG SEGMENT
ASSUME CS: C_SEG, DS: D_SEG
CONVERT PROC FAR
PUSH DS
PUSH DX
MOV DX, D_SEG
MOV DS, DX
ADD CARAC, AL
MOV AH, 09
LEA DX, MSG
INT 21H
POP DX
POP DS
RET
CONVERS ENDP
C_SEG ENDS
END
Có thể tối ưu hoá chương trình trên:
* CTR12.ASM
EXTRN CONVERS:NEAR
S_SEG SEGMENT STACK
DB 100 DUP (0)
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 82 -
S_SEG ENDS
D_SEG SEGMENT BYTE PUBLIC 'DATA'
MSG DB 'Nhập vào một chữ cái thường: $'
D_SEG ENDS
C_SEG SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:C_SEG, DS: D_SEG, SS: S_SEG
MAIN PROC
MOV AX, D_SEG
MOV DS, AX
MOV AH, 09
LEA DX, MSG
INT 21H
MOV AH, 1
INT 21H
CALL CONVERS
MOV AH,4CH
INT 21H
MAIN ENDP
C_SEG ENDS
END MAIN
Tập tin CTR22.ASM
PUBLIC CONVERS
D_SEG SEGMENT BYTE PUBLIC 'DATA'
MSG DB 0DH,0AH, 'Chữ HOA là : '
CARAC DB -20h,' $'
D_SEG ENDS
C_SEG SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS: C_SEG, DS: D_SEG
CONVERT PROC NEAR
PUSH DX
ADD CARAC, AL
MOV AH, 09
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 83 -
LEA DX, MSG
INT 21H
POP DX
RET
CONVERS ENDP
C_SEG ENDS
END
MASM CTR21;
MASM CTR22;
LINK CTR21+CTR22
III- VÍ DỤ CHƯƠNG TRÌNH COM
MyProg SEGMENT
Org 100h
ASSUME CS:MyProg, DS:MyData
Start:
JMP Main
Main PROC
MOV AH,9
LEA DX,CS:MSG
INT 21h
INT 20h
Main ENDP
MyProg ENDS
MyData SEGMENT
MSG DB 'Chào các bạn, hẹn gặp lại $'
MyData ENDS
END Start
MASM CTCUOI;
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 84 -
LINK CTCUOI;
EXE2BIN CTCUOI CTCUOI.COM
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 85 -
CHƯƠNG 8: CHƯƠNG TRÌNH ỨNG DỤNG
I. IN NỘI DUNG VĂN BẢN RA MÁY IN:
1. Sử dụng hàm 40h ngắt 21h (DOS) để thực hiện
.MODEL SMALL
.STACK 100h
.DATA
HelloMessage DB 'Hello, world',13,10,12 ; 12 Form Feed
HELLO_MESSAGE_LENGTH EQU $ - HelloMessage
.CODE
mov ax,@data
mov ds,ax ;set DS to point to the data segment
mov ah,40h ;DOS write to device function #
mov bx,4 ;printer handle
mov cx,HELLO_MESSAGE_LENGTH ;number of characters to print
mov dx,OFFSET HelloMessage ;string to print
int 21h ;print "Hello, world"
mov ah,4ch ;DOS terminate program function #
int 21h ;terminate the program
END
2. Sử dụng hàm 01h ngắt 17h (ROMBIOS)
.model small
.stack 100h
.data
printe equ 17h
prin_first equ 0
.code
printe_char proc
mov ax,@data
mov ds,ax
mov dx,prin_first
mov ah,01
int printe
mov cx,0ffh
conti:
mov al,41h
call pri
dec cx
cmp cx,0
jnz conti
mov al,0dh
call pri
mov ah,4ch
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 86 -
int 21h
printe_char endp
pri proc
mov ah,0
int printe
ret
pri endp
end printe_char
II. ĐẾM SỐ TỪ TRONG MỘT TẬP TIN
;
; Program to count the number of words in a file. Words are
; delimited by whitespace, which consists of spaces, tabs,
; carriage returns, and linefeeds.
.MODEL SMALL ;code and data each fit in 64K
.STACK 200h ;512-byte stack
.DATA
Count DW 0 ;used to count words
InWhitespace DB ? ;set to 1 when the last
; character read was whitespace
TempChar DB ? ;temporary storage used by
; GetNextCharacter
Result DB 'So tu la: ', 5 DUP (?)
;string printed to report the count
CountInsertEnd DB 0dh,0ah,'$'
;DOS fn #9 expects strings to end with
; a dollar sign
.CODE
ProgramStart:
mov ax,@data
mov ds,ax ;point DS to the .DATA segment
mov [InWhitespace],1 ;assume we're in whitespace, since
; the first non-whitespace we'll find
; will mark the start of a word
CountLoop:
call GetNextCharacter ;get next character to check
jz CountDone ;...if any
call IsCharacterWhitespace ;is it whitespace?
jz IsWhitespace ;yes
cmp [InWhitespace],0 ;character is not
; whitespace-are we currently in
; whitespace?
jz CountLoop ;we're not in whitespace, and the
; character isn't whitespace, so
; we're done with this character
inc [Count] ;we are in whitespace, and the
; character is not whitespace, so
; we just found the start of a new word
mov [InWhitespace],0 ;mark that we're no longer
;in whitespace
jmp CountLoop ;do the next character
IsWhitespace:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 87 -
mov [InWhitespace],1 ;mark that we're in whitespace
jmp CountLoop ;do the next character
;
; We're done counting--report the results.
CountDone:
mov ax,[Count] ;number to convert to a string
mov bx,OFFSET CountInsertEnd-1 ;point to the end of
; the string to put the number in
mov cx,5 ;number of digits to convert
call ConvertNumberToString ;make the number a string
mov bx,OFFSET Result ;point to result string
call PrintString ;print the count
mov ah,4ch ;DOS terminate program fn #
int 21h ;end the program
;
; Subroutine to get the next character from the standard input.
;
; Input: None
;
; Output:
; AL = character, if one was available
; Z flag = 0 (NZ) if character available,
; = 1 (Z) if end of file reached
;
; Registers destroyed: AH, BX, CX, DX
;
GetNextCharacter PROC
mov ah,3fh ;DOS read from file fn #
mov bx,0 ;standard input handle
mov cx,1 ;read one character
mov dx,OFFSET TempChar ;put the character in TempChar
int 21h ;get the next character
jc NoCharacterRead ;if DOS reports an error, then treat
; it as the end of the file
cmp [TempChar],1ah ;was it Control-Z?
; (marks end of some files)
jne NotControlZ ;no
NoCharacterRead:
sub ax,ax ;mark no character read
NotControlZ:
and ax,ax ;set Z flag to reflect whether a
; character was read (NZ), or the
; end of the file was reached (Z).
; Note that DOS fn #3fh sets AX to
; the number of characters read
mov al,[TempChar] ;return the character read
ret ;done
GetNextCharacter ENDP
;
; Subroutine to report whether a given character is whitespace.
;
; Input:
; AL = character to check
;
Nguyễn Hữu Lộc Khoa Vật Lý
; Output:
Hợp Ngữ - 88 -
; Z flag = 0 (NZ) if character is not whitespace
; = 1 (Z) if character is whitespace
;
; Registers destroyed: none
;
IsCharacterWhitespace PROC
cmp al,' ' ;is it a space?
jz EndIsCharacterWhitespace ;if so, it's whitespace
cmp al,09h ;is it a tab?
jz EndIsCharacterWhitespace ;if so, it's whitespace
cmp al,0dh ;is it a carriage return?
jz EndIsCharacterWhitespace ;if so, it's whitespace
cmp al,0ah ;is it a linefeed? If so,
; it's whitespace, so return Z;
; if not, it's not whitespace,
; so return NZ as set by cmp
EndIsCharacterWhitespace:
ret
IsCharacterWhitespace ENDP
;
; Subroutine to convert a binary number to a text string.
;
; Input:
; AX = number to convert
; DS:BX = pointer to end of string to store text in
; CX = number of digits to convert
;
; Output: None
;
; Registers destroyed: AX, BX, CX, DX, SI
;
ConvertNumberToString PROC
mov si,10 ;used to divide by 10
ConvertLoop:
sub dx,dx ;convert AX to doubleword in DX:AX
div si ;divide number by 10. Remainder is in
; DX--this is a one-digit decimal
; number. Number/10 is in AX
add dl,'0' ;convert remainder to a text character
mov [bx],dl ;put this digit in the string
dec bx ;point to the location for the
; next most-significant digit
loop ConvertLoop ;do the next digit, if any
ret
ConvertNumberToString ENDP
;
; Subroutine to print a string on the display.
;
; Input:
; DS:BX = pointer to string to print
;
; Output: None
;
; Registers destroyed: None
Nguyễn Hữu Lộc Khoa Vật Lý
;
Hợp Ngữ - 89 -
;
;
PrintString PROC
push ax
push dx ;reserve registers in this subroutine
mov ah,9 ;DOS print string function #
mov dx,bx ;point DS:DX to the string to print
int 21h ;invoke DOS to print the string
pop dx ;restore registers we changed
pop ax
ret
PrintString ENDP
END ProgramStart
III- ĐỔI NGƯỢC CHUỖI
.MODEL SMALL
.STACK 100h
.DATA
MAXIMUM_STRING_LENGTH EQU 1000
StringToReverse DB MAXIMUM_STRING_LENGTH DUP(?)
ReverseString DB MAXIMUM_STRING_LENGTH DUP(?)
.CODE
mov ax,@data
mov ds,ax ;set DS to point to the data segment
mov ah,3fh ;DOS read from handle function #
mov bx,0 ;standard input handle
mov cx,MAXIMUM_STRING_LENGTH ;read up to maximum
;number of characters
mov dx,OFFSET StringToReverse ;store the string here
int 21h ;get the string
and ax,ax ;were any characters read?
jz Done ;no, so you're done
mov cx,ax ;put string length in CX, where
; you can use it as a counter
push cx ;save the string length
mov bx,OFFSET StringToReverse
mov si,OFFSET ReverseString
add si,cx
dec si ;point to the end of the
; reverse string buffer
ReverseLoop:
mov al,[bx] ;get the next character
mov [si],al ;store the characters in reverse order
inc bx ;point to next character
dec si ;point to previous location in reverse buffer
loop ReverseLoop ;move next character, if any
pop cx ;get back the string length
mov ah,40h ;DOS write from handle function #
mov bx,1 ;standard output handle
mov dx,OFFSET ReverseString ;print this string
int 21h ;print the reversed string
Done:
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 90 -
mov ah,4ch ;DOS terminate program function #
int 21h ;terminate the program
END
IV. CHƯƠNG TRÌNH HIỂN THỊ THỜI GIAN
Chương trình bao gồm các bước sau đây:
1- Lấy thời gian
2- Đổi giờ, phút, giây sang dạng chữ số ASCII
3- Hiển thị các chữ số ASCII
Tập tin thứ 1: PGM1_1.ASM
EXTRN GET_TIME:NEAR
.MODEL SMALL
.STACK 100h
.DATA
TIME_BUF DB '00:00:00$' ; bộ đệm thời gian
;hr:min:sec
.CODE
MAIN PROC
MOV AX,@DATA
MOV DX,AX ; khởi tạo DS
;lấy và hiển thị thời gian
LEA BX,TIME_BUF
CALL GET_TIME ;đưa thời gian
;hiện tại vào DX
LEA DX,TIME_BUF
MOV AH,09H
INT 21H
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 91 -
;trở về DOS
MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN
Tập tin thứ 2: PGM1_2.ASM
PUBLIC GET_TIME
.MODEL SMALL
.CODE
GET_TIME PROC
;lấy thời gian trong ngày và chứa các chữ số ASCII ;trong bộ
đệm thời gian
MOV AH,2CH
INT 21H
;đổi giờ sang dạng ASCII và lưu trữ
MOV AL,CH
CALL CONVERT
MOV [BX],AX
;đổi phút sang dạng ASCII và lưu trữ
MOV AL,CL
CALL CONVERT
MOV [BX+3],AX
;đổi giây sang dạng ASCII và lưu trữ
MOV AL,CH
CALL CONVERT
MOV [BX+6],AX
RET
GET_TIME ENDP
;
;
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 92 -
CONVERT PROC
;
; đổi số kiểu byte (0-59) sang các chữ số ASCII
; vào: AL = số
; ra:AX = các chữ số ASCII, AL = chữ số hàng chục
; AH = chữ số hàng đơn vị
;
MOV AH,0
MOV DL,10
DIV DL
OR AX, 0303H ; đổi sang dạng ASCII
RET
CONVERT END
END
Chương trình hiển thị thời gian và kết thúc
* Để tạo chương trình thời gian thú vị hơn, chúng ta cho hiển thị thời
gian và cập nhật lại sau mỗi giây
Thủ tục SETUP_INT trong chương trình PGM2_2.ASM cất vectơ ngắt
cũ và thiết lập vectơ ngắt mới. Nó nhận số hiệu ngắt trong AL, bộ đệm để cất
vectơ cũ tại DS:DI và bộ đệm chứa vectơ ngắt mới tại DS:SI. Bằng việc hoán
đổi hai bộ đệm, SET_INT có thể được dùng để phục hồi lại vectơ cũ.
Tập tin PGM2_2.ASM
PUBLIC SETUP_INT
.MODEL SMALL
.CODE
SETUP_INT PROC
;cất vectơ cũ
MOV AH,35H
INT 21H ;ES:BX=vectơ ngắt
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 93 -
MOV [DI],BX ; cất offset
MOV [DI+2],ES ;cất địa chỉ phân đoạn
; thiết lập vectơ mới
MOV DX,[SI] ;DX chứa offset
PUSH DS ;cất DS
MOV DS,[SI+2];DS chứa số hiệu đoạn
MOV AH,25H
INT 21H
POP DS ; phục hồi DS
RET
SETUP_INT END
END
Điều khiển con trỏ:
Mỗi khi hiển thị thời gian bằng hàm 9 ngắt 21h, con trỏ bị dịch đi.
Lần hiển thị sau sẽ xuất hiện tại một vị trí khác trên màn hình. Như vậy
để thấy thời gian cập nhật lại ở cùng một vị trí trên màn hình, chúng ta
phải phục hồi con trỏ tại vị trí nguyên thủy của nó trước khi hiển thị thời
gian. Muốn thực hiện điều này, trước hết chúng ta phải xác định vị trí
hiện tại của con trỏ, tiếp đó sau mỗi thao tác in chuỗi chúng ta lại
chuyển con trỏ trỏ về vị trí ban đầu của nó.
Chúng ta sử dụng các hàm 3 và 2 của ngắt 10h để cất vị trí của
con trỏ và di chuyển con trỏ đến vị trí ban đầu của nó sau mỗi thao tác in
chuỗi.
Thủ tục ngắt:
Khi một thủ tục ngắt được kích hoạt, không thể xem thanh ghi DS
chứa địa chỉ phân đoạn dữ liệu của chương trình. Vì thế nếu muốn sử
dụng bất cứ biến nào, phải khởi tạo thanh ghi DS. Thanh ghi DS phải
được phục hồi lại trước khi kết thúc trình phục vụ ngắt với lệnh IRET
(Interrupt Return)
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 94 -
PGM2_1.ASM chứa thủ tục MAIN và thủ tục ngắt TIME_INT.
Các bước của thủ tục MAIN gồm:
Cất vị trí con trỏ hiện tại
Thiết lập vectơ ngắt cho TIME_INT
Đợi vào 1 phím
phục hồi lại ngắt cũ và kết thúc
Thực hiện bước thứ 2, chúng ta sử dụng toán tử giả OFFSET và
SEG để lấy offset và địa chỉ phân đoạn của thủ tục TIEME_INT, vectơ
này sau đó được lưu vào trong bộ đệm NEW_VEC. Thủ tục SETUP_INT
được gọi để thiết lập vectơ cho ngắt nhịp thời gian 1Ch. Ngắt 16h, hàm 0
được dùng trong bước 3 để vào 1 phím. Thủ tục SETUP_INT lại được
gọi một lần nữa trong bước 4, lần này SI trỏ đến vectơ cũ và DI trỏ đến
vectơ của thủ tục TIME_INT.
Các bước của thủ tục TIME_INT gồm
(1) Thiết lập DS
(2) Lấy thời gian mới
(3) Hiển thị thời gian
(4) phục hồi vị trí con trỏ
(5) Phục hồi DS
Chương trình được tiến hành như sau: sau khi thiết lập con trỏ và
các vectơ ngắt, thủ tục MAIN đợi 1 phím nhấn. Khi ấy thủ tục ngắt
TIME_INT cập nhật thời gian mới mỗi khi có xung nhịp của mạch thời
gian. Sau khi một phím được nhấn, vectơ cũ được phục hồi và chương
trình kết thúc.
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 95 -
PGM2_1.ASM
EXTRN GET_TIME:NEAR, SETUP_INT:NEAR
.MODEL SMALL
.STACK 100H
.DATA
TIME_BUF DB '00:00:00$'
CURSOR_POS DW ?
NEW_VEC DW ?,?
OLD_VEC DW ?,?
;
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX ;Khởi tạo DS
;cất vị trí con trỏ
MOV AH,3
MOV BH,0 ;trang 0
INT 10H
MOV CURSOR_POS,DX; cất vị trí con trỏ
;thiết lập thủ tục ngắt bằng cách
; đưa segment:offset của TIME_INT vào NEW_VEC
MOV NEW_VEC, OFFSET TIME_INT
MOV NEW_VEC+2,SEG TIME_INT
LEA DI, OLD_VEC ;DI trỏ đến bộ đệm vectơ
LEA SI, NEW_VEC ;SI trỏ đến vectơ mới
MOV AL,1CH ; ngắt thời gian
CALL SETUP_INT ; thiết lập vectơ mới
; đọc bàn phím
MOV AH,0
INT 16H
;phục hồi vectơ ngắt cũ
LEA DI,NE_VEC
LEA SI,OLD_VEC
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 96 -
MOV AL,1CH
CALL SETUP_INT
;trở về DOS
MOV AH,4CH
INT 21H
MAIN ENDP
;
TIME_INT PROC
;thủ tục ngắt
;kích hoạt bởi mạch thời gian
PUSH DS; cất giá trị tức thời của DS
MOV AX,@DATA
MOV DS,AX ;DS trỏ đến đoạn dữ liệu
;lấy thời gian mới
LEA BX, TIME_BUF ; BX trỏ đến bộ đệm
;thời gian
CALL GET_TIME ; cất thời gian trong bộđệm
;hiển thị thời gian
LEA DX,TIME_BUF
MOV AH,09H
INT 21H
;phục hồi vị trí con trỏ
MOV AH,2
MOV BH,0
MOV DX,CURSOR_POS
INT 10H
IRET
TIME_INT ENDP
;
END MAIN
Lệnh LINK gồm các mođun PGM2_1.ASM, PGM1_2.ASM,
PGM2_2.ASM
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 97 -
V. CHƯƠNG TRÌNH THƯỜNG TRÚ BỘ NHỚ.
Cũng vẫn hiển thị giờ nhưng bây giờ là ở thường trú trong bộ nhớ
(terminate and stay resident)
Thông thường khi kết thúc một chương trình, bộ nhớ mà nó chiếm
giữ được DOS sử dụng để nạp chương trình khác. Tuy nhiên khi một
chương trình TSR kết thúc, bộ nhớ không bị thu hồi lại. Chính vì thế một
chương trình TSR còn được gọi là chương trình thường trú bộ nhớ
(memory resident program)
Để trở về DOS, một chương trình TSR kết thúc bằng cách sử dụng
ngắt 27h hay ngắt 21h (hàm 31h)
Chúng ta sẽ tạo một chương trình .COM vì để sử dụng ngắt 27h
chúng ta cần xác định số byte được ở lại thường trú trong bộ nhớ. Cấu
trúc của một chương trình .COM khiến việc tính toán dễ dàng hơn vì nó
chỉ có một phân đoạn chương trình.
Một khi muốn kết thúc hoàn toàn nghĩa là chương trình TSR
không hoạt động. Chương trình này phải được kích hoạt bởi các tác động
ngoài như một tổ hợp phím nào đó (Ví dụ:Ctrl+Shift). Ưu điểm của
chương trình thường trú là chúng có thể được kích hoạt khi đang chạy
một chương trình nào khác.
Chương trình gồm 2 phần: Phần khởi tạo thiết lập vectơ ngắt và
phục vụ ngắt
Tập tin PGM3_1.ASM
EXTRN MAIN:NEAR, SETUP_INT:NEAR
EXTRN NEW_VEC:DWORD, OLD_VEC:DWORD
PUBLIC INITIALIZE
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 98 -
C_SEG SEGMENT PUBLIC
ASSUME CS:C_SEG
INITIALIZE PROC
;thiết lập vectơ ngắt
MOV NEW_VEC,OFFSET MAIN; lưu địa chỉ
MOV NEW_VEC+2,CS
LEA DI, OLD_VEC ; DI trỏ về vectơ cũ
LEA SI, NEW_VEC ; SI trỏ về vectơ mới
MOV AL,09H ;ngắt bàn phím
CALL SETUP_INT ; thiết lập vectơ ngắt
;trở về DOS
LEA DX, INITIALIZE
INT 27H ; Kết thúc và ở lại thường trú
INITIALIZE ENDP
C_SEG ENDS
END INITIALIZE
Cách đơn giản để nhận biết các phím điều khiển là kiểm tra các
cờ phím (hàm 2- ngắt 16h). Chúng ta sẽ sử dụng tổ hợp phím Ctrl và
Shift phải để kích hoạt và kết thúc sự hiển thị đồng hồ. Khi kích hoạt,
thời gian hiện tại sẽ được hiển thị tại góc phải trên của màn hình . Đầu
tiên phải chép lại dữ liệu màn hình để sau khi kết thúc hiển thị đồng hồ
ta có thể phục hồi lại màn hình cũ.
Thủ tục SET_CURSOR thiết lập vị trí con trỏ tại hàng 0 và cột
trong DL
Thủ tục SAVE_SCREEN chép dữ liệu màn hình vào bộ đệm
Thủ tục RESTOR_SCREEN trả lại dữ liệu cho bộ đệm màn hình
Tập tin PGM3_2.ASM
EXTRN SS_BUF:BYTE
PUBLIC SAVE_SCREEN,RESTOR_SCREEN, SET_CURSOR
C_SEG SEGMENT PUBLIC
ASSUME CS:C_SEG
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 99 -
;
SAVE_SCREEN PROC
;lưu giữ 8 ký tự ở góc phải trên của màn hình
LEA DI,SS_BUF ; Bộ đệm màn hình
MOV CX,8
MOV DL,72 ;cột 72
CLD ; xoá DF cho thao tác chuỗi
SS_LOOP:
CALL SET_CURSOR;thiết lập con trỏ
MOV AH,08H ; đọc ký tự trên màn hình
INT 10H ;AH=thuộc tính/AL=ký tự
STOSW ; cất ký tự và thuộc tính
INC DL ; cột tiếp theo
LOOP SS_LOOP
RET
SAVE_SCREEN ENDP
;
RESTOR_SCREEN PROC
;phục hồi màn hình đã cất
LEA SI,SS_BUF ;SI trỏ đến bộ đệm
MOV DI,8 ;lặp 8 lần
MOV DL,72 ;cột 72
MOV CX,1 ; mỗi lần 1 ký tự
RS_LOOP:
CALL SET_CURSOR ;di chuyển con trỏ
LODSW ;AL=ký tự/AH=thuộc tính
MOV BL,AH
MOV AH,9 ; viết ký tự và thuộc tính
MOV BH,0 ;trang 0
INT 10h
INC DL ;vị trí ký tự tiếp theo
DEC DI
JG RS_LOOP
RET
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 100 -
RESTOR_SCREEN END
;
SET_CURSOR PROC
;chuyển con trỏ đến hàng 0, cột DL
; vào DL=số hiệu cột
MOV AH,2
MOV BH,0
MOV DH,0
INT 10H
SET_CURSOR END
;
C_SEG ENDS
END
Bây giờ chúng ta đã sẵn sàng để viết thường trình ngắt. Để xác
định xem sự hiển thị thời gian có được kích hoạt hay không ta sử dụng cờ
biến đổi được ON_FLAG. Cờ này được thiết lập bằng 1 khi thời gian
được hiển thị. MAIN là thủ tục ngắt
Tập tin PGM3_3.ASM
;chương trình thường trú bộ nhớ chỉ thời gian
; kích hoạt bằng tổ hợp phím Ctrl+Shift phải
EXTRN INITIALIZE:NEAR,SAVE_SCREEN:NEAR
EXTRN RESTOR_SCREEN:NEAR,SET_CURSOR:NEAR
EXTRN GET_TIME:NEAR
PUBLIC MAIN
PUBLIC NEW_VEC,OLD_VEC,CURSOR_POS
C_SEG SEGMENT
ASSUME CS:C_SEG, DS:C_SEG, SS:C_SEG
ORG 100H
START:
JMP MAIN
;
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 101 -
SS_BUF DB 16DUP(?) ;bộ đệm lưu giữ màn hình
TIME_BUF DB '00:00:00$'
CURSOR_POS DW ? ;vị trí con trỏ
ON_FLAG DB 0 ;1=chạy thủ tục ngắt
NEW_VEC DW ?,? ; chứa vectơ mới
OLD_VEC DW ?,? ;chứa vectơ cũ
;
MAIN PROC
;thủ tục ngắt
; cất các thanh ghi
PUSH DS
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV AX,CS ;thiết lập DS
MOV DS,AX
MOV ES,AX
;Gọi thủ tục ngắt bàn phím cũ
PUSHF
CALL INITIALIZE
;lấy các cờ bàn phím
MOV AX,CS ;thiết lập lại DS
MOV DS,AX
MOV ES,AX ;ES cho phân đoạn hiện hành
MOV AH,02 ; xem cờ bàn phím
INT 16H ;AL chứa các cờ bàn phím
TEST AL,1 ; Shift phải?
JE I_DONE ; không, thoát
TEST AL,100B ;Ctrl?
JE I_DONE ;không, thoát
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 102 -
;đúng, xử lý
CMP ON_FLAG,1;thủ tục đang được kích hoạt?
JE RESTOR ;đúng, khử kích hoạt
MOV ON_FLAG,1 ;không, kích hoạt
;cất vị trí con trỏ và thông tin màn hình
MOV AH,03 ;lấy vị trí con trỏ
MOV BH,0 ;trang 0
INT 10H ;DH=hàng,DL=cột
MOV CURSOR_POS,DX ;lưu vị trí con trỏ
CALL SAVE_SCREEN ;lưu màn hình
; hiển thị thời gian
; định vị con trỏ đến góc trên bên phải
MOV DL,72 ; cột 72
CALL SET_CURSOR
LEA BX,TIME_BUF
CALL GET_TIME ; lấy thời gian hiện tại
;hiển thị thời gian
LEA SI,TIME_BUF
MOV CX,8 ; 8ký tự
MOV BH,0 ; trang 0
MOV AH,0EH ; viết ký tự
M1:
LODSB ;ký tự trong AL
INT 10H ;con trỏ được chuyển
; đến hàng tiếp theo
LOOP M1 ; lặp lại 8 lần
JMP RES_CURSOR
RESTOR:
;phục hồi màn hình
MOV ON_FLAG,0 ;xoá cờ
CALL RESTOR_SCREEN
;phục hồi vị trí con trỏ lưu trữ
RES_CURSOR:
MOV AH,02 ;thiết lập con trỏ
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 103 -
MOV BH,0
MOV DX,CURSOR_POS
INT 10H
;phục hồi các thanh ghi
I_DONE: POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
IRET ;trở về từ ngắt
MAIN ENDP
C_SEG ENDS
END START
Tập tin PGM3_4.ASM
PUBLIC GET_TIME,SETUP_INT
C_SEG SEGMENT PUBLIC
ASSUME CS:C_SEG
;
GET_TIME PROC
MOV AH,2CH
INT 21H
MOV AL,CH
CALL CONVERT
MOV [BX],AX
MOV AL,CL
CALL CONVERT
MOV [BX+3],AX
MOV AL,DH
CALL CONVERT
MOV [BX+6],AX
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 104 -
RET
GET_TIME ENDP
;
CONVERT PROC
MOV AH,0
MOV DL,10
DIV DL
OR AX,0303H
RET
CONVERT ENDP
;
SETUP_INT PROC
MOV AH,35H
INT 21H
MOV [DI],BX
MOV [DI+2],ES
MOV DX,[SI]
PUSH DS
MOV DS,[SI+2]
MOV AH,25H
INT 21H
POP DS
RET
SETUP_INT ENDP
;
C_SEG ENDS
END
LINK PGM3_3+PGM3_2+PGM3_4+PGM3_1.
Chú ý PGM3_1 được liên kết cuối cùng để thủ tục INITIALIZE
được đưa vào cuối chương trình. Viết các chương trình TSR rất phức tạp,
nếu như đã có một chương trình TSR khác trong hệ thống, chương trình
hiện có có thể không còn thực hiện đúng nữa
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 105 -
PHỤ LỤC A: MỘT SỐ CHƯƠNG TRÌNH PHỤC VỤ CỦA DOS
Chức năng Ngắt
(Hex)
TG vào
Kết thúc chương trình 20
Kết thúc nhưng nằm
thường trực (max 64KB)
27 DS:DX=địachỉ byte sau vùng được giữ
lại thường trú
CÁC CHƯƠNG TRÌNH PHỤC VỤ CỦA DOS (NGẮT 21h)
Chức năng Số (Hex) TG vào TG ra
Đưa vào từ bàn phím 01 AH=01
AL=ký tự vào 8 bit
Đưa ra màn hình một ký
tự
02 AH=02
DL=ký tự ra 8 bit
Đưa ra máy in 05 AH=05
DL=ký tự
Đưa vào trực tiếp từ bàn
phím và không hiện
07 AH=07
AL=ký tự vào 8 bit
Đưa ra màn hình một
chuỗi
09 AH=09
DS:DX = trỏ đến
chuỗi kết thúc bằng
'$'
Đưa vào đệm bàn phím 0A AH=0A
DS:DX=trỏ đến đệm
bàn phím
Thiết lập vectơ ngắt 25 AH=25
AL= số hiệu ngắt
DS:DX= trỏ tới
chương trình xử lý
ngắt
Lấy ngày tháng năm 2A AH=2A AL=thứ trong tuần
CX=năm (1980-2099
DH=tháng
DL=ngày
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 106 -
Nguyễn Hữu Lộc Khoa Vật Lý
Chức năng Số (Hex) TG vào TG ra
Đặt ngày tháng năm 2B AH=2B
CX=năm (1980-2099
DH=tháng
DL=ngày
AL=mã trả về
Lấy thời gian 2C AH=2C CL=phút
CH=giờ
DL=phần trăm giây
DH=giây
Đặt thời gian 2D AH=2D
CL=phút
CH=giờ
DL=phần trăm giây
DH=giây
Kết thúc chương trình và
thường trú
31 AH=31
AL=mã trả về
DX=địa chỉ đoạn
chương trình trên bộ
nhớ để giải phóng
AX=mã trả về
Lấy vectơ ngắt 35 AH=35
AL=số hiệu ngắt
ES:BX=vectơ ngắt
AX=mã trả về
Tạo thư mục 39 AH=39
DS:DX = trỏ đến
chuỗi ASCII tên
đường
Nếu sai CF=01,
AX= mã lỗi
Nếu tốt: CF=00
Xoá thư mục 3A AH=3A
DS:DX = trỏ đến
chuỗi ASCII tên
đường
Nếu sai CF=01,
AX= mã lỗi
Đổi thư mục hiện thời 3B AH=3B
DS:DX = trỏ đến
chuỗi ASCII tên
đường
Nếu sai CF=01,
AX= mã lỗi
Tạo file 3C AH=3C
CX=đặc tính file
DS:DX= trỏ đến
AX=thẻ file hoặc mã
trả về
CF=00 (tốt), 01 (sai)
Hợp Ngữ - 107 -
Nguyễn Hữu Lộc Khoa Vật Lý
Chức năng Số (Hex) TG vào TG ra
chuỗi ASCII tên file
Mở thẻ 3D AH=3D
CX=mã truy nhập
DS:DX = trỏ đến
chuỗi ASCII tên file
AX=thẻ file hoặc mã
trả về
Đóng thẻ 3E AH=3E
BX=thẻ file
AX=thẻ file hoặc mã
trả về
Đọc file hoặc từ thiết bị 3F AH=3F
BX=thẻ file
CX=số byte cần đọc
DS:DX= trỏ đến
vùng đệm dữ liệu
AX=số byte đọc được
hoặc mã trả về
Ghi file hoặc ra thiết bị 40 AH=40
BX=thẻ file
CX=số byte cần ghi
DS:DX= trỏ đến
vùng đệm dữ liệu
AX=số byte ghi được
hoặc mã trả về
Xoá file 41 AH=41
DS:DX = trỏ đến
chuỗi ASCII tên file
Nếu sai CF=01, AX=
mã trả về
Kết thúc quá trình 4C AH=4C
AL= mã trả về
Đổi tên file 56 AH=56
DS:DX = trỏ đến
chuỗi ASCII tên cũ
ES:DI = trỏ đến
chuỗi ASCII tên mới
Nếu sai CF=01, AX=
mã trả về
Hợp Ngữ - 108 -
PHỤ LỤC B: MỘT SỐ CHƯƠNG TRÌNH PHỤC VỤ CỦA ROM-
BIOS
Chức năng Ngắt
(Hex)
TG vào TG ra
Di chuyển con trỏ 10 AH=2
BH=số hiệu trang
DH=số hiệu dòng
DL=số hiệu cột
Lấy vị trí con trỏ 10 AH=3
BH=số hiệu trang
DH=số hiệu cột
DL=số hiệu dòng
CH=dòng quét đầu
của con trỏ
CL=dòng quét cuối
của con trỏ
Đọc một ký tự và thuộc
tính
10 AH=8
BH=trang màn hình
AH=thuộc tính
AL=ký tự
Ghi 1 ký tự 10 AH=0E
AL=ký tự
BL=màu trong kiểu
đồ thị
Đọc một cung 13 AH=02
AL= số cung
CH=rãnh
CL=cung
DL=ổ đĩa
ES:BX=con trỏ đến
đệm
CF=báo kết quả
tốt/hỏng
AH=mã trạng thái
AL=số cung được
đọc
Ghi một cung 13 AH=03
AL= số cung
CH=rãnh
CL=cung
DL=ổ đĩa
ES:BX=con trỏ đến
đệm
CF=báo kết quả
tốt/hỏng
AH=mã trạng thái
AL=số cung được ghi
Nguyễn Hữu Lộc Khoa Vật Lý
Hợp Ngữ - 109 -
Nguyễn Hữu Lộc Khoa Vật Lý
Chức năng Ngắt
(Hex)
TG vào TG ra
Lấy các tham số hiện
thời của ổ đĩa
13 AH=08
DL=số hiệu đĩa
DL=số ổ đĩa
DH=số lượng mặt
max
CL[0,5]=số hiệu
cung max
CL[6,7]=2 bit cao
của số lượng từ trụ
max
CH=ca'c bit thấp của
số lượng từ trụ max
CF=cờ báo kết quả
tốt/hỏng
AH=mã trạng thái
Đọc ký tự tiếp từ bàn
phím
16 AH=00 AH=mã quét bàn
phím
AL=mã ASCII
Lấy cờ bàn phím 16 AH=02 AL=cờ các phím
bit 0=1: Shift phải
bit 1=1: Shift trái
bit 2=1: Ctrl
bit 3=1: Alt
bit 4=1: Scroll lock
bit 5=1: Num Lock
bit 6=1:Caps lock
bit 7=1: Chế độ chèn
Gửi một byte ra máy in 17 AH=00
AL=ký tự
DX=số máy in
Giá trị các bit:
0: quá thời gian
1: không sử dụng
2: không sử dụng
3=1:lối vào/ra
4=1: đã được chọn
5=1:hết giấy
6=1:xác nhận
7=1:không bận
Hợp Ngữ - 110 -
TÀI LIỆU THAM KHẢO
1. Ngôn ngữ lập trình Assembly và máy vi tính IBM-PC - Ytha Yu và
Charles Marut (Quách Tuấn Ngọc-Đỗ Tiến Dũng- Nguyễn Quang
Khải biên dịch) - Nhà xuất bản Giáo dục
2. Lập trình Hợp ngữ Turbo Assembler 2.0 - Phan Trương Dần - Nhà xuất
bản Giáo dục
3. Cẩm nang lập trình - Peter Norton (Nguyễn Minh San dịch) - Nhà xuất
bản Giáo Dục
4. Cẩm nang cho người lập trình trên máy vi tính IBM- Peter Norton -
Nhà xuất bản Thống kê - Viện Điện tử - Tin học
5. Assembleur facile - PhMercier- Marabout
6. Hardware Reference Manual 8088 - Intel
7. Macro Assembler Programmer's Guide 5.0 - Microsoft
Nguyễn Hữu Lộc Khoa Vật Lý
Các file đính kèm theo tài liệu này:
- giao_trinh_hop_ngu_nguyen_huu_loc.pdf