Giáo trình Hợp ngữ - Nguyễn Hữu Lộc

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

pdf110 trang | Chia sẻ: huongthu9 | Lượt xem: 381 | Lượt tải: 0download
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:

  • pdfgiao_trinh_hop_ngu_nguyen_huu_loc.pdf