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

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

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

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

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

5
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
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
je exit1 CR_LF:PROC,PRINT_CHAR:PROC,GET_IN_NUMBER:PROC,WRITE_
cmp al,30h CHAR:PROC
jb sta ;----------------------------------
cmp al,39h DATA_SEG SEGMENT PUBLIC
ja sta DATA_1 DB 'ENTER TWO STRING:$'
mov dl,al DATA_2 DB 'NUMBER1:$'
; xor ah,ah DATA_3 DB 'NUMBER2:$'
PRODUCT DB 'PRODUCT IS:$'
mov ah,02h TEMP_VAR DW 0
int 21h TEMP DW 0
exit1: NUMBER DW 0
pop dx DATA_SEG ENDS
ret ;-------------------------------
nhap endp STACK SEGMENT STACK
;---------------------------- DB 64 DUP('STACK')
code ends STACK ENDS
end start ;------------------------------
Bài tập 5: CODE_SEG SEGMENT PUBLIC
Tìm số nguyên tố nhỏ hơn hoặc bằng số giới hạn cho ASSUME CS:CODE_SEG,DS:DATA_SEG,SS:STACK
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 MOV DX,OFFSET DATA_2
tu 2 den $’ INT 21H
M3 db ‘la: $’ CALL PRINT_CHAR
M4 db 0ah,0dh,’ Co tiep tuc CMP AX,99
khong (c/k) ?: $’ JA EXIT
So dw dw MOV TEMP_VAR,AX
DATA ends CALL CR_LF
CODE segment MOV AH,09 ; so thu 2
Assume CS:CODE, DS:DATA, SS:_STACK MOV DX,OFFSET DATA_3
PS: INT 21H
Mov AX,DATA CALL PRINT_CHAR

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

7
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
PUSH AX POP DX
cmp dauso1,1 SUM_UP: ADD AX,DX
jne khongam MOV TEMP_VAR,AX
call indau INC CX
jmp khongam CMP CX,3
;------------------------------------------------------------------ JA EXIT_2
khacdau: mov cl,number1 JMP LOOP_2
cmp cl,number2 ;SO1>SO2 ? EXIT_2: MOV AX,TEMP_VAR
je writeZero POP DX
ja laydauso1 POP CX
;-------------------------------------------------------- POP BX
XOR AX,AX RET
MOV BL,NUMBER1 GET_AN_INT_NUM ENDP
SUB AL,BL ;----------------------------------------------
PUSH AX ;
;----------------------------------------------
cmp dauso2,1 GET_A_DEC_DIGIT PROC
jne khongam LOOP_1:
CALL INDAU PUSH DX
JMP KHONGAM MOV AH,08H
INT 21H
laydauso1: XOR AX,AX CMP AL,0DH
MOV AL,NUMBER1 JE EXIT_1
SUB AL,NUMBER2 ;------------------------
PUSH AX CMP AL,'-'
cmp dauso1,1 JNE TIEP
jne khongam JMP INSO
CALL INDAU ;------------------------
TIEP: CMP AL,30H
khongam: JB LOOP_1
CMP AL,39H
POP AX JA LOOP_1

CALL WRITE_INT_NUMBER
jmp exit INSO: MOV DL,AL
writezero: mov ax,0 MOV AH,02
call write_int_number INT 21H
EXIT_1: POP DX
EXIT: RET
INT 20 GET_A_DEC_DIGIT ENDP
;---------------------------------------------- ;-------------------------------------------
;
;---------------------------------------------- ;-------------------------------------------
indau proc WRITE_INT_NUMBER PROC NEAR
push ax MOV BX,10
push dx XOR CX,CX
mov ah,02 NONE_ZERO:
mov dl,'-' XOR DX,DX
int 21h DIV BX
pop dx PUSH DX
pop ax INC CX
ret OR AX,AX
indau endp JNZ NONE_ZERO
;---------------------------------------------- WRITE_DIGIT_LOOP:
GET_AN_INT_NUM PROC POP DX
JMP $+4 ADD DL,48 ;=30H='0'
TEMP_VAR DW 0 MOV AH,02
PUSH BX INT 21H
PUSH CX LOOP WRITE_DIGIT_LOOP
PUSH DX RET
XOR DX,DX WRITE_INT_NUMBER ENDP
MOV TEMP_VAR,0 ;---------------------------------
MOV CX,1 ;
mov soam,0h ;---------------------------------
CR_LF PROC NEAR
LOOP_2: CALL GET_A_DEC_DIGIT PUSH AX
CMP AL,0DH PUSH DX
JE EXIT_2 MOV AH,02
;-------------------------------- MOV DL,0DH
cmp al,'-' INT 21h
jne tieptuc MOV DL,0AH
mov soam,1h INT 21H
jmp loop_2 POP DX
;------------------------------------------------------- POP AX
tieptuc: SUB AL,30H RET
XOR AH,AH CR_LF ENDP
MOV DX,AX ;---------------------------------
MOV AX,TEMP_VAR CODE_SEG ENDS
CMP CX,1 END START
JE SUM_UP Bài tập 8:
MOV BL,10 Chương Trình xác định số cổng COM và địa chỉ cổng
PUSH DX COM
MUL BL hien_string MACRO xau

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

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

10
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
;thay doi AX,ES,DS MOV AH,49h
WRITE_S PROC NEAR INT 21h
MOV AX,DISPLAY_BASE ;lay int 13
MOV ES,AX ;dia chi man hinh ES:DI MOV AX,3513h
MOV AX,CS INT 21h
MOV DS,AX ;dia chi display_tm tai DS:SI MOV CS:OLD_INT13,BX
REP MOVSW MOV CS:OLD_INT13[2],ES
RET ;dat int 13
WRITE_S ENDP MOV AX,2513h
;bat dau khoi tao PUSH CS
INIT: ;bat dau thuong tru POP DS
OLDPSP DW ? MOV DX,OFFSET INT13
BLOCMCB EQU 'M' ; bao hieu chua het MCB INT 21h
LASTMCB EQU 'Z' ; da het MCB ;lay int 1C
MCB STRUC ;cau truc cua MCB MOV AX,351Ch
IDCODE DB ? INT 21h
PSP DW ? MOV CS:OLD_INT1C,BX
SIZE DW ? MOV CS:OLD_INT1C[2],ES
MCB ENDS ;dat int 1C
MOV AX,251Ch
;kiem tra xem da resident chua PUSH CS
MOV AH,51h POP DS
INT 21h ;lay PSP cua chuong trinh,gia tri cho trong MOV DX,OFFSET INT1C
BX INT 21h
MOV DX,BX ; giu gia tri vao DX MOV DX,OFFSET INIT_TSR
CALL WRITE_MSG
;lay dia chi MCB dau ;ket thuc va noi tru
MOV AH,52h MOV DX,OFFSET INIT
INT 21h ;ES:BX-2 tro toi dia chi cua MCB dau tien INT 27h
SUB BX,2
MOV AX,ES:[BX] YET_INST: ;da TSR roi thi kiem tra va ket thuc chuong trinh
MOV ES,AX POP DI
XOR BX,BX ;ES:BX la MCB dau POP ES
MOV DI,OFFSET MAGIC_CODE ;ES:DI se chua MOV AX,ES:[BX].PSP
Magic_code neu da thuong tru MOV OLDPSP,AX ;nap PSP cua TSR vao OLDPSP
FIND_CODE: ;Tim xem da thuong tru chua CALL READPARAM
CMP DX,ES:[BX].PSP ;xem PSP(MCB) co bang INT 20h
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)+ INT 11h
(segment(PROG)-PSP(PROG)) MOV CL,6
PUSH ES ;cat ES SHR AX,CL
MOV ES,AX ;ES se chua doan chuong trinh thuong AND AL,3
tru 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 JA GET_F ;thi ket thuc
chuong trinh MOV AL,2 ;co hai o
MOV CX,OFFSET MAGIC_LEN-OFFSET MAGIC_CODE GET_F:
;tinh chieu dai chuoi MOV NUM_FLOPPIES,AL
REPE CMPSB ;kiem tra xem hai chuoi co bang POP CX
nhau POP AX
JCXZ YET_INST ;da co thuong tru ,ket thuc RET
chuong trinh GET_NUM_DISK ENDP
POP DI ;tra lai DI
POP ES ;tra lai ES
TIEP: READPARAM PROC NEAR
CMP ES:[BX].IDCODE,LASTMCB ;da het MCB chua MOV SI,80h ;Dia chi duoi dong lenh
JE NOT_INST MOV CL,[SI] ;so do chieu dai duoi lenh
MOV AX,ES ;khong thi JCXZ NO_PARAM ;neu khong co thi bao loi va ket
ADD AX,ES:[BX].SIZE ;cong ES voi SIZE+1 cua MCB thuc
INC AX READ_PARAM: ;khong thi lap voi CX=so tham so
MOV ES,AX ;ES:BX la MCB ke tiep INC SI ;tham so dau tien
JMP FIND_CODE MOV BL,[SI]
CMP BL,' '
NOT_INST: ;neu chua TSR thi khoi tao JE CON_READ ;neu la ky tu trang thi doc tiep
CALL GET_NUM_DISK CMP BL,'/' ;co dung lenh khong
JZ CON_READ ;dung thi tiep tuc
;xac dinh dia chi co in_dos CMP BL,'U' ;lenh vao la /U thi unload TSR
MOV AH,34h JZ REMOVE ;dung thi loai TSR ra khoi bo nho
INT 21h CMP BL,'u'
MOV CS:DAPTR_OFS,BX ;offset cua co DOS JNZ W_PARAM
MOV CS:DAPTR_SEG,ES ;segment cua co DOS REMOVE:
CALL UNLOAD ;dung thi unload TSR
;giai phong khoi moi truong truoc khi TSR RET
CON_READ:
MOV ES,DX ;ES doan cua PSP cua chuong trinh se LOOP READ_PARAM
thuong tru NO_PARAM:
XOR BX,BX ;ES:BX chua dia chi PSP MOV DX,OFFSET YET_TSR
MOV AX,ES:[BX].ENVSEG ;nap dia chi moi truong vao CALL WRITE_MSG ;khong co tham so thi in thong
AX bao
MOV ES,AX RET

11
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
W_PARAM: push es ds si di ax
MOV DX,OFFSET WRONG_PARAM push cs cs
CALL WRITE_MSG pop ds es
RET cmp ax,0FEFEh
READPARAM ENDP je ALREADY
lea di,Make
UNLOAD PROC NEAR ;thu tuc de loai TSR ra khoi bo nho cmp ax,0BABAh
PREFIX STRUC ;cau truc cua PSP je EQUAL0
DUMMY DB 2Ch DUP(?) cmp ax,0ABABh
ENVSEG DW ? ;dia chi cua moi truong je EQUAL1
PREFIX ENDS jmp CONTINUE
;lay dia chi cua khoi moi truong
MOV DX,OLDPSP ;nap OLDPSP vao DX ALREADY:
MOV AX,351Ch ;kiem tra xem pop ax di si ds es
INT 21h ;ngat 1CH co bi thay doi khong mov ax,0EFEFh
MOV AX,ES ;AX chua dia chi cua ngat 1CH iret
CMP AX,DX EQUAL0:
JNE CHANGED ;neu khong bang thi ket thuc xor al,al
stosb
MOV AX,3513h ;kiem tra xem pop ax di si ds es
INT 21h ;ngat 13H co bi thay doi khong iret
MOV AX,ES ;AX chua dia chi cua ngat 13H EQUAL1:
CMP AX,DX mov al,1
JNE CHANGED ;neu khong bang thi ket thuc stosb
BEGIN_UNLOAD: ;neu khong thay doi thi loai TSR pop ax di si ds es
;giai phong bo nho ,luc nay ES da chua segment PSP cua iret
TSR
;PUSH ES CONTINUE:
MOV AH,49h lea si, Make
;POP ES ;ES la dia chi doan cua TSR lodsb
INT 21h cmp al,0
;dat lai ngat cu pop ax di si ds es
PUSH DS ;cat DS je PASSBY
CLI cmp ah,2
MOV AX,2513h ;dat lai ngat 13 je READ
LDS DX,ES:OLDINT13_PTR cmp ah,3
INT 21h je READ
PASSBY:
MOV AX,251Ch ;dat lai ngat 1c jmp cs:Oldint13h
LDS DX,ES:OLDINT1C_PTR
INT 21h READ:
cmp dl,0
STI je GOON
POP DS ;tra lai DS cu cmp dl,1
MOV DX,OFFSET SUCCESS ;da loai ra khoi bo nho jne PASSBY
CALL WRITE_MSG GOON:
RET cmp ch,0
CHANGED: ;vec to ngat da bi doi je TRACK0
MOV DX,OFFSET UN_SUCCESS cmp ch,79
CALL WRITE_MSG je TRACK79
RET jmp PASSBY
UNLOAD ENDP
TRACK0:
WRITE_MSG PROC NEAR add ch,79
PUSH AX jmp PASSBY
MOV AH,9
INT 21h TRACK79:
POP AX cmp ah,3
RET jne COMEBACK
WRITE_MSG ENDP mov ah,1
;khai bao cac chuoi de thong bao stc
INIT_TSR DB 'DISKLITE VERSION 1.0',13,10 COMEBACK:
DB ' COPYRIGHT (C) LE ANH TUAN 1994$' Iret
YET_TSR DB 'CHUONG TRINH DA THUONG TRU$'
WRONG_PARAM DB 'SAI THAM SO$' INIT:
SUCCESS DB 'CHUONG TRINH DA DUOC UNLOAD$' mov si,80h
UN_SUCCESS DB 'KHONG THE UNLOAD DUOC CHUONG lodsb
TRINH$' push ax
CODE ENDS mov ax,0FEFEh
END START int 13h
Bài tập 10: cmp ax,0EFEFh
Chương trình sửa bad track 0 của đĩa mềm pop ax
.model tiny jne INSTALL
.code cmp al,1
org 100h jbe CHANGETRACK
start: mov si,82h
jmp INIT lodsw
Oldint13h label dword cmp ax,0752Fh
Int13hofs dw ? je NORMAL
Int13hseg dw ? cmp ax,0552Fh
Make db 1 je NORMAL
lea dx,Error
NEWINT13H: call WRITE

12
ĐHQG – HN CNTT Ngôn ngữ máy ASSEMBLY
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