1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Kỹ thuật vi xử lý - Chương 3 pot

19 393 2

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 19
Dung lượng 445,17 KB

Nội dung

Có thể sử dụng chương trình dịch hợp ngữ MASM 5.10 Macro Assembler phiên bản 5.10 của Microsoft với các định nghĩa đoạn đơn giản và chế độ bộ nhớ nhỏ.. Ngôn ngữ assembly hợp ngữ Các chươ

Trang 1

Chương 3 Lập trình bằng hợp ngữ cho 8088 trên máy tính IBM PC và các máy tương thích IBM PC

1 Giới thiệu chung

Sau khi đã giới thiệu một số lệnh cơ bản của bộ vi xử lý 8088  ta sẽ dùng các lệnh

đó để lập trình dùng hợp ngữ trên các máy tính IBM PC (hoặc các máy tương thích máy IBM PC) Vì loại máy tính này có cấu trúc tiêu biểu của một hệ vi xử lý, hơn nữa ta cũng có thể sử dụng nhiều chức năng sẵn có cho chương trình thông qua các dịch vụ (các chương trình con phục vụ ngắt) của các ngắt của DOS và của BIOS Có thể sử dụng chương trình dịch hợp ngữ MASM 5.10 (Macro Assembler phiên bản 5.10) của Microsoft với các định nghĩa đoạn đơn giản và chế độ bộ nhớ nhỏ Ngoài ra ta cũng có thể sử dụng chương trình dịch hợp ngữ TASM 2.0 (Turbo Assembler phiên bản 2.0) của Borland International để thực hiện dịch chương trình của chúng ta

Ngôn ngữ assembly (hợp ngữ)

Các chương trình thực hiện chuyển đổi chương trình của người sử dụng được viết bằng một ngôn ngữ nào đó sang một ngôn ngữ khác được gọi là chương trình dịch (translate) Ngôn ngữ được sử dụng để viết chương trình nguồn được gọi là ngôn ngữ nguồn còn ngôn ngữ của chương trình mà do chương trình nguồn chuyển sang được gọi là ngôn ngữ đích

Người ta đã phân chương trình dịch làm 2 loại dựa trên mối quan hệ giữa ngôn ngữ nguồn và ngôn ngữ đích như sau:

- Khi ngôn ngữ nguồn về căn bản là một sự biểu diễn bằng ký hiệu cho một ngôn ngữ máy bằng số thì chương trình dịch được gọi là assembler và ngôn ngữ nguồn

được gọi là ngôn ngữ assembly (hợp ngữ)

- Khi ngôn ngữ nguồn là một ngôn ngữ bậc cao như Pascal, C, và ngôn ngữ

đích là ngôn ngữ máy hoặc là một biểu diễn bằng ký hiệu cho một ngôn ngữ như vậy thì chương trình dịch được gọi là compiler

Ngôn ngữ assembly thuần khiết là ngôn ngữ mà trong đó mỗi lệnh (chỉ thị) của nó khi

được dịch sinh ra đúng một chỉ thị máy, điều đó có nghĩa là có sự tương ứng 1 - 1 giữa các lệnh máy và các lệnh trong ngôn ngữ assembly Nếu mỗi dòng trong chương trình assembly chứa một chỉ thị assmebly và mỗi word trong bộ nhớ chứa một lệnh máy thì chương trình dài n dòng sẽ sinh ra một chương trình ngôn ngữ máy dài n word

Sử dụng ngôn ngữ assmebly để lập trình dễ hơn sử dụng ngôn ngữ máy (dạng số, là dãy các bit) rất nhiều Việc sử dụng tên và địa chỉ bằng ký hiệu thay cho số nhị phân (hoặc

hệ 8, 10, 16) tạo nên sự khác biệt lớn Mọi người dễ dàng có thể nhớ được các ký hiệu (symbol) viết tắt cho lệnh cộng (add), trừ (substract), nhân (multiply) và chia (divide) là ADD, SUB, MUL, DIV nhưng ít ai có thể nhớ được các lệnh máy cho các phép toán đó dưới dạng số, ví dụ là: 24576, 57344, 28672 và 29184 (trừ khi làm việc quá nhiều với chúng mà

tự nhiên nhớ được) Người lập trình bằng ngôn ngữ assembly chỉ cần nhớ các tên bằng ký hiệu gợi nhớ ADD, SUB, MUL, DIV, vì chúng sẽ được assembler dịch ra các lệnh máy Tuy nhiên nếu ai muốn lập trình bằng ngôn ngữ máy thì họ cần phải nhớ mã lệnh dưới dạng số (hoặc liên tục tra cứu)

Đối với địa chỉ, cũng rút ra các nhận xét tương tự Người lập trình bằng ngôn ngữ asembly có thể đặt tên bằng ký hiệu gợi nhớ cho các ô nhớ và giao cho assembly phải

Trang 2

cung cấp đúng địa chỉ bằng số, trong khi đó người lập trình bằng ngôn ngữ máy luôn luôn phải làm việc với các giá trị bằng số của các địa chỉ

Vì vậy mà từ khi có ngôn ngữ assembly ra đời cho đến nay, không còn ai viết chương trình bằng ngôn ngữ máy nữa

Ngoài sự tương ứng (ánh xạ) 1 - 1 của các lệnh assembly vào các lệnh máy, ngôn ngữ assembly còn có một tính chất khác nữa làm cho nó khác hẳn các ngôn ngữ lập trình bậc cao, đó là người lập trình bằng ngôn ngữ assembly có thể truy cập tới tất cả các đặc

điểm trong máy tính vật lý Ví dụ, nếu có một bit báo tràn số (Overflow bit) thì chương trình bằng ngôn ngữ assembly có thể truy cập và kiểm tra trực tiếp bit này, trong khi đó chương trình bằng ngôn ngữ bậc cao (Pascal, C ) không thể làm được việc đó

Một sự khác biệt lớn và quan trong nữa giữa chương trình assembly và chương trình bằng ngôn ngữ bậc cao là chương trình bằng ngôn ngữ assembly chỉ có thể chạy được trên một họ máy, trong khi đó chương trình được viết bằng ngôn ngữ bậc cao nói chung có thể chạy được trên nhiều họ máy, đây chính là một ưu điểm lớn của ngôn ngữ bậc cao so với ngôn ngữ assembly

Nói chung, tất cả các việc có thể thực hiện được bằng ngôn ngữ máy đều có thể thực hiện được bằng ngôn ngữ assembly, tuy nhiên ngôn ngữ bậc cao không làm được như vậy một cách hiệu quả

Khi xây dựng các ứng dụng lớn, thông thường người ta chọn ngôn ngữ bậc cao vì nó hướng tới thuật toán giải quyết vấn đề (Ngôn ngữ hướng bài toán - problem-oriented language) mà không chọn ngôn ngữ assembly vì khi đó người lập trình phải chú ý tới các chi tiết nhỏ nhặt khi lập trình Ngược lại, khi xây dựng các chương trình nhỏ thực hiện các thao tác can thiệp sâu vào phần cứng máy tính thì người ta thường chọn ngôn ngữ assembly vì tính tối ưu, hiệu quả và khả năng mạnh mẽ của nó

2 Giới thiệu khung chương trình

Với bất kỳ ngôn ngữ nào, khi ta lập trình bằng ngôn ngữ đó ta cũng phải tuân thủ chương trình viết đúng cú pháp, quy định khung chương trình Từ đó chương trình mới được dịch ra mã máy, rồi mới tạo ra các chương trình chạy được (phần mở rộng: *.EXE hoặc

*.COM)

Một chương trình hợp ngữ bao gồm các dòng lệnh, mỗi lệnh được viết trên một dòng

- Một dòng lệnh có thể là lệnh thật dưới dạng gợi nhớ (nmenomic) hay dạng ký hiệu (symbolic) của bộ vi xử lý

- Hoặc hướng dẫn chương trình dịch (Essembler directive)

Lệnh thật dưới dạng gợi nhớ sẽ được dịch ra mã máy còn hướng dẫn chương trình dịch thì không, nó chỉ có tác dụng chỉ dẫn cho chương trình dịch thực hiện công việc trong quá trình dịch

Lệnh có thể được viết dưới dạng chữ hoa hay chữ thường đều được, chúng được cho

là tương đương vì đối với các dòng lệnh, chương trình dịch không phân biệt kiểu chữ

a Cấu trúc của một lệnh hợp ngữ

Một dòng lệnh của chương trình hợp ngữ (assembly) có cấu trúc như sau:

Tên (Nhãn) Mã lệnh Các toán hạng Giải thích

Trang 3

Ví du:

+ LAP: Mov CL, AH ;Số lần lặp được đặt trong thanh ghi CL

CL, AH là các toán hạng

Và trường giải thích bắt đầu bằng dấu chấm phẩy (;) + Main Proc

Main là tên Proc là mã của lệnh giả () hay hướng dẫn chương trình dịch

(dùng để bắt đầu chương trình hoặc bắt đầu chương trình con)

Một lệnh không nhất thiết phải có đầy đủ các trường như trên Tuỳ từng công việc cụ thể mà lệnh có thể khuyết một hoặc một số trường nào đó

 Trường tên (Nhãn)

Trường này chứa nhãn, tên biến, tên hằng hoặc tên thủ tục của chương trình Tên và nhãn sẽ được chương trình dịch gán bằng các địa chỉ cụ thể của ô nhớ

Quy tắc đặt tên (cũng khá giống như quy tắc đặt tên trong ngôn ngữ Pascal)

- Dùng các ký tự thuộc bộ chữ cái (không phân biệt chữ hoa, chữ thường)

- Không được bắt đầu bằng chữ số, không được chứa dấu cách

- Độ dài: 1 21 ký tự

- Có thể sử dụng các ký tự đặc biệt như: ?, , _, @, $, %

- Trong trường hợp nếu dùng dấu chấm (.), thì nó phải được đặt ở vị trí đầu tiên của tên hoặc nhãn

- Nhãn thường kết thúc bằng dấu hai chấm (;)

 Trường mã lệnh

Trường này gồm mã các lệnh thật hoặc giả (hướng dẫn chương trình dịch)

- Lệnh thật: lệnh dạng gợi nhớ (nmemonic) của bộ vi xử lý Lệnh này sẽ được chương trình dịch dịch ra mã máy

- Hướng dẫn chương trình dịch thì không được dịch

 Trường các toán hạng

Trường này là dữ liệu cho các thao tác

Tuỳ từng lệnh cụ thể mà có thể có 2, 1 hoặc không có toán hạng nào

Ví dụ:

Mov al, al ;Lệnh này có 2 toán hạng

Rol bx, cl ;Lệnh này có 2 toán hạng

Not bl ;Lệnh này có 1 toán hạng

Ret n ;Lệnh này có 1 toán hạng

Ret ;Lệnh này không có toán hạng nào

Sti ;Lệnh này không có toán hạng nào

Nop ;Lệnh này không có toán hạng nào

Với hướng dẫn chương trình dịch, trường này chứa các thông tin khác nhau liên quan đến các lệnh giả của hương dẫn

Trang 4

 Trường giải thích

Trường này được bắt đầu bằng dấu chầm phẩy (;), sau đó là dòng giải thich Chương trình dịch sẽ bỏ qua không dịch trường này

Lệnh tuy được viết dưới dạng gợi nhớ của bộ vi xử lí, tuy nhiên chúng ta luôn nên có trường này Lời giải thích cần sát nghĩa của công việc thực hiện (không nên giải thích ý nghĩa của câu lệnh)

b Dữ liệu cho chương trình hợp ngữ

Dữ liệu cho (của) một chương trình hợp ngữ có thể ở dạng hệ 2, hệ 10, hệ 16 hoặc dạng ký tự Đối với chương trình Debug (dùng để tìm lỗi cho các chương trình hợp ngữ) thì dữ liệu bằng số đưọc ngầm định ở dạng hệ 16 Còn đối với assembly thì dữ liệu bằng số được ngầm định ở hệ 10 Khi cung cấp dữ liệu cho chương trình, số cho ở hệ nào thì phải kèm hậu tố của hệ đó (trừ hệ 10 - ngầm định) Riêng đối với hệ

16, nếu số bắt đầu bằng chữ cái (a f hoặc A F) thì phải thêm số 0 ở trước để chương trình dịch không nhầm với một tên hoặc nhãn nào đó (B-Binary: Hệ 2; D-Decimal: Hệ 10; H-Hexa: Hệ 16)

Ví dụ:

1001b ;số ở hệ 2

100 ;số ở hệ 10

0ah ;số ở hệ 16

Nếu dữ liệu cho dưới dạng ký tự thì phải bao đóng (đặt) ký tự trong cặp dấu nháy đơn

Ví dụ:

'a' ;Ký tự a

'abcd' ;Chuỗi ký tự

Với kiểu ký tự, ngoài cách trên ta còn có thể dùng mã ASCII của ksy tự đó

Ví dụ:

'0' ;Ký tự 0

30h ;Mã ASCII của ký tự 0

Với 2 cách viết trong ví dụ trên là như nhau đối với chương trình dịch assembler

c Biến và hằng

Một biến bất kỳ được sử dụng trong chương trình hợp ngữ phải được định nghĩa, chương trình dịch sẽ gán cho biến đó một địa chỉ xác định trong bộ nhớ

 Biến đơn

Một biến đơn trong chương trình hợp ngữ được định nghĩa theo mẫu sau:

Tên_biến Kiểu Giá trị khởi tạo

Tên: do người sử dụng tự đặt theo quy tắc đặt tên

Kiểu: là kích thước (phạm vi) biểu diễn của biến Có các kiểu sau:

DD (Define Double Word): Kiểu double word (4 byte)

DF (Define Farword): Kiểu farword (6 byte),

DQ (Define Quadword): Kiểu Quadword (8 byte)

Trang 5

DT (Define Ten byte): Kiểu Ten byte (10 byte)

Trong một biến có kích tước lớn hơn 1 byte thì byte cao ở địa chỉ cao, byte thấp

ở địa chỉ thấp (Theo quy ước Big-endian của Intel)

Ví dụ:

Ab db 4 ;Định nghĩa một biến có tên là Ab, kích thước 1 byte và được

Ab1 db ? ;Định nghĩa một biến có tên là Ab1, kích thước 1 byte và được

Ab2 dw 100h ;Định nghĩa một biến có tên là Ab2, kích thước 2 byte và được

Ab3 dw ? ;Định nghĩa một biến có tên là Ab3, kích thước 2 byte và được

 Biến mảng

Một biến mảng trong chương trình hợp ngữ được định nghĩa theo mẫu sau:

Tên_biến Kiểu Các giá trị khởi tạo

Tên: do người sử dụng tự đặt theo quy tắc đặt tên

Kiểu: là kích thước (phạm vi) biểu diễn của biến như đã biết

Biến mảng là biến hình thành từ một dãy liên tiếp các phần tử cùng kiêu Khi

định nghĩa biến mảng ta gán tên cho một dãy liên tiếp các phần tử có cùng độ dài (kích thước) trong bộ nhớ cùng với các giá trị ban đầu tương ứng

Ví dụ:

Ar db 1, 3, 2, 4

;Định nghĩa một biến có tên là Ar, gồm 4 phần tử, mỗi phần tử có kích thước 1

;byte (gồm 4 byte được dành chỗ cho nó trong bộ nhớ từ địa chỉ ứng với Ar để

;chứa các giá trị khởi đầu là: 1, 2, 3 và 4) Phần tử đầu tiên của mảng có địa

;chỉ trùng với địa chỉ của Ar và có giá trị là 1, phần tử thứ 2 có địa chỉ là Ar+1

;và có giá trị là 2, phần tử tiếp theo có

Ta có thể dùng toán tử DUP để khởi đầu giá trị các phần tử của mảng với cùng một giá trị

Ví dụ:

Ar1 dw 100 DUP(5)

;Định nghĩa một biến có tên là Ar1, gồm 100 phần tử, mỗi phần tử có kích

;thước 2 byte (gồm 200 byte được dành chỗ cho nó trong bộ nhớ từ địa chỉ ứng

;với Ar1 để chứa với cùng một giá trị khởi đầu cho mỗi 2 byte (word) là 5)

;Phần tử đầu tiên của mảng có địa chỉ trùng với địa chỉ của Ar1, các phần tử tiếp ;theo có địa chỉ Ar1+2, Ar1+4, Ar1+6,

Ar2 dd 20 DUP(?)

;Định nghĩa một biến có tên là Ar2, gồm 20 phần tử, mỗi phần tử có kích thước

;4 byte (gồm 80 byte được dành chỗ cho nó trong bộ nhớ từ địa chỉ ứng với Ar2

;và chưa được khởi đầu giá trị) Phần tử đầu tiên của mảng có địa chỉ trùng với

;địa chỉ của Ar, các phần tử tiếp theo có địa chỉ Ar2+4, Ar2+8, Ar2+12,

Đặc biệt ta có thể dùng toán tử DUP lồng nhau để khởi đầu giá trị các phần tử của mảng

Ví dụ:

Ar3 db 2, 2, 2 DUP(1, 3 DUP(5), 4)

Trang 6

;Định nghĩa một biến có tên là Ar3, gồm 12 phần tử, mỗi phần tử có kích thước

1 byte (gồm 12 byte được dành chỗ cho nó trong bộ nhớ từ địa chỉ ứng với Ar3

để chứa các giá trị khởi đầu cho mỗi byte) Phần tử đầu tiên của mảng có địa chỉ trùng với địa chỉ của Ar3, các phần tử tiếp theo có địa chỉ Ar3+1, Ar3+2, Dãy thứ tự giá trị các phần tử là: 2, 2, 1, 5, 5, 5, 4, 1, 5, 5, 5, 4

 Biến xâu

Biến kiểu xâu ký tự là trường hợp dặc biệt của biến mảng mà các phần tử của mảng là ký tự Một xâu ký tự có thể được định nghĩa bằng các ký tự, xâu ký tự hoặc bằng mã ASCII của các ký tự

Chúng ta có thể định nghĩa biến xâu ký tự theo các dòng ví dụ sau, chúng là tương đương nhau:

Ví dụ:

Str1 db 'Co non'

Str2 db 'C', 'o', ' ', 'n', 'o', 'n'

Str3 db 'C', 'o', ' ', 'non'

Str4 db 43h, 6fh, 32h, 6eh, 6fh, 6eh

Str5 db 43h, 'o', 32h, 'n', 6fh, 6eh

 Hằng

Trong chương trình hợp ngữ, các giá trị không đổi thường được gán tên làm cho chương trình rõ ràng, dễ đọc hơn - gọi là các hằng Hằng trong chương trình có thể là kiểu số hoặc kiểu ký tự Việc gán tên cho hằng được thực hiện nhờ lệnh giả EQU (Equate) theo mẫu sau:

Tên_hằng Equ Giá trị khởi tạo

Ví dụ:

Cr Equ 0dh ;Carriage return

Lf Equ 0ah ;Line feed

Pa Equ 3f8h

Clause Equ 'Co non xanh tan chan troi'

Str db Clause,'$'

Str1 db Clause, Cr, Lf., '$'

d Khung của một chương trình hợp ngữ

Một chương trình mã máy được nạp vào bộ nhớ thường bao gồm các vùng nhớ khác nhau:

- Vùng dữ liệu: Dùng để chứa các biến, kết quả trung gian hay kết quả khi chạy chương trình

- Vùng mã lệnh: Dùng để chứa mã lệnh của chương trình

- Vùng ngăn xếp: Dùng để phục vụ cho các hoạt động của chương trình như gọi chương trình con, trở về chương trình chính từ chương trình con

Một chương trình hợp ngữ cũng có cấu trúc như vậy, để khi được dịch nó sẽ tạo

ra mã tương ứng với chương trình mã máy nói trên (có cấu trúc giống như vậy) Chúng ta sẽ khai báo quy mô sử dụng bộ nhớ đối với các vùng nhớ đó để sử dụng một cách phù hợp, tiết kiệm, hiệu quả và đúng với cấu trúc chương trình

 Khai báo quy mô sử dụng bộ nhớ

Khai báo này xác định kích thước cho đoạn mã và dữ liệu của chương trình

Trang 7

Sử dụng hướng dẫn chương trình dịch Model đặt trước các hướng dẫn khác trong chương trình theo mẫu như sau:

.Model Kích_thước

Ví dụ:

Model Small

Model Tiny

Có các kiểu Kích_thước bộ nhớ cho chương trình hợp ngữ như sau:

- Tiny (hẹp): Mã lệnh và dữ liệu nằm gọn trong một đoạn

- Small (nhỏ): Mã lệnh trong một đoạn, dữ liệu trong một đoạn

- Medium (Trung bình): Mã lệnh hơn một đoạn, dữ liệu trong một đoạn

- Compact (Gọn): Mã lệnh trong một đoạn, dữ liệu hơn một đoạn

- Large (Lớn), Huge (Rất lớn - khổng lồ): Mã lệnh và dữ liệu hơn một đoạn Các mảng có thể lớn hơn 64KByte

 Khai báo đoạn ngăn xếp

Ngăn xếp là vùng nhớ phục vụ cho các hoạt động của chương trình khi gọi cheơng trình con và trở về chương trình chính từ chương trình con Tuỳ theo cấu trúcvà quy mô của chương trình mà ta khai báo kích thước của đoạn này Việc khai báo được thực hiện nhờ hướng dẫn chương trình dịch Stack theo mẫu sau:

.Stack Kích_thước

Ví dụ:

Stack 100

Stack 100h ;256

Chú ý: Nếu ta không khai báo kích thước của đoạn này thì chương trình dịch sẽ

tự động gán giá trị 1 Kbyte cho vùng ngăn xếp này Đây là kích thước quá lớn đối với một ứng dụng thông thường Nói chung ta nên chọn là 100 hoặc 100h là đủ

 Khai báo đoạn dữ liệu

Phần này để định nghĩa các biến của chương trình

Hằng cũng nên định nghĩa ở đây để đảm bảo sự thống nhất (mặc dù ta có thể

định nghĩa hằng ở chỗ khác, lý do là lệnh giả EQU không cấp phát bộ nhớ cho hằng (tên hằng không tương ứng với một địa chỉ nào) nên ta có thể định nghĩa hằng tự do thoải mái trong chương trình

Việc khai báo đoạn dữ liệu được thực hiện nhờ hướng dẫn chương trình dịch .Data Định nghĩa các biến, mảng và hằng được thực hiện tiếp ngay sau đó bằng các lệnh giả thích hợp, của thể như sau:

Ví dụ:

Data

Chao db 'Xin chao ban!','$'

Crlf db 0dh, 0ah, '$'

 Khai báo đoạn mã lệnh

Phần này chứa toàn bộ mã lệnh của chương trình Việc khai báo đoạn mã được thực hiện nhờ hướng dẫn chương trình dịch Code như sau:

.Code

Tên_CTC Proc

Các lệnh ;Các lệnh của thanh chương trình chính

Trang 8

Call Tên_ctc ;Gọi chương trình con

Tên_CTC Endp

Tổng quát: Một thủ tục được định nghĩa nhờ cặp thủ tục 'Proc - Endp ', chương trình chính cũng là một thủ tục được định nghĩa như trên Lệnh giả Proc dùng để báo bắt đầu một thủ tục và lệnh giả Endp dùng để báo kết thúc thủ tục đó Một chương trình con cũng được định nghĩa dưới dạng một thủ tục nhờ các lệnh giả 'Proc - Endp ' như sau:

Tên_ctc Proc

Các lệnh của chương trình con ở đây

Tên_ctc Endp

Chú ý: Trong chương trình con, tại cuối chương trình có lệnh Ret là lệnh trở về chương trình chính từ chương trình con

Để kết thúc toàn bộ chương trình, ta dùng hướng dẫn chương trình dịch End như sau:

End Tên_CTC

 Khung của chương trình hợp ngữ để dịch ra chương trình *.exe

.Model Small

.Stack 100

.Data

;Định nghĩa các biến, mảng, hằng ở đây

.Code

Tên_CTC Proc

;Khởi tạo đoạn dữ liệu

Mov ds, ax

Mov es, ax ;Nếu cần

;Các lệnh của chương trình chính

;Trở về DOS dùng hàm 4ch của ngắt 21h

Mov ah, 4ch

Int 21h

Tên_CTC Endp

;Các chương trình con nếu có được định nghĩa ở đây

End Tên_CTC

Khi chương trình *.exe được nạp vào bộ nhớ, DOS sẽ lập ra một một mảng gọi

là đoạn mào đầu chương trình (Program Segment Prefix - PSP) gồm 256 byte dùng

để chứa các thông tin liên quan đến chương trình và cả DOS, được gắn vào đầu chương trình DOS sử dụng các thông tin này để giúp chạy chương trình, PSP được DOS khởi tạo cho mọi chương trình dù chúng được viết bằng ngôn ngữ nào Do ngay khi chương trình được nạp vào bộ nhớ, DOS cũng đưa các thông số liên quan đến chương trình vào các thanh ghi DS và ES (cụ thể là DS và ES trỏ vào đầu của PSP)

mà không chứa giá trị địa chỉ của các thanh ghi đoạn dữ liệu của chương trình Để

chương trình chạy đúng, ta phải khởi đầu cho các thanh ghi DS và

ES nhờ các lệnh:

Với 8088/8086 và một số bộ vi xử lý khác thuộc họ 80x86

Mov ax, @Data

Mov ds, ax

Mov es, ax

Trang 9

của Intel, vì lý do kỹ thuật mà chúng không cho phép chuyển giá trị số (chế độ địa chỉ trực tiếp) vào các thanh ghi đoạn nên ta phải dùng thanh ghi ax làm trung gian Thanh ghi ax cũng có thể thay thế bằng các thanh ghi đa năng khác

@Data là tên của đoạn dữ liệu, Data dđịnh nghĩa bởi hướng dẫn chương trình dịch  chương trình dịch sẽ dịch tên @Data thành giá trị địa chỉ của đoạn dữ liệu Chương trình ví dụ1.asm để dịch ra *,exe, thực hiện xuất một dòng ký tự lên màn hình Dòng ký tự ở đây là lời chào bất kỳ được hiện giữa 2 dòng trống:

.Model Small

.Stack 100

.Data

Chao db 'Xin chao, chuc mung ban da thanh cong voi chuong trinh dau tay$' Crlf db 0dh, 0ah, '$'

.Code

Vidu1 Proc

Mov ax, @Data ;Lấy địa chỉ của đoạn dữ liệu

Mov ds, ax ;Khởi tạo đoạn dữ liệu

Mov es, ax

;Về đầu dòng mới dùng hàm 9 của ngắt 21h để "hiển thị" cặp ký tự ;xuống dòng (lf: line feed) và về đầu dòng (cr: carriage return)

Mov ah, 9

Lea dx, crlf

Int 21h

;Hiển thị lời chào dùng hàm 9 của ngắt 21h

Mov ah, 9

Lea dx, Chao

Int 21h

;Về đầu dòng mới dùng hàm 9 của ngắt 21h

Mov ah, 9

Lea dx, crlf

Int 21h

;Về DOS dùng hàm 4ch của ngắt 21h

Mov ah, 4ch

Int 21h

Vidu1 Endp

End Vidu1

Nhận xét về chương trình trên:

 Khung của chương trình hợp ngữ để dịch ra chương trình *.com

Với khung chương trình hợp ngữ để dịch ra tệp chương trình chạy được *.exe thì

có mặt đầy đủ các đoạn Ngoài tệp chương trình chạy được có phần mở rộng exe ra

ta còn có khả năng dịch chương trình hợp ngữ có kết cấu (cấu trúc) thích hợp ra một loại chương trình chạy được kiểu khác với phần mở rộng com Đây là chương trình ngắn gọn và đơn giản hơn nhiều so với tệp chương trình *.exe mà trong đó các đoạn:

đoạn mã, đoạn dữ liệu và đoạn ngăn xếp của chương trình được gói gọn trong một

đoạn (64Kbyte) duy nhất là đoạn mã Với những ứng dụng mà dữ liệu và mã lệnh của chương trình không yêu cầu nhiều về không gian nhớ thì ta có thể ghép luôn chúng chung vào cùng một đoạn mã rồi tạo ra tệp *.com Việc tạo ra tệp này không chỉ tiết

Trang 10

kiệm được thời gian và bộ nhớ khi cho chạy chương trình mà còn tiết kiệm cả không gian nhớ khi phải lưu trữ chúng trên bộ nhớ ngoài (đĩa từ)

Để có thể tạo ra được chương trình với phần mở rộng com thì chương trình nguồn hợp ngữ phải có kết cấu thích hợp, một ví dụ như sau:

.Model Tiny

.Code

Start: Jmp Continue

;Định nghĩa các biến, mảng, hằng ở đây

Continue:

Tên_CTC Proc

;Các lệnh của chương trình chính

;Trở về DOS dùng ngắt 20h

Int 20h

Tên_CTC Endp

;Các chương trình con nếu có được định nghĩa ở đây

End Start

Nhìn vào khung chương trình hợp ngữ để dịch ra chương trình com ta thấy không có khai báo đoạn ngăn xếp và đoạn dữ liệu, khai báo quy mô sử dụng bộ nhớ

là Tiny (tuy nhiên có thể sử dụng quy mô bộ nhớ là Small) ở đầu đoạn mã có lệnh giả Org (Origin: điểm xuất phát) và lệnh Jmp (nhảy) Lệnh Org 100h dùng để gán điạ chỉ bắt đầu cho chương trình là 100h trong đoạn mã, bỏ qua vùng nhớ kích thước 100h (256 byte) cho đoạn mào đầu (PSP) từ địa chỉ 0 đến địa chỉ 255

Lệnh Jmp dùng để nhảy qua phần bộ nhớ dành cho việc định nghĩa các dữ liệu (về nguyên tắc, dữ liệu có thể được đặt ở đầu hoặc cuối đoạn mã nhưng ở đây, nó

được đặt ở đầu để có thể áp dụng các định nghĩa đơn giản đã nói) Đích của lệnh nhảy là phần bắt đầu của chương trình chính

Hình vẽ: Tệp chương trình com trong bộ nhớ Nhìn vào hình vẽ ta thấy một chương trình com cùng được nạp vào bộ nhớ sau vùng PSP như chương trình exe Ngăn xếp cho chương trình được đặt cuối đoạn mã,

đỉnh của ngăn xếp lúc ban đầu là ô nhớ có địa chỉ FFFEh

Đặc điểm của chương trình *.com

Vì dung lượng nhớ cực đại của một đoạn là 64Kbyte, nên ta phải chắc chắn rằng chương trình của ta có số lượng byte của mã lệnh và dữ liệu là không lớn (không vượt quá giới hạn cho phép của một đoạn, nếu không nó sẽ làm cho cả nhóm nở ra

về phía địa chỉ cao của đoạn)

Chương trình phải sử dụng ngăn xếp một cách hạn chế, nếu không nó sẽ làm cho đỉnh ngăn xếp dâng lên về phía địa chỉ thấp của đoạn khi hoạt động.Chúng ta phải đảm bảo rằng không thể xảy ra hiện tượng chùm lên nhau của các thông tin tại vùng ngăn xếp và thông tin tại vùng mã lệnh và dữ liệu

Khi kết thúc chương trình kiểu *.com, để trở về DOS ta dùng ngắt 20h của DOS

để làm cho chương trình gọn hơn Mặc dù ta vẫn có thể dùng hàm 4ch của ngắt 21h

để trở về DOS như đã dùng trong chương trình để dịch ra *.exe

Ngày đăng: 22/07/2014, 05:21

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w