Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY

Các ngắt của hệ thống hỗ trợ cho lập trình ASSSEMBLY +cho phép đặt segment vào 1 địa chỉ mong muốn (theo yêu cầu) của
Có 4 hàm hay dùng nhất: bộ nhớ RAM
Hàm 1: Chờ 1 ký tự từ bàn phím: tên_segment SEGMENT at địa_chỉ_dạng_vật_lý
Mov ah, 1;AL chứa mã ASCII ký tự mã vào {thân}
Int 21h tên_segment ENDS
Hàm 2: Đưa 1 ký tự dạng ASCII ra màn hình tại vị trí con trỏ +cho chương trình đa tệp: cách gộp các segment có cùng tên nằm ở
đang đứng các tệp khác nhau khi liên kết. Ví dụ: Tệp 1 có DATA SEGMENT; Tệp 2
Cách 1: Nhờ ngắt của BIOS có DATA SEGMENT.khác
Mov al, mã ASCII của ký tự _COMMON tức là độ dài của segment sau liên kết bằng độ dài
Mov ah, oeh segment lớn nhất
Int 10h _PUBLIC tức là độ dài của segment sau liên kết bằng tổng độ dài cả
Cách 2: 2 segment
Mov dl, mã ASCII của ký tự _PRIVATE tức là độ dài của segment sau liên kết bằng độ dài của
Mov ah, 2 chính nó (không quan hệ với nhau, đây là chế độ default)
Int 21h _STACK giống như _PUBLIC
Hàm 3: Hiện 1 xâu ký tự kết thúc bằng dấu $ ra màn hình _CLASS sắp xếp các segment lại gần nhau sau khi liên kết
Mov dx, offset tên biến xâu (Sau khi liên kết thì những segment nào cùng một nhóm thì ở gần
Mov ah, 9 nhau)
Int 21h _GROUP gộp các segment có cùng kiểu lại với nhau cho dễ dàng qui
Hàm 4: Trở về DOS chiếu
Mov ah, 4ch ;[int 20h] tên_ nhóm GROUP tên_các_segment (cách nhau bởi dấu , )
Int 21h _ASSUME cho biết tên segment thuộc loại segment nào
Các DIRECTIVE điều khiển SEGMENT dạng đơn giản: dễ viết, dễ _ASSUME tên_thanh_ghi SEG : tên_seg
liên kết nhưng chưa bao hết mọi tình huống về điều khiển SEGMENT Cấu trúc một chương trình Assembly thường thấy: Khai báo
.Model thuê vùng nhớ RAM thích hợp cho chương trình MACRO, STRUCT, UNION, RECORD, SEGMENT
.Model kiểu_tiny code+data≤64KB Dạng đơn giản
.Model kiểu_small code≤64KB;data≤64KB .Model kiểu
.Model kiểu_compact code≤64KB;data≥64KB .Stack độ lớn
.Model kiểu_medium code≥64KB;data≤64KB [.Data
.Model kiểu_large code≥64KB;data≥64KB song khi khai báo1 array khai báo biến]
không ≤64KB .Code
.Model kiểu_large code≥64KB;data≥64KB song khi khai báo1 array nhãn_chương_trình:
không >64KB mov ax, @data
.Stack Độ lớn (Byte) → Xác lập độ lớn stack cho chương trình mov ds, ax
.Data Xác lập vùng nhớ cho dữ liệu của chương trình khai báo ...
biến nằm ở segment này thân chương trình
.Data Khai báo biến (có 3 loại biến) ...
Với các loại biến số thì kiểu db có độ dài 1 byte mov ah, 4ch
dw có độ dài 2 byte int 21h
dd có độ dài 4 byte [các chương trình con]
dp/df có độ dài 6 byte END nhãn_chương_trình
dq có độ dài 8 byte
dt có độ dài 10 byte Dạng chuẩn
Với các loại biến xâu có các cách khai báo như sau: _Stack segment
tên_biến_xâu db ‘các ký tự’ db độ_dài dup(?)
tên_biến_xâu db độ_lớn dup(‘1 ký tự’) _Stack ends
tên_biến_xâu db độ_lớn dup(?) Data segment
Với các loại biến trường số (array) có các cách khai báo như sau: khai báo biến
tên_biến_trường kiểu_thành_phần (các số cách nhau bởi dấu ,) Data ends
tên_biến_trường kiểu_thành_phần độ_lớn dup(giá trị 1 số) Code segment
tên_biến_trường kiểu_thành_phần độ_lớn dup(?) Assume cs:code ds:data ss:stack nhãn_chương_trình:
.Code Xác lập vùng nhớ truy xuất ngẫu nhiên dùng cho phần mã máy mov ax, data
.Code mov ds, ax
nhãn_chương_trình: ...
mov ax, @data thân chương trình
mov ds, ax ...
... mov ah, 4ch
thân chương trình int 21h
... [các chương trình con]
mov ah, 4ch ENDS
int 21h END nhãn_chương_trình
[các chương trình con] *Chương trình con:
end nhãn_chương_trình 1, Cơ chế khi 1 chương trình con bị gọi:
Các DIRECTIVE điều khiển SEGMENT dạng chuẩn: _SEGMENT; Bước 1: Tham số thực đưa vào STACK
_GROUP; _ASSUME Bước 2: Địa chỉ của lệnh tiếp theo được đưa vào STACK
_SEGMENT Xác lập các segment cho chương trình Bước 3: Hệ điều hành quản lý địa chỉ đầu của chương trình con do vậy
tên_segment SEGMENT align combine use ‘class’ Hệ điều hành sẽ đưa địa chỉ đó vào CS:IP → rẽ nhánh vào chương trình
{thân segment} con
tên_segment ENDS Bước 4: Thực hiện thân chương trình con cho đến khi gặp lệnh RET thì
trong đó: vào STACK lấy địa chỉ lệnh tiếp theo (đã cất ở Bước 2) và cho vào
tên_segment là 1 identifier (không chứa dấu cách, dấu \ ; : ...) CS:IP, rồi quay về chương trình đã gọi nó
align là cách xác lập khoảng cách giữa segment đang khai báo với Bước 5: Tiếp tục thực hiện chương trình đang đợi
segment trước nó 2, Cú pháp của chương trình con Assembly:
align Tên_chương_trình_con PROC [NEAR/FAR]
byte khoảng cách 1 byte Bảo vệ các thanh ghi sẽ bị phá vỡ ở thân chương trình
word khoảng cách 2 byte Thân chương trình con
paka khoảng cách 16 byte Hồi phục các thanh ghi mà chương trình con phá vỡ
page khoảng cách 256 byte RET
combine có hai chức năng: Tên_chương_trình_con ENDP
a, Vấn đề NEAR – FAR:

1
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
NEAR chương trình con cùng nằm trên 1 segment với chương trình gọi IFB <biểu thức>
nó → địa chỉ lệnh tiếp theo cất vào STACK (Bước 2) chỉ cần 2 byte Khối_lệnh
offset ENDIF
FAR chương trình con nằm khác segment với chương trình con gọi nó Lệnh IFNB giống như lệnh IFB nhưng ngược điều kiện
→ địa chỉ lệnh tiếp theo cất vào STACK (Bước 2) cần đến 4 byte offset Chức năng: Dịch khối lệnh khi <biểu thức 1> = <biểu thức 2>
* Với khai báo segment dạng đơn giản thì directive model sẽ xác định IFIDN <biểu thức 1>, <biểu thức 2>
hiện chương trình con NEAR hay FAR Khối_lệnh
. Model tiny → chương trình con là NEAR ENDIF
. Model small → chương trình con là NEAR Lệnh IFDIF giống như lệnh IFIDN nhưng ngược điều kiện
. Model compact → chương trình con là NEAR Chức năng: Dịch khối lệnh khi nhãn theo sau đó đã được khai báo
. Model medium→ chương trình con là FAR IFDEF nhãn
. Model large → chương trình con là FAR Khối_lệnh
. Model huge → chương trình con là FAR ENDIF
* Với khai báo dạng chuẩn thì mặc định là NEAR Lệnh IFNDEF giống như lệnh IFDEF nhưng ngược điều kiện
b, Chương trình con Assembly không có đối số → cơ chế kích *Macro là 1 cơ chế giúp người lập trình tạo 1 lệnh mới trên cơ sở tập
hoạt chương trình con Assembly không có Bước 1 lệnh sẵn có của Assembly
3, Chuyển giao tham số: - Trước khi được dùng thì phải khai báo
Cách 1: Nhờ thanh ghi Cú pháp:
Chương_trình_chính Chương_trình_con Tên_Macro MACRO[đối]
...... ...... Bảo vệ các thanh ghi sẽ bị phá vỡ ở thân chương trình
mov ax, 10 mov bx, ax Thân MACRO
call Chương_trình_con ...... Hồi phục các thanh ghi mà chương trình con phá vỡ
...... ENDM
(khi đó bx = 10) - Cách dùng lệnh mới đã xác lập ở MACRO: Sau khi macro đã được xác
Cách 2: Nhờ biến nhớ lập thì tên của Macro trỏ thành một lệnh mới của ASM
Chương_trình_chính Chương_trình_con - Cách dùng: Gọi tên macro và thay vì đối sẽ là tham số thực
...... ...... Chương trình Macro hiện xâu ra màn hình:
mov value, 20 mov bx, value HIENSTRING MACRO XAU
call Chương_trình_con ...... Push ax, bx
...... Lea dx, XAU
(khi đó bx = 20) Mov ah, 9
Cách 3: Thông qua STACK (dùng khi liên kết với ngôn ngữ lập trình Int 21h
bậc cao) Pop dx, ax
4, Bảo vệ thanh ghi: ENDM
Khi thân chương trình con sử dụng các lệnh làm giá trị thanh ghi thay Chương trình Macro xóa màn hình:
đổi như and, xor, ... thì phải bảo vệ các thanh ghi đó trước khi dùng CLRSCR MACRO
Cách 1: Dùng các lệnh POP, PUSH Push ax
Cách 2: Chuyển vào biến hoặc thanh ghi khác sau đó hồi phục Mov ah, 0fh
Tệp include Int 10h
Tệp INCLUDE cho phép người lập trình viết gọn chương trình Mov ah, 0
- Thiết lập 1 tệp ngoài (gọi là tệp INCLUDE) mà trong tệp này chứa Int 10h
khối lệnh Assembly .ASM Pop ax
- Sau đó dùng lệnh INCLUDE để chèn khối lệnh đó vào tệp chương ENDM
trình đang viết. Cú pháp: tính ưu việt của macro
.............. a, So sánh Macro với chương trình con:
INCULDE X:\đường dẫn\tệp INCLUDE Tốc độ: Khi chạy chương trình thì Macro nhanh hơn vì không phải dùng
.............. lệnh CALL và RET
- Cơ chế của chương trình dịch Assembly khi gặp INCLUDE: chương Tiết kiệm bộ nhớ: Chương trình con chiếm ít bộ nhớ hơn
trình dịch của Tubor Assember khi gặp INCLUDE thì thực hiện các Macro cho phép chuyển giao tham số thông qua đối và cho phép sử
bước: dụng các Directive lặp khidịch chương trình. Các Directive điều khiển
* Mở tệp INCLUDE theo sau Directive Include điều kiện khi dịch chương trình.
* Sao chép và chèn toàn bộ khối lệnh Assembly có trong tệp INCLUDE b, So sánh Macro với tệp INCLUDE:
vào vị trí Directive Include đứng Cơ chế: Giống nhau khi dịch
* Tiến hành dịch khối lệnh đó Tốc độ: Khi chạy chương trình thì Macro nhanh hơn vì không phải mở
- Cách tìm tệp INCLUDE để chèn đóng tệp
* Nếu tệp đứng sau Directive Include có tên đĩa, đường dẫn thì chương Macro cho phép có nhãn nhảy trong lệnh của Macro nhờ Directive
trình dịch tìm đến, nếu không có thì đó là thư mục hiện hành, còn nếu Local. Trong thân Macro cho phép có các Macro khác
không có nữa thì sai Chương trình dạng *.com và *.exe
* Nếu sai thì chỉ có cách sửa lại chương trình nguồn. Khi dịch chương Chương trình .EXE có 3 segment {code, data và stack}. Có thể không
trình dùng thêm tham số TASM -i A:\...\*.ASM cùng nằm trên 1 segment
- Hạn chế của INCLUDE là không được phép có nhãn nhảy trong khối Chương trình .COM có 3 segment {code, data và stack} nằm cùng
lệnh của tệp INCLUDE khi gọi nó 2 lần trên 1 segment. Khi chạy chương trình .COM cần 256 byte đầu của
macro và các vấn đề liên quan segment đó để nhảy. Do vậy, lệnh đầu của chương trình .COM sẽ đặt ở
1, Các lệnh lặp khối lệnh khi dịch chương trình: offset → người lập trình phải khai báo cho hệ điều hành Directive ORG
REPT dịch khối lệnh theo số lần đi sau REPT Khai báo chương trình dạng .COM có 1 segment và là Code Segment →
REPT n biến cũng được khai báo ở Code Segment
Khối_lệnh .Code
ENDM Nhãn_chương trình:
IRP dịch khối lệnh theo số lượng danh sách Jmp nhãn_khác
IRP tên_đối <danh sách> [nếu có khai báo biến]
Khối_lệnh Khai báo biến
ENDM Nhãn_khác:
- Các Directive điều khiển điều kiện khi dịch chương trình ......
Chức năng: Dịch khối lệnh khi điều kiện đúng TRUE mov ah, 4ch
IF <điều kiện> IF <điều kiện> int 21h
Khối_lệnh Khối_lệnh_1 Dạng thường thấy của chương trình .COM thuần túy [Khai báo
ENDIF ELSE Khối_lệnh_2 MACRO, STACK, UNION, RECORD]
ENDIF Dạng đơn giản Dạng chuẩn
Lệnh IFE giống như lệnh IF nhưng ngược điều kiện .Model tiny .Code segment
Chức năng: Dịch khối lệnh khi biểu thức <điều kiện> = 0 (hoặc small) ORG 100h

2
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
.Code assume cs:code,ds:code,ss:code Int n (tác động linh kiện)
ORG 100h Nhãn_chương_trình: Bước 1: Flag → STACK;Tham số thực → STACK
Nhãn_chương_trình: Jmp nhãn_khác Bước 2: Địa chỉ lệnh tiếp theo → STACK
Jmp nhãn_khác Khai báo biến Bước 3: Hệ điều hành quản lý địa chỉ đầu của chương trình con phục
Khai báo biến Nhãn_khác: vụ ngắt. Song địa chỉ đầu của chương trình con phục vụ ngắt nằm
Nhãn_khác: ........ trong ô nhớ tương ứng của bảng vectơ ngắt → máy tính vào vectơ ngắt
......... int 20h lấy địa chỉ đầu của chương trình con phục vụ ngắt đưa vào cs:ip → rẽ
int 20h [các chương trình con] nhánh vào chương trình con phục vụ ngắt
[các chương trình con] code ends Bước 4: Thực hiện các lệnh của chương trình con cho đến khi gặp
END nhãn_chương_trình END nhãn_chương_trình IRET thì vào STACK lấy địa chỉ lệnh tiếp theo (đã cất ở bước 2) → cs:ip
Directive public và trở về chương trình đang dở
Chức năng: Báo cho chương trình dịch biết những nhãn ở Model này Bước 5: Trước khi tiếp tục chương trình đang dở thì vào STACK lấy cờ
cho phép các tệp khác cũng có thể dùng đã cất
Cú pháp: Public tên_nhãn Bảng vectơ ngắt: là vùng nhớ RAM chứa địa chỉ đầu của chương trình
Khai báo kiểu nhãn con phục vụ ngắt. Máy tính có 256 ngắt → có 256 chương trình con
.Với hằng: Public tên_hằng = hằng phục vụ ngắt. Địa chỉ ô bằng n * 4 (mỗi địa chỉ 4 byte)
Public Port Các bước để xác lập chương trình con phục vụ ngắt:
Port = 038h Bước 1: Viết chương trình con theo yêu cầu của thuật toán
.Với biến: Public tên_biến Cú pháp: Tên_chtrình_con_pvụ_ngắt PROC [NEAR/FAR]
Khai báo biến Bảo vệ các thanh ghi
.Với tên chương trình con: Thân chương trình
Public tên_chương_trình_con Phục hồi các thanh ghi
tên_chương_trình_con PROC IRET
........... Tên_chtrình_con_pvụ_ngắt ENDP
RET Bước 2: Sau khi viết xong chương trình con phục vụ ngắt thì tìm địa
tên_chương_trình_con ENDP chỉ đầu của chương trình này đưa vào vị trí tương ứng của bảng vectơ
Directive public ngắt
Chức năng: Báo cho chương trình dịch biết Module này xin phép được Khởi động máy tính với hệ điều hành DOS
dùng các nhãn mà các Module khác đã cho phép Với máy tính của INTEL, khi bật máy thì thanh ghi CS = F000h; IP =
Cú pháp: Extrn tên_nhãn: kiểu FFF0h và sẽ nhảy vào thực hiện lệnh ở ô nhớ F000:FFF0. Lệnh này là
.Nhãn là tên hằng: Extrn tên_nhãn: ABS lệnh jmp và nó nhảy đến chương trình khởi động máy tính đều nằm ở
Extrn Post kiểu ROM-BIOS
.Nhãn là biến nhớ: Extrn x: word (hoặc byte hoặc dword) ROM-BIOS là vùng nhớ chỉ đọc, không ghi được và chứa 2 loại chương
.Nhãn là chương trình con: trình khởi động máy và chương trình phục vụ ngắt của BIOS
Extrn tên_chương_trình_con:PROC Các chương trình khởi động máy tính:
Directive global Test CPU: kiểm tra các thanh ghi. Tống vào các giá trị 00, 55 và FF vào
Chức năng: Không phải chương trình nào cũng có Directive này, nó các thanh ghi và kiểm tra lại có bằng 00, 55 và FF không. Đồng thời
thay cho Public và Extrn kiểm tra một số lệnh ASM nếu có lỗi thì hiện FATA ERROR.
Cú pháp: GLOBAL tên_nhãn: kiểu Kiểm tra ROM-BIOS: trong ROM có 1 byte CHECKSUM (tổng các byte
Khai báo biến của ROM) khi khởi động thì có 1 chương trình cộng các byte của ROM
Liên kết C với Assembly lại lưu kết quả vào 1 byte và so sánh byte này với CHECKSUM. Nếu
INLINE ASM là chèn khối lệnh ASM vào chương trình được viết bằng bằng nhau thì tức là ROM tốt, ngược lại là tồi.
C Kiểm tra một số linh kiện quan trọng của mainboard
Cú pháp: khối lệnh C 8259 là chip phục vụ ngắt
ASM lệnh ASM 8250 UART (COM)
........... 8253 Timer
ASM lệnh ASM 8237 DMA
khối lệnh C Kiểm tra RAM (giống hệt CPU và thanh ghi) tức là cho toàn bộ các byte
Dịch và liên kết của RAM các giá trị 00, 55, FF liệu RAM có chấp nhận các giá trị này
TCC -ms :IC\TC\INCLUDE -LC không
Hạn chế: Các lệnh ASM được chèn thì dịch nhờ bởi chương trình dịch Xác lập bảng vec tơ ngắt của BIOS
của TC. Do đó 1 số lệnh khó của ASM dịch không đúng. Không cho Đưa mọi địa chỉ đầu của các chương trình con phục vụ ngắt vào bảng
phép có các nhãn nhảy trong ASM → khối lệnh chèn vào yếu (vì không vec tơ ngắt
có LOOP, nhảy có và không có điều kiện) Đưa các thông số máy tính đang dùng vào vùng nhớ biến BIOS
Viết tách biệt tệp cho c và tệp cho asm Kiểm tra liệu có ROM mở rộng: với màn hình và ổ đĩa thì về phần cứng
Phải giải quyết 3 vấn đề: cho các Card điều khiển không giống nhau → không thể viết 1 driver
1, Vấn đề đa tệp: (khai báo Public) với Module của C, bất kỳ khai báo chung và nạp vào ROM-BIOS chuẩn → thỏa hiệp của các hãng: Ai sản
nào của C đều là khai báo Public. Khai báo External ngôn ngữ C phải xuất phần cứng thì viết driver cho nó và nạp vào ROM và ROM đó sẽ
xin phép dùng các nhãn đã cho phép từ tệp ngoài. Với Module ASM được đặt trên Card đó
giống như đa tệp thuần túy Int 19h: Lôi boot sector xuống RAM và trao quyền cho chương trình
2, Vấn đề dấu (-) (underscore) người viết chương trình ASM phải nằm trong boot sector
thêm dấu – vào trước trên các nhãn dùng chung với C và thêm ở mọi Trong boot sector là sector 512 byte chứa tham số đĩa và chứa chương
nơi mà tên đó xuất hiện trình mồi
3, Vấn đề giá trị quay về của hàm ASM: qui định với giá trị 2 byte Chương trình mồi lôi 2 tệp ẩn xuống RAM (hệ điều hành DOS)
thì trước khi RET ax = bao nhiêu thì tên hàm ASM có giá trị bấy nhiêu. Kiểm tra thiết bị ngoại vi
Với giá trị 4 byte trước khi RET dx:ax có giá trị bao nhiêu thì hàm ASM Lôi COMMAND.COM vào vùng nhớ RAM – là chương trình dịch các lệnh
có giá trị bấy nhiêu của DOS → Mã máy
cơ chế khi một ngắt và chương trình con được kích hoạt CONFIG.SYS
Chương trình con bình thường: AUTOEXEC.BAT
CALL C:\>
Bước 1: Tham số thực → STACK
Bước 2: Địa chỉ lệnh tiếp theo → STACK
Bước 3: Hệ điều hành quản lý địa chỉ đầu của chương trình con → Hệ
điều hành đưa địa chỉ đầu của chương trình con → cs:ip → rẽ nhánh
vào chương trình con
Bước 4: Thực hiện các lệnh của chương trình con → RET thì vào
STACK lấy địa chỉ lệnh tiếp theo (đã cất ở bước 2) → cs:ip và trở về
chương trình đang dở
Bước 5: Tiếp tục chương trình đang dở
Chương trình con phục vụ ngắt:

3
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
call Hien_so_N
hienstring m4
mov ah,1
int 21h
cmp al,'c'
je ps
Bài tập 1: mov ah,4ch
Hiện 1 xâu ký tự “Hello TASM!” ra màn hình int 21h
Cách 1: include C:\HTDAT\INCLUDE\lib2.asm
.MODEL small code ends
.STACK 100h end ps
.DATA So sánh 2 số nhập vào từ bàn phím xem số nào bé hơn
Message db ‘Hello TASM!$’ Cách 2:
.CODE hien_string MACRO xau
ProgramStart: push ax dx
Mov AX,@DATA mov dx,offset xau
Mov DS,AX mov ah,9
Mov DX,OFFSET Message int 21h
Mov AH,9 pop dx ax
Int 21h ENDM
Mov AH,4Ch ;---------------------------------
Int 21h .model small
END ProgramStart .stack 100h
Cách 2: .data
_STACK segment stack ‘stack’ sohex dw ?
db 100h dup(?) temp dw ?
_STACK ends m1 db 0ah,0dh,'Vao so thu1: $'
DATA segment m2 db 0ah,0dh,'Vao so thu2: $'
Message db ‘Hello TASM!’,0 m3 db 0ah,0dh,'So be la: $'
DATA ends .code
CODE segment ps:
Assume CS:CODE, DS:DATA, SS:_STACK mov ax,@data
ProgramStart: mov ds,ax
Mov AX,DATA hien_string m1
Mov DS,AX call VAOSO
Mov SL,OFFSET Message mov ax,sohex
cld mov temp,ax
L1: hien_string m2
Lodsb call VAOSO
And AL,AL mov bx,sohex
Jz Stop hien_string m3
Mov AH,0eh cmp ax,bx
Int 10h jl L1
Jmp L1 xchg ax,bx
Stop: L1:
Mov AH,1 call HIENSO
Int 21h mov ah,1
Mov AH,4Ch int 21h
Int 21h mov ah,4ch
CODE ends int 21h
END ProgramStart ;--------------------------------------------
Bài tập 2: VAOSO PROC
So sánh 2 số nguyên nhập từ bàn phím xem số nào bé hơn push ax bx cx dx
Cách 1: mov bx,10
include C:\HTDAT\INCLUDE\lib1.asm xor cx,cx
_stack segment stack 'stack' mov sohex,cx
db 100h dup(?) VS1:
_stack ends mov ah,1 ; Ham nhan 1 ki tu va --->al
data segment int 21h
m1 db 10,13,'Vao so thu nhat:$' cmp al,0dh
m2 db 10,13,'Vao so thu hai:$' je VS2
m3 db 10,13,'So be la:$' sub al,30h
m4 db 10,13,'Co tiep tuc khong (c/k)?:$' mov cl,al
data ends mov ax,sohex
code segment mul bx
assume cs:code,ds:data,ss:_stack add ax,cx
ps: mov sohex,ax
mov ax,data jmp VS1
mov ds,ax VS2:
clrscr pop dx cx bx ax
hienstring m1 ret
call Vao_so_N VAOSO ENDP
mov bx,ax ;----------------------------------------------
hienstring m2 HIENSO PROC
call Vao_so_N push ax bx cx dx
cmp ax,bx mov bx,10
jl L1 xor cx,cx
xchg ax,bx HS1:
L1: xor dx,dx
hienstring m3 div bx ; tuc lay dx:ax chia cho bx kq thuong-->ax va du-->dx

4
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
add dx,30h ; de dua ra dang ASCCI data ends
push dx ; tong 1 chu vao stack code segment
inc cx assume cs:code,ds:data,ss:_stack
cmp ax,0 ps:
jnz HS1 mov ax,data
HS2: mov ds,ax
pop ax clrscr
mov ah,0eh hienstring m1
int 10h call vao_so_N
loop HS2 hienstring m2
pop dx cx bx ax call Hien_so_N
ret hienstring m3
HIENSO ENDP call S_N_T
end ps mov ax,fv
Bài tập 3: call hien_so_N
Tính trung bình cộng 2 só nguyên nhập từ bàn phím hienstring m4
INCLUDE C:\INCLUDE\LIB1.ASM mov ah,1
_STACK segment int 21h
db 100h dup(?) cmp al,'c'
_STACK ends je ps
DATA segment mov ah,4ch
M1 db ‘Hay vao so thu 1: $’ int 21h
M2 db 0ah,0dh,‘Hay vao so thu 2: $’ include C:\HTDAT\INCLUDE\lib3.asm
M3 db 0ah,0dh,‘Trung binh cong cua 2 so nguyen la: $’ include C:\HTDAT\INCLUDE\lib2.asm
M4 db ‘-$’ code ends
M5 db ‘.5$’ end ps
M6 db 0ah,0dh,’ Co tiep tuc khong (c/k) ?: $’ Chương trình tính giai thừa của một số n nhập từ bàn phím
DATA ends Cách 2:
CODE segment code segment
assume cs:code,ds:data,ss:_stack assume cs:code,ds:code
ps: org 100h
mov ax,data start: jmp do
mov ds,ax msg1 db 'nhap vao mot so:$'
clrscr msg2 db 'ket qua la:$'
HienString M1 giaithua dw 1
call VAO_SO_N so dw 0
mov bx,ax m db 'ok $'
HienString M2 do :
call VAO_SO_N mov ah,09h
HienString M3 mov dx,offset msg1
Add ax,bx int 21h
And ax,ax call nhapso
Jns L1 call cr_lf
HienString M4 mov bx,1
Neg ax mov cx,ax
L1: lap:
Shr ax,1 mov ax,giaithua
Pushf mul bx
Call HIEN_SO_N inc bx
Popf mov giaithua,ax
Inc L2 loop lap
HienString M5 mov ax,giaithua
L2: push ax
HienString M6 push dx
Mov ah,1 mov ah,09h
Int 21h mov dx,offset msg2
Cmp al,’c’ int 21h
Je TT pop dx
Mov ah,4ch pop ax
Int 21h call inra
TT: mov ah,01h
Jmp ps int 21h
INCLUDE C:\INCLUDE\LIB2.ASM int 20h
CODE ends ;--------------------------
END ps cr_lf proc near
Bài tập 4: push ax
Nhập một số nguyên dương n từ bàn phím và tìm giai thừa của push dx
nó mov ah,02h
Cách 1: mov dx,0dh
include C:\HTDAT\INCLUDE\lib1.asm int 21h
_stack segment stack 'stack' mov dx,0ah
db 100h dup(?) int 21h
_stack ends pop dx
data segment pop ax
fv dw ? ret
fac dw ? cr_lf endp
m1 db 10,13,'Vao so n:$' ;---------------------------
m2 db 10,13,'Giai thua cua $' nhapso proc near
m3 db ' la:$' push dx
m4 db 10,13,'Co tiep tuc khong(c/k)?: ' push cx

5
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
push bx M4 db 0ah,0dh,’ Co tiep tuc khong (c/k) ?: $’
xor dx,dx So dw dw
mov so,0 DATA ends
mov cx,1 CODE segment
lap1: call nhap Assume CS:CODE, DS:DATA, SS:_STACK
cmp al,0dh PS:
je exit Mov AX,DATA
sub al,30h Mov DS,AX
xor ah,ah CLRSCR
xor dx,dx HienString M1
mov dx,ax Call VAO_SO_N
mov ax,so HienString M2
cmp cx,1 Call VAO_SO_N
je nota HienString M3
mov bl,10 Mov BX,AX
mul bl Mov so,1
nota: add ax,dx L1:
mov so,ax Inc so
inc cx Mov AX,so
jmp lap1 Cmp AX,BX
exit: mov ax,so Jg Stop
pop bx Mov CX,AX
pop cx Shr CX,1
pop dx L2:
ret Cmp CX,1
nhapso endp Jle L3
;--------------------------- Xor DX,DX
inra proc Div CX
mov bx,10 And DX,DX
xor cx,cx Jz L1
none_zero: Mov AX,so
xor dx,dx Loop L1
div bx L3:
push dx Call HIEN_SO_N
inc cx HienString M4
or ax,ax Jmp L1
jnz none_zero Stop:
write: pop dx HienString M5
add dl,'0' Mov AH,1
mov ah,02 Int 21h
int 21h Cmp AL,’c’
loop write Je TT
ret Mov AH,4Ch
inra endp Int 21h
TT:
;--------------------------- Jmp PS
public nhap INCLUDE C:\INCLUDE\LIB2.ASM
nhap proc near CODE ends
sta : END PS
push dx Bài tập 6:
mov ah,08 Nhập 2 số vào từ bàn phím và in ra tích của chúng
int 21h EXTRN
cmp al,0dh CR_LF:PROC,PRINT_CHAR:PROC,GET_IN_NUMBER:PROC,WRITE_C
je exit1 HAR:PROC
cmp al,30h ;----------------------------------
jb sta DATA_SEG SEGMENT PUBLIC
cmp al,39h DATA_1 DB 'ENTER TWO STRING:$'
ja sta DATA_2 DB 'NUMBER1:$'
mov dl,al DATA_3 DB 'NUMBER2:$'
; xor ah,ah PRODUCT DB 'PRODUCT IS:$'
TEMP_VAR DW 0
mov ah,02h TEMP DW 0
int 21h NUMBER DW 0
exit1: DATA_SEG ENDS
pop dx ;-------------------------------
ret STACK SEGMENT STACK
nhap endp DB 64 DUP('STACK')
;---------------------------- STACK ENDS
code ends ;------------------------------
end start CODE_SEG SEGMENT PUBLIC
Bài tập 5: ASSUME CS:CODE_SEG,DS:DATA_SEG,SS:STACK
Tìm số nguyên tố nhỏ hơn hoặc bằng số giới hạn cho trước START: MOV AX,DATA_SEG ;khoi tao thanh ghi DX
INCLUDE C:\INCLUDE\LIB1.ASM MOV DS,AX
_STACK segment MOV AH,09 ;yeu cau nhap
db 100h dup(?) MOV DX,OFFSET DATA_1
_STACK ends INT 21H
DATA segment CALL CR_LF
M1 db ‘Hay vao so gioi han: $’ MOV AH,09 ; so thu 1
M2 db 0ah,0dh,’ Cac so nguyen to tu 2 den $’ MOV DX,OFFSET DATA_2
M3 db ‘la: $’ INT 21H

6
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
CALL PRINT_CHAR POP BX
CMP AX,99 POP DX
JA EXIT RET
MOV TEMP_VAR,AX PRINT_CHAR ENDP
CALL CR_LF ;----------------------------
MOV AH,09 ; so thu 2 WRITE_CHAR PROC NEAR
MOV DX,OFFSET DATA_3 PUSH BX
INT 21H PUSH CX
CALL PRINT_CHAR XOR DX,DX
CMP AX,99 MOV BX,10
JA EXIT MOV CX,1
CALL CR_LF LOOP_2:
MUL NUMBER ;AX:=AX*NUMBER DIV BX
PUSH AX PUSH DX
MOV AH,09 INC CX
MOV DX,OFFSET PRODUCT OR AX,AX
INT 21H JNZ LOOP_2
POP AX JE PRINT
CALL WRITE_CHAR PRINT: POP DX
EXIT: MOV AH,4CH ADD DX,30H
INT 21H MOV AH,02H
CODE_SEG ENDS INT 21H
END START LOOP PRINT
;---------------------------------- RET
CR_LF PROC FAR WRITE_CHAR ENDP
PUSH AX ;----------------------------
PUSH DX Bài tập 7:
MOV AH,02 Tính tổng hai số nhập từ bàn phím
MOV DX,0AH CODE_SEG SEGMENT BYTE PUBLIC
INT 21H ASSUME CS:CODE_SEG,DS:CODE_SEG
MOV DX,0DH ORG 100H
INT 21H START: JMP FIRST
POP DX MSG DB 'NHAP VAO 2 SO DE CONG :$'
POP AX MSG1 DB 'SO THU NHAT :$'
RET MSG2 DB 'SO THU HAI :$'
CR-LF ENDP MSG3 DB 'TONG CUA CHUNG LA :$'
;----------------------------------- NUMBER1 DB 0
GET_IN_NUMBER PROC NUMBER2 DB 0
PUSH DX
NHAY: MOV AH,08 soam db ?
INT 21H dauso1 db ?
CMP AL,0DH dauso2 db ?
JE EXIT_1
CMP AL,30H FIRST: MOV AH,09H
JB NHAY MOV DX,OFFSET MSG
CMP AL,39H INT 21H
JA NHAY call cr_lf
MOV DL,AL MOV AH,09H
MOV AH,02 MOV DX,OFFSET MSG1
INT 21H INT 21H
EXIT_1: POP DX
MOV AX,4CH mov soam,0
INT 21H mov dauso1,0
RET CALL GET_AN_INT_NUM
GET_IN_NUMBER ENDP cmp soam,1
;------------------------------------ jne so1khongam
PRINT_CHAR PROC NEAR mov dauso1,1
PUSH DX so1khongam:
PUSH BX CMP AX,255
MOV TEMP,0 Jb tieptuclam
MOV CX,1 int 20h
LOOP_1: CALL GET_IN_NUMBER
CMP AL,0DH tieptuclam: MOV NUMBER1,AL
JE EXIT_2 CALL CR_LF
SUB AL,30H
MOV DX,AX MOV AH,09H
XOR AH,AH MOV DX,OFFSET MSG2
MOV AX,TEMP INT 21H
CMP CX,2
JB NONE_ZERO mov soam,0h
MOV BX,10 mov dauso2,0
MUL BX CALL GET_AN_INT_NUM
NONE_ZERO: cmp soam,1
ADD AX,DX jne so2khongam
MOV TEMP,AX mov dauso2,1
INC CX so2khongam:
CMP CX,2 CMP AX,255
JA EXIT_2 JA EXIT
JMP LOOP_1 MOV NUMBER2,AL
EXIT_2: MOV AX,TAM CALL CR_LF

7
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
LOOP_2: CALL GET_A_DEC_DIGIT
MOV AH,09 CMP AL,0DH
MOV DX,OFFSET MSG3 JE EXIT_2
INT 21H ;--------------------------------
cmp al,'-'
;---------------------------------------------------------------- jne tieptuc
mov cl,dauso1 mov soam,1h
add cl,dauso2 jmp loop_2
cmp cl,1 ;-------------------------------------------------------
tieptuc: SUB AL,30H
je khacdau ;HAI SO KHAC DAU XOR AH,AH
MOV DX,AX
XOR AX,AX MOV AX,TEMP_VAR
MOV BL,NUMBER1 CMP CX,1
ADD AL,BL JE SUM_UP
PUSH AX MOV BL,10
cmp dauso1,1 PUSH DX
jne khongam MUL BL
call indau POP DX
jmp khongam SUM_UP: ADD AX,DX
;------------------------------------------------------------------ MOV TEMP_VAR,AX
khacdau: mov cl,number1 INC CX
cmp cl,number2 ;SO1>SO2 ? CMP CX,3
je writeZero JA EXIT_2
ja laydauso1 JMP LOOP_2
;-------------------------------------------------------- EXIT_2: MOV AX,TEMP_VAR
XOR AX,AX POP DX
MOV BL,NUMBER1 POP CX
SUB AL,BL POP BX
PUSH AX RET
GET_AN_INT_NUM ENDP
cmp dauso2,1 ;----------------------------------------------
jne khongam ;
CALL INDAU ;----------------------------------------------
JMP KHONGAM GET_A_DEC_DIGIT PROC
LOOP_1:
laydauso1: XOR AX,AX PUSH DX
MOV AL,NUMBER1 MOV AH,08H
SUB AL,NUMBER2 INT 21H
PUSH AX CMP AL,0DH
cmp dauso1,1 JE EXIT_1
jne khongam ;------------------------
CALL INDAU CMP AL,'-'
JNE TIEP
khongam: JMP INSO
;------------------------
POP AX TIEP: CMP AL,30H
JB LOOP_1
CALL WRITE_INT_NUMBER CMP AL,39H
jmp exit JA LOOP_1
writezero: mov ax,0
call write_int_number
INSO: MOV DL,AL
EXIT: MOV AH,02
INT 20 INT 21H
;---------------------------------------------- EXIT_1: POP DX
RET
;---------------------------------------------- GET_A_DEC_DIGIT ENDP
indau proc ;-------------------------------------------
push ax ;
push dx ;-------------------------------------------
mov ah,02 WRITE_INT_NUMBER PROC NEAR
mov dl,'-' MOV BX,10
int 21h XOR CX,CX
pop dx NONE_ZERO:
pop ax XOR DX,DX
ret DIV BX
indau endp PUSH DX
;---------------------------------------------- INC CX
GET_AN_INT_NUM PROC OR AX,AX
JMP $+4 JNZ NONE_ZERO
TEMP_VAR DW 0 WRITE_DIGIT_LOOP:
PUSH BX POP DX
PUSH CX ADD DL,48 ;=30H='0'
PUSH DX MOV AH,02
XOR DX,DX INT 21H
MOV TEMP_VAR,0 LOOP WRITE_DIGIT_LOOP
MOV CX,1 RET
mov soam,0h WRITE_INT_NUMBER ENDP
;---------------------------------

8
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
; ret
;--------------------------------- HIENHEX ENDP
CR_LF PROC NEAR HIEN PROC
PUSH AX cmp al,10
PUSH DX jl H
MOV AH,02 add al,7
MOV DL,0DH H:
INT 21h add al,30h
MOV DL,0AH mov ah,0eh
INT 21H int 10h
POP DX ret
POP AX HIEN ENDP
RET code ends
CR_LF ENDP end ps
;--------------------------------- Bài tập 9:
CODE_SEG ENDS Hiển thị tên ổ đĩa và thời gian đọc đĩa
END START COMMENT *
Bài tập 8: PROGRAM DISKLITE
Chương Trình xác định số cổng COM và địa chỉ cổng COM chuong trinh se hien thi ten o dia va thoi gian doc dia
hien_string MACRO xau moi khi co truy nhap dia
push ax dx Sudung:
mov dx,offset xau DISKLITE -> chay chuong trinh
mov ah,9 DISKLITE /U -> unload disklite*
int 21h CODE SEGMENT
pop dx ax ASSUME CS:CODE,DS:CODE
ENDM ORG 100h
;--------------------------------- START:
_STACK SEGMENT STACK 'STACK' JMP INIT ;nhay toi thu tuc khoi tao
db 100h dup(?) MAGIC_CODE DB 'DISKLITE VERSION 1.0'
_STACK ENDS MAGIC_LEN LABEL BYTE
data segment NUM_IN EQU 11 ;so chu so de in
m1 db 'Khong co cong COM. $' DISPLAY_BASE DW 0B800h
m2 db 0ah,0dh,'So luong cong COM la: $' OLD_CHARS DB NUM_IN*2 DUP(?)
m3 db 0ah,0dh,'Dia chi cong COM1 la: $' DISPLAY_DRV DB 'A',70h,':',70h,' ',70h ;in ten o dia
data ends DISPLAY_TM DB '0',70h,'0',70h,':',70h,'0',70H,'0',70h,':',70h
code segment DB 2 DUP('0',70h)
assume cs:code,ds:data,ss:_STACK NUM_FLOPPIES DB ?
ps: SECOND DB 0
mov ax,data MINUTE DB 0
mov ds,ax HOUR DB 0
TICKER DB 0 ;so nhip dong ho
mov ax,40h D_DISK EQU (80-NUM_IN-1)*2 ;offset de ghi ten o dia
mov es,ax D_TIME EQU (82-NUM_IN)*2 ;offset ghi thoi gian
mov bx,11h ;dia chi byte trang thai moto o mem
mov al,es:[bx] MOTOSTATUS EQU 43Fh
and al,0eh ; lay 3 bit chua so luong cong COM (0 0 0 0 | x x x 0) ;dia chi cong dia cung
; 0 e HARDPORT EQU 1F7h
jnz l1 ;dia chi co dia cung
hien_string m1 HARDFLAGS EQU 48Ch ;(Neu flags and 8)=8 thi dang roi
jmp stop ;dia chi co IN_DOS
l1: DAPTR EQU THIS DWORD
hien_string m2 DAPTR_OFS DW ?
shr al,1 DAPTR_SEG DW ?
add al,30h ;cac thuc tuc ngat cu
mov ah,0eh OLDINT13_PTR EQU THIS DWORD
int 10h OLD_INT13 DW ? ;dia chi ngat 13H
hien_string m3 DW ?
mov bx,2 ; cong COM 2 OLDINT1C_PTR EQU THIS DWORD
mov ax,es:[bx] OLD_INT1C DW ? ;dia chi ngat 1C
push ax DW ?
mov al,ah INT13 PROC FAR
call HIENHEX ASSUME CS:CODE,DS:NOTHING
pop ax PUSHF ;luu thanh ghi co
call HIENHEX PUSH AX
stop: PUSH CX
mov ah,1 PUSH DX
int 21h PUSH SI
mov ah,4ch PUSH DI
int 21h PUSH DS
; chuong trinh con HIENHEX va trong CTC nay lai chua CTC HIEN PUSH ES
HIENHEX PROC CALL GET_DISPLAY_BASE ;tinh dia chi doan bo nho man hinh
push ax cx CALL SAVE_SCREEN ;Luu 11 ky tu
push ax CALL DISPLAY_DRIVE
mov cl,4 CALL DISPLAY_TIME
shr al,cl POP ES
call HIEN POP DS
pop ax POP DI
and al,0fh POP SI
call HIEN POP DX
pop cx ax POP CX

9
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
POP AX POP DX
POPF ;POP CX
PUSHF POP AX
CALL DWORD PTR CS:OLD_INT13 JMP DWORD PTR CS:OLD_INT1C
PUSHF INT1C ENDP
PUSH AX ;thu tuc get_display_base xac dinh doan bo nho man hinh
PUSH CX ; thay doi AX
PUSH SI GET_DISPLAY_BASE PROC NEAR
PUSH DI INT 11h ;lay co thiet bi
PUSH DS AND AX,30h
PUSH ES CMP AX,30h ;man hinh don sac
LEA SI,OLD_CHARS MOV AX,0B800h
MOV DI,D_DISK JNE GET_BASE
MOV CX,NUM_IN MOV AX,0B000h
CALL WRITE_S GET_BASE:
POP ES MOV DISPLAY_BASE,AX
POP DS RET
POP DI GET_DISPLAY_BASE ENDP
POP SI ;thu tuc savescreen luu manh hinh lai
POP CX ;thay doi AX,si,di,ds,es,cx
POP AX SAVE_SCREEN PROC NEAR
POPF MOV SI,D_DISK ;lay dia chi bo nho man hinh
RET 2 MOV DI,OFFSET OLD_CHARS
INT13 ENDP MOV AX,DISPLAY_BASE
INT1C PROC FAR MOV DS,AX ;ky tu man hinh nam tai DS:SI
ASSUME CS:CODE,DS:NOTHING MOV AX,CS
PUSH AX MOV ES,AX ;old_chars nam tai ES:DI
;PUSH CX MOV CX,NUM_IN
PUSH DX REP MOVSW
PUSH DI RET
;PUSH SI SAVE_SCREEN ENDP
PUSH DS ;thu tuc display_drive ghi ten o dia
;PUSH ES ;thay doi AX,SI,CX,DI
;LDS DI,[DAPTR] ;nap IN_DOS vao DS:DI DISPLAY_DRIVE PROC NEAR
;CMP BYTE PTR DI,0 ;co DOS co ban khong MOV AL,DL
XOR AX,AX CMP AL,80h ;co phai o cung khong
MOV DS,AX JB DISPLAY ;khong thi tiep tuc
MOV AL,BYTE PTR DS:[MOTOSTATUS] ;co o dia nao quay khong SUB AL,80h ;khong thi tru 80h
AND AL,3 ADD AL,NUM_FLOPPIES ;cong voi so o dia
CMP AL,0 DISPLAY:
JNE CONTINUE ;neu ban thi tiep tuc ADD AL,'A'
;MOV DX,HARDPORT ;cong dia cung chua byte so 7 la co bao LEA SI,DISPLAY_DRV
ban MOV CS:[SI],AL
;IN AL,DX ;kiem tra cong dia cung MOV CX,3
;SHR AL,7 ;kiem tra bit 7 MOV DI,D_DISK ;offset in ten dia
;CMP AL,1 ;neu ban CALL WRITE_S
MOV AL,BYTE PTR DS:[HARDFLAGS] ;kiem tra co dia cung RET
AND AL,8 DISPLAY_DRIVE ENDP
CMP AL,8 ;neu co=8 la roi ;thu tuc display_time in so gio
JNE CONTINUE ;khong thi tiep tuc ;thay doi AX,CX,SI,DX
XOR AL,AL DISPLAY_TIME PROC NEAR
MOV SECOND,AL LEA SI,DISPLAY_TM ;dia chi cua gio de in
MOV MINUTE,AL MOV DL,'0'
MOV HOUR,AL MOV CS:[SI],DL
MOV TICKER,AL MOV AL,HOUR
JMP NOT_INC XOR AH,AH
CONTINUE: CMP AX,10 ;gio co lon hon muoi khong
XOR DL,DL JB LESS_H
INC TICKER MOV CL,10
MOV AL,TICKER DIV CL ;ket qua trong AL,so du trong AH
CMP AL,18 ;so nhip 18.2 lan trong mot giay ADD AL,'0'
JB NOT_INC ;neu Chua bang thi in ra man hinh MOV CS:[SI],AL
MOV TICKER,DL ;neu qua thi dat lai ticker=0 MOV AL,AH ;lay so du trong AH
INC SECOND ;tang giay LESS_H:
MOV AL,SECOND INC SI
CMP AL,60 ;neu qua 60 giay thi tang phut INC SI
JB NOT_INC ADD AL,'0'
MOV SECOND,DL MOV CS:[SI],AL
INC MINUTE ;tang phut ADD SI,4 ;dat SI vao offset cua minute
MOV AL,MINUTE MOV CS:[SI],DL ;dat truoc hang chuc=0
CMP AL,60 MOV AL, MINUTE
JB NOT_INC XOR AH,AH
MOV MINUTE,DL CMP AX,10 ; phut co lon hon 10 khong
INC HOUR JB LESS_M
NOT_INC: MOV CL,10
;CALL DISPLAY_TIME ;thu DIV CL ;ket qua trong AL,so du trong AH
;POP ES ADD AL,'0'
POP DS MOV CS:[SI],AL
;POP SI MOV AL,AH ;lay so du trong AH
POP DI LESS_M:

10
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
INC SI POP ES ;tra lai ES
INC SI TIEP:
ADD AL,'0' CMP ES:[BX].IDCODE,LASTMCB ;da het MCB chua
MOV CS:[SI],AL JE NOT_INST
ADD SI,4 ;dat SI vao offset cua second MOV AX,ES ;khong thi
MOV CS:[SI],DL ADD AX,ES:[BX].SIZE ;cong ES voi SIZE+1 cua MCB
MOV AL,SECOND INC AX
XOR AH,AH MOV ES,AX ;ES:BX la MCB ke tiep
CMP AX,10 ; giay co lon hon 10 khong JMP FIND_CODE
JB LESS_S
MOV CL,10 NOT_INST: ;neu chua TSR thi khoi tao
DIV CL ;ket qua trong AL,so du trong AH CALL GET_NUM_DISK
ADD AL,'0'
MOV CS:[SI],AL ;xac dinh dia chi co in_dos
MOV AL,AH ;lay so du trong AH MOV AH,34h
LESS_S: INT 21h
INC SI MOV CS:DAPTR_OFS,BX ;offset cua co DOS
INC SI MOV CS:DAPTR_SEG,ES ;segment cua co DOS
ADD AL,'0'
MOV CS:[SI],AL ;giai phong khoi moi truong truoc khi TSR
LEA SI,DISPLAY_TM
MOV CX,NUM_IN-3 MOV ES,DX ;ES doan cua PSP cua chuong trinh se thuong tru
MOV DI, D_TIME XOR BX,BX ;ES:BX chua dia chi PSP
CALL WRITE_S MOV AX,ES:[BX].ENVSEG ;nap dia chi moi truong vao AX
RET MOV ES,AX
DISPLAY_TIME ENDP MOV AH,49h
;Thu tuc write_s in chuoi ra man hinh INT 21h
;thay doi AX,ES,DS ;lay int 13
WRITE_S PROC NEAR MOV AX,3513h
MOV AX,DISPLAY_BASE INT 21h
MOV ES,AX ;dia chi man hinh ES:DI MOV CS:OLD_INT13,BX
MOV AX,CS MOV CS:OLD_INT13[2],ES
MOV DS,AX ;dia chi display_tm tai DS:SI ;dat int 13
REP MOVSW MOV AX,2513h
RET PUSH CS
WRITE_S ENDP POP DS
;bat dau khoi tao MOV DX,OFFSET INT13
INIT: ;bat dau thuong tru INT 21h
OLDPSP DW ? ;lay int 1C
BLOCMCB EQU 'M' ; bao hieu chua het MCB MOV AX,351Ch
LASTMCB EQU 'Z' ; da het MCB INT 21h
MCB STRUC ;cau truc cua MCB MOV CS:OLD_INT1C,BX
IDCODE DB ? MOV CS:OLD_INT1C[2],ES
PSP DW ? ;dat int 1C
SIZE DW ? MOV AX,251Ch
MCB ENDS PUSH CS
POP DS
;kiem tra xem da resident chua MOV DX,OFFSET INT1C
MOV AH,51h INT 21h
INT 21h ;lay PSP cua chuong trinh,gia tri cho trong BX MOV DX,OFFSET INIT_TSR
MOV DX,BX ; giu gia tri vao DX CALL WRITE_MSG
;ket thuc va noi tru
;lay dia chi MCB dau MOV DX,OFFSET INIT
MOV AH,52h INT 27h
INT 21h ;ES:BX-2 tro toi dia chi cua MCB dau tien
SUB BX,2 YET_INST: ;da TSR roi thi kiem tra va ket thuc chuong trinh
MOV AX,ES:[BX] POP DI
MOV ES,AX POP ES
XOR BX,BX ;ES:BX la MCB dau MOV AX,ES:[BX].PSP
MOV DI,OFFSET MAGIC_CODE ;ES:DI se chua Magic_code MOV OLDPSP,AX ;nap PSP cua TSR vao OLDPSP
neu da thuong tru CALL READPARAM
FIND_CODE: ;Tim xem da thuong tru chua INT 20h
CMP DX,ES:[BX].PSP ;xem PSP(MCB) co bang PSP(PROG)
JE TIEP ;co thi nhay sang MCB khac GET_NUM_DISK PROC NEAR
MOV AX,DS ;dia chi cua chuong trinh thuong tru PUSH AX
SUB AX,DX PUSH CX
ADD AX,ES:[BX].PSP ;addr=PSP(MCB)+(segment(PROG)- INT 11h
PSP(PROG)) MOV CL,6
PUSH ES ;cat ES SHR AX,CL
MOV ES,AX ;ES se chua doan chuong trinh thuong tru AND AL,3
neu da resident INC AL
PUSH DI ;cat DI CMP AL,1 ;neu la 1 o dia
MOV SI,DI ;DS:SI se chua magic_code cua chuong JA GET_F ;thi ket thuc
trinh MOV AL,2 ;co hai o
MOV CX,OFFSET MAGIC_LEN-OFFSET MAGIC_CODE ;tinh GET_F:
chieu dai chuoi MOV NUM_FLOPPIES,AL
REPE CMPSB ;kiem tra xem hai chuoi co bang nhau POP CX
JCXZ YET_INST ;da co thuong tru ,ket thuc chuong POP AX
trinh RET
POP DI ;tra lai DI GET_NUM_DISK ENDP

11
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
MOV AH,9
INT 21h
READPARAM PROC NEAR POP AX
MOV SI,80h ;Dia chi duoi dong lenh RET
MOV CL,[SI] ;so do chieu dai duoi lenh WRITE_MSG ENDP
JCXZ NO_PARAM ;neu khong co thi bao loi va ket thuc ;khai bao cac chuoi de thong bao
READ_PARAM: ;khong thi lap voi CX=so tham so INIT_TSR DB 'DISKLITE VERSION 1.0',13,10
INC SI ;tham so dau tien DB ' COPYRIGHT (C) LE ANH TUAN 1994$'
MOV BL,[SI] YET_TSR DB 'CHUONG TRINH DA THUONG TRU$'
CMP BL,' ' WRONG_PARAM DB 'SAI THAM SO$'
JE CON_READ ;neu la ky tu trang thi doc tiep SUCCESS DB 'CHUONG TRINH DA DUOC UNLOAD$'
CMP BL,'/' ;co dung lenh khong UN_SUCCESS DB 'KHONG THE UNLOAD DUOC CHUONG TRINH$'
JZ CON_READ ;dung thi tiep tuc CODE ENDS
CMP BL,'U' ;lenh vao la /U thi unload TSR END START
JZ REMOVE ;dung thi loai TSR ra khoi bo nho Bài tập 10:
CMP BL,'u' Chương trình sửa bad track 0 của đĩa mềm
JNZ W_PARAM .model tiny
REMOVE: .code
CALL UNLOAD ;dung thi unload TSR org 100h
RET start:
CON_READ: jmp INIT
LOOP READ_PARAM Oldint13h label dword
NO_PARAM: Int13hofs dw ?
MOV DX,OFFSET YET_TSR Int13hseg dw ?
CALL WRITE_MSG ;khong co tham so thi in thong bao Make db 1
RET
W_PARAM: NEWINT13H:
MOV DX,OFFSET WRONG_PARAM push es ds si di ax
CALL WRITE_MSG push cs cs
RET pop ds es
READPARAM ENDP cmp ax,0FEFEh
je ALREADY
UNLOAD PROC NEAR ;thu tuc de loai TSR ra khoi bo nho lea di,Make
PREFIX STRUC ;cau truc cua PSP cmp ax,0BABAh
DUMMY DB 2Ch DUP(?) je EQUAL0
ENVSEG DW ? ;dia chi cua moi truong cmp ax,0ABABh
PREFIX ENDS je EQUAL1
;lay dia chi cua khoi moi truong jmp CONTINUE
MOV DX,OLDPSP ;nap OLDPSP vao DX
MOV AX,351Ch ;kiem tra xem ALREADY:
INT 21h ;ngat 1CH co bi thay doi khong pop ax di si ds es
MOV AX,ES ;AX chua dia chi cua ngat 1CH mov ax,0EFEFh
CMP AX,DX iret
JNE CHANGED ;neu khong bang thi ket thuc EQUAL0:
xor al,al
MOV AX,3513h ;kiem tra xem stosb
INT 21h ;ngat 13H co bi thay doi khong pop ax di si ds es
MOV AX,ES ;AX chua dia chi cua ngat 13H iret
CMP AX,DX EQUAL1:
JNE CHANGED ;neu khong bang thi ket thuc mov al,1
BEGIN_UNLOAD: ;neu khong thay doi thi loai TSR stosb
;giai phong bo nho ,luc nay ES da chua segment PSP cua TSR pop ax di si ds es
;PUSH ES iret
MOV AH,49h
;POP ES ;ES la dia chi doan cua TSR CONTINUE:
INT 21h lea si, Make
;dat lai ngat cu lodsb
PUSH DS ;cat DS cmp al,0
CLI pop ax di si ds es
MOV AX,2513h ;dat lai ngat 13 je PASSBY
LDS DX,ES:OLDINT13_PTR cmp ah,2
INT 21h je READ
cmp ah,3
MOV AX,251Ch ;dat lai ngat 1c je READ
LDS DX,ES:OLDINT1C_PTR PASSBY:
INT 21h jmp cs:Oldint13h

STI READ:
POP DS ;tra lai DS cu cmp dl,0
MOV DX,OFFSET SUCCESS ;da loai ra khoi bo nho je GOON
CALL WRITE_MSG cmp dl,1
RET jne PASSBY
CHANGED: ;vec to ngat da bi doi GOON:
MOV DX,OFFSET UN_SUCCESS cmp ch,0
CALL WRITE_MSG je TRACK0
RET cmp ch,79
UNLOAD ENDP je TRACK79
jmp PASSBY
WRITE_MSG PROC NEAR
PUSH AX TRACK0:

12
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
add ch,79
jmp PASSBY

TRACK79:
cmp ah,3
jne COMEBACK
mov ah,1
stc
COMEBACK:
Iret

INIT:
mov si,80h
lodsb
push ax
mov ax,0FEFEh
int 13h
cmp ax,0EFEFh
pop ax
jne INSTALL
cmp al,1
jbe CHANGETRACK
mov si,82h
lodsw
cmp ax,0752Fh
je NORMAL
cmp ax,0552Fh
je NORMAL
lea dx,Error
call WRITE
ret
CHANGETRACK:
mov ax,0ABABh
int 13h
lea dx,Mess2
call WRITE
ret
NORMAL:
mov ax,0BABAh
int 13h
lea dx,Mess1
call WRITE
ret

INSTALL:
mov ax,3513h
int 21h
mov int13hofs,bx
mov int13hseg,es
lea dx,newint13h
mov ax,2513h
int 21h
lea dx,Mess
call WRITE
lea dx,Mess2
Call WRITE
lea dx,INIT
int 27h

WRITE:
mov ah,9
int 21h
ret

Mess db 'Program repares bad track0 disk.',13,10,'Written by Hoang


Tuan Dat.',13,10,'Finish install.',13,10,'$'
Mess1 db 13,10,'Now you can not read bad track0 disk',13,10,'$'
Mess2 db 13,10,'Now you only can read bad track0 disk',13,10,'$'
Error db 'Input valid',13,10,'$'
end Start

13

You might also like