You are on page 1of 13

Bộ vi xử lý 8088/8086 và lập trình hợp ngữ x86

3.1 Thanh ghi (Register)

Là các phần tử nhớ đặc biệt bên trong bộ vi xử lý. các thanh ghi luôn có kích thước
bằng nhau, kích thước này cũng chính là độ rộng của data bus bên trong bộ xử lý.
8088 là bộ vi xử lý 16 bit do đó các thanh ghi của 8088 đều có kích thước 16 bit.

Một số tác vụ đặc biệt như nhân hay chia, kết quả bắt buộc phải đặt trong thanh ghi
Một số thanh ghi chỉ dùng để xác định địa chỉ cho bộ xử lý
Các tác vụ trên thanh ghi nhanh hơn nhiều so với các tác vụ trên bộ nhớ
Bộ vi xử lý 8088 có 14 thanh ghi 16 bit chia thành nhóm theo chức năng như sau:

Nhóm thanh ghi đa dụng (General registers):
F E D C B A 9 8 7 6 5 4 3 2 1 0
AX AH AL
BX BH BL
CX CH CL
DX DH DL

Nhóm thanh ghi chỉ mục và con trỏ (Index & Pointer registers):
F E D C B A 9 8 7 6 5 4 3 2 1 0
SI SI
DI DI
BP BP
SP SP

Nhóm thanh ghi phân đoạn (Segment registers):
F E D C B A 9 8 7 6 5 4 3 2 1 0
DS DS
ES ES
SS SS
CS CS

Thanh ghi cờ hiệu:
F E D C B A 9 8 7 6 5 4 3 2 1 0
Flag O D I T S Z A P C

Thanh ghi contrỏ lệnh (Instruction Pointer) :
F E D C B A 9 8 7 6 5 4 3 2 1 0
Flag IP
3.1.1 Nhóm thanh ghi dữ liệu (Data registers):

AX,BX,CX,DX hay là AH,AL,BH,BL,CH,CL,DH,DL
Đóng vai trò chủ yếu như là các phần tử nhớ cơ bản trong các quá trình tính
toán. Tham gia vào các tác vụ tính toán của bộ xử lý. Có thể sử dụng như là
một thanh ghi 16 bit hoặc hai thanh ghi 8 bit nối liền nhau.

3.1.2 Nhóm thanh ghi chỉ mục và con trỏ (Index & Pointer registers):

SI,DI,BP,SP
Có thể sử dụng như các thanh ghi đa dụng, ngoài ra còn đóng vai trò làm chỉ
mục khi xác dịnh địa chỉ theo offset của bộ xử lý.

- SI và DI là hai thanh ghi chỉ mục để thực hiện các tác vụ chuỗi
- BP và SP là hai thanh ghi con trỏ để thao tác trên cấu trúc STACK

3.1.3 Nhóm thanh ghi phân đoạn (Segment registers):

DS,ES,SS,CS
Không thể tham gia vào các tác vụ tính toán, thường chỉ dùng để xác định các
địa chỉ phân đoạn.

- DS: Data segment register
- ES: Extra segment register
- SS: Stack segment register
- CS: Code segment register

3.1.4 Thanh ghi con trỏ lệnh (Instruction Pointer register):

IP
Không thể tham gia vào các tác vụ tính toán, không thể gán giá trị trực tiếp,
cùng với CS tạo thành địa chỉ mã lệnh sẽ thực hiện của CPU

3.1.5 Thanh ghi cờ hiệu (Flag register):

Flag
Không thể tham gia vào các tác vụ tính toán, không thể gán giá trị trực tiếp,
chỉ dùng để ghi nhận hoặc chỉ định các trạng thái làm việc của CPU.

3.2 Địa chỉ (Memory address)

Các lệnh của bộ xử lý thao tác trực tiếp lên các đối tượng chủ yếu là thanh ghi và bộ
nhớ . Các thanh ghi dược xác định bằng tên , các phần tử thuộc bộ nhớ được xác định
bằng địa chỉ. Các bộ xử lý thuộc dòng họ x86 xác định địa chỉ bằng hai giá trị 16 bit
gọi là segment và offset. Địa chỉ vật lý tương ứng được tính theo công thức :
Memory_Address = Segment * 10h + Offset
20 bit 16 bit 16 bit

Một địa chỉ vật lý có thể biểu diễn thành nhiều cặp segment và offset khác nhau.
Thí dụ: 0040:006C 0000:046C 0020:026C
là các biểu diễn của dịa chỉ vật lý 20 bit 00046C.

3.2.1 Segment:

Segment là một đoạn bộ nhớ có kích thước tối đa 64KB (16 bit offset) và có
thể bắt đầu tại các địa chỉ chia chẵn cho 16 (10h) trên toàn bộ vùng nhớ 1MB
(20 bit).

Trong hầu hết các tác vụ của bộ xử lý 8088, segment dược xác định gián tiếp
qua các thanh ghi segment DS , ES , SS , CS . Khi cần sử dụng segment nào ,
phải gán giá trị tương ứng cho các thanh ghi segment . Lúc đó các địa chỉ
được thể hiện thành dạng Segment:offset
Thí dụ: CS:Offset , DS:Offset

3.2.2 Offset:

Offset là một cự ly (16 bit) so với điểm đầu của một segment.
Các cách mô tả offset:
[Const] , [BX] , [BP] , [SI] , [DI]
[BX+Const] , [BP+Const] , [SI+Const] , [DI+Const]
[BX+SI+Const] , [BX+DI+Const] , [BP+SI+Const] , [BP+DI+Const]

Const là một hằng số

* Nhận xét: Offset có thể mô tả bằng một tổng của : Hằng số 16 bit và các
thanh ghi chỉ mục BX, BP, SI, DI . Trong đó các cặp BX và BP , SI và DI
không được phép cùng xuất hiện

3.3 Các lệnh cơ bản

Các lệnh của bộ vi xử lý 8088 dưới đây sẽ được mô tả theo dạng thức:
Tên_Lệnh [Đích [, Nguồn]]

Đích (Dest) có thể là tên một thanh ghi (Reg) , một địa chỉ trong bộ nhớ (Mem), một
vị trí trong chương trình (Label)

Nguồn (Src) có thể là tên một thanh ghi (Reg) , một địa chỉ trong bộ nhớ (Mem), một
hằng số (Const)

Đích và Nguồn không đồng thời là hai địa chỉ trong bộ nhớ (Mem)
3.3.1 Lệnh MOVE

MOVE <Dest>,<Src>

Giá trị của Src dược gán (assign) vào Dest

Không thể MOVE :
- Hai thanh ghi segment
- Hằng số vào thanh ghi segment
- Bất cứ gia trị nào vào các thanh ghi IP và Flag

3.3.2 Lệnh XCHG

XCHG <Dest>,<Src>

Giá trị của Src và Dest đổi chỗ cho nhau
 Src và Dest chỉ có thể là Reg hoặc Addr/Mem

Không thể XCHG giữa các thanh ghi segment với nhau.

3.3.3 Lệnh INC , ADD và ADC

INC <Dest>
Lấy Dest cộng với 1 rồi gán kết quả vào Dest

ADD <Dest>,<Src>
Lấy Dest cộng với Src rồi gán kết quả vào Dest

ADC <Dest>,<Src>
Lấy Dest cộng với Src và cộng thêm 1 nếu CF=1 rồi gán kết quả vào Dest

3.3.4 Lệnh DEC , SUB và SBB

DEC <Dest>
Lấy Dest trừ đi 1 rồi gán kết quả vào Dest

SUB <Dest>,<Src>
Lấy Dest trừ đi Src rồi gán kết quả vào Dest

SBB <Dest>,<Src>
Lấy Dest trừ đi Src và trừ tiếp 1 nếu CF=1 rồi gán kết quả vào Dest
3.3.5 Lệnh MUL

MUL <Reg_8bit/Mem_8bit>

Lấy AL nhân với Reg_8bit hoặc Mem_8bit
Kết quả (16 bit) gán vào AX

MUL <Reg_16bit/Mem_16bit>

Lấy AX nhân với Reg_16bit hoặc Mem_16bit
Kết quả (32 bit) gán vào DX,AX (Theo thứ tự DH,DL,AH,AL)

3.3.6 Lệnh DIV

DIV <Reg_8bit/Mem_8bit>

Lấy AX chia cho Reg_8bit hoặc Mem_8bit
Kết quả (8 bit) gán vào AL , số dư (8 bit) gán vào AH

DIV <Reg_16bit/Mem_16bit>

Lấy DX,AX (32 bit) chia cho Reg_8bit hoặc Mem_8bit
Kết quả (16 bit) gán vào AX , số dư (16 bit) gán vào DX

3.3.7 Lệnh IMUL và IDIV

Giống MUL và DIV, nhưng thực hiện trên các giá trị có dấu và cho ra kết quả
có dấu

3.3.8 Lệnh AND , OR , XOR và NOT

ADD <Dest>,<Src>
OR <Dest>,<Src>
XOR <Dest>,<Src>

Lấy Dest AND/OR/XOR với Src rồi gán kết quả vào Dest

NOT <Dest>

Lấy NOT của Dest gán vào Dest
3.3.9 Lệnh SHL , SHR

SHL/SHR <Reg/Mem>,1

Đẩy các bit của thanh ghi sang trái (SHL)hoặc sang phải(SHR) 1 cột
(Nhân/Chia với 2)

SHL/SHR <Reg/Mem>,CL

Đẩy các bit của thanh ghi sang trái (SHL) hoặc sang phải (SHR) n cột, với n là
giá trị chứ a trong CL (Nhân/Chia với 2n )

Kết thúc lệnh , cờ hiệu CF chứa bit cuối cùng lọt ra ngoài.

Trước khi SHL  SHL AL,1  SHL AL,1
1 0 0 1 1 0 1 1 0 0 1 1 0 1 1 0 0 1 1 0 1 1 0 0
CF = 1 CF = 0

Trước khi SHR  SHR AL,1  SHR AL,1
1 0 0 1 1 0 1 1 0 1 0 0 1 1 0 1 0 0 1 0 0 1 1 0
CF = 1 CF =1

3.3.10 Lệnh RCL , RCR

RCL/RCR <Reg/Mem>,1

Quay các bit của thanh ghi và CF sang trái hoặc sang phải 1 cột

RCL/RCR <Reg/Mem>,CL

Quay các bit của thanh ghi và CF sang trái hoặc sang phải n cột, với n là giá
trị chứ a trong CL

Trước khi RCL  RCL AL,1  RCL AL,1
1 0 0 1 1 0 1 1 0 0 1 1 0 1 1 0 0 1 1 0 1 1 0 1
CF = 0 CF = 1 CF = 0

Trước khi RCR  RCR AL,1  RCR AL,1
1 0 0 1 1 0 1 1 0 1 0 0 1 1 0 1 1 0 1 0 0 1 1 0
CF = 0 CF = 1 CF =1
3.3.11 Lệnh ROL , ROR

ROL/ROR <Reg/Mem>,1

Quay các bit của thanh ghi sang trái (ROL) hoặc sang phải (ROR) 1 cột

ROL/ROR <Reg/Mem>,CL

Quay các bit của thanh ghi sang trái (ROL) hoặc sang phải (ROR) n cột, với n
là giá trị chứ a trong CL

Trước khi ROL  ROL AL,1  ROL AL,1
1 0 0 1 1 0 1 1 0 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0

Trước khi ROR  ROR AL,1  ROR AL,1
1 0 0 1 1 0 1 1 1 1 0 0 1 1 0 1 1 1 1 0 0 1 1 0

3.4 Các lệnh so sánh và chuyển điều khiển cơ bản

3.4.1 Lệnh JMP

JMP <Label>
CPU chuyển đến thực hiện lệnh tại <Label>.

3.4.2 Lệnh CMP và TEST

CMP <Dest>,<Src>
Thực hiện phép trừ Dest cho Src, kết quả không được giữ lại, các cờ hiệu bị
thay đổi.

Test <Dest>,<Src>
Thực hiện phép AND Dest với Src, kết quả không được giữ lại, các cờ hiệu
bị thay đổi.

Hai tác vụ này được phối hợp cùng với các lệnh chuyển điều khiển theo điều
kiện.

3.4.3 Các lệnh chuyển điều khiển theo điều kiện

Lệnh chuyển điều khiển theo điều kiện có dạng thức chung như sau :

<Jump_command> <Label>

<Label> là một tên nhãn đánh dấu một vị trí trong chương trình. Khi điều
kiện kiểm tra là đúng, CPU sẽ chuyển đến thực hiện lệnh tại vị trí <Label> ,
nếu điều kiện kiểm tra là sai CPU sẽ thực hiện lệnh kế tiếp
Lệnh chuyển điều khiển theo điều kiện so sánh
Số không dấu Số có dấu So
sánh
JA JG >
JAE , JNB JGE , JNL >=
JE , JZ JE , JZ =
JBE , JNA JLE , JNG <=
JB JL <
JNE , JNZ JNE , JNZ <>

Lệnh chuyển điều khiển theo cờ hiệu Lệnh làm thay đổi cờ hiệu trực tiếp
Lệnh Điều kiện Lệnh Điều kiện
JC CF = 1 STC CF = 1
JNC CF = 0 CLC CF = 0
JZ ZF = 1 STD DF = 1
JNZ ZF = 0 CLD DF = 0
JO OF = 1 STI IF = 1
JNO OF = 0 CLI IF = 0
JP PF = 1
JNP PF = 0
JS SF = 0
JNS SF = 0
JNS SF = 0
JCXZ CX = 0

Các lệnh chuyển điều khiển theo điều kiện thường đi theo sau lệnh CMP
Các lệnh chuyển điều khiển không làm thay đổi giá trị của các cờ hiệu.

3.4.4 Lệnh LOOP

LOOP <Label>

<Label> là một tên nhãn đánh dấu một vị trí trong chương trình.
Đoạn lệnh tương đương:

SUB CX,1
CMP CX,0
JNE <Label>

Mỗi lần thực hiện LOOP , CX giảm đi 1 , sau đó nếu CX=0 CPU sẽ thực hiện
lệnh tiếp theo , nếu CX>0 CPU sẽ chuyển đến thực hiện lệnh tại <Label>.
Nên dùng LOOP khi cần phải thực hiện các chu trình có số lần lặp đã biết
trước.
3.5 Viết chương trình với Assembler 86

3.5.1 Thí dụ 1

Code segment
assume cs,ds,es:code
org 0100h

Main proc near

; Day la ghi chu
; Sau dau cham phay la ghi chu

mov ah,1 ; ah=1 , Read char function
int 021h ; chờ nhấn một phím

int 020h ; kết thúc chương trình và quay lại
; dấu đợi lệnh
Main endp

Code ends
end Main

Có thể viết các chương trình đầu tiên bằng cách dùng thí dụ 1 làm mẫu, chỉ cần thay thế
các các dòng lệnh màu xanh bằng phần chương trình của mình

3.5.2 Thí dụ 2

Code segment
assume cs,ds,es:code
org 0100h

Main proc near

lea dx,chuoi ; nạp địa chỉ của chuoi vào dx
mov ah,9 ; ah=9 , Print string
int 021h ; In chuoi ra màn hình
int 020h ; kết thúc chương trình và quay lại
; dấu đợi lệnh
Main endp

chuoi db 'Chao ban', '$'

Code ends
end Main
3.5.3 Khai báo và sử dụng bộ nhớ:

Chương trình viết cho bộ vi xử lý 8088 là một tập hợp các byte vừa mã lệnh
vừa dữ liệu. Người viết chương trình phải tự tổ chức và sắp xếp để khi chương
trình được thực hiện bộ vi xử lý không nhầm lẫn giữa dữ liệu và mã lệnh.
Ta có thể khai báo một vùng nhớ trong chương trình dùng để lưu trữ dữ liệu
bằng các dòng lệnh như sau:

db 1,2,3,4 ; Mô tả 4 byte lần lượt có giá trị là 1,2,3,4
db 'a', 'b' ; Mô tả 2 byte mã ASCII của ký tự a và b
db 1,2,'a'
db 'chao' ; Mô tả 4 byte của chuỗi ‘chao’

dw 0,1 ; Mô tả 2 word (4 byte) 0 và 1
dd 0,1 ; Mô tả 2 dword (8 byte) 0 và 1

Khai báo kiểu dữ liệu (db,dw,dd ) mô tả các ô nhớ và giá trị được gán trong
chương trình. Số lượng các ô nhớ được xác định bằng số lượng các giá trị
được liệt kê ngay sau khai báo kiểu dữ liệu.
Kiểu dữ liệu db ấn định mỗi phần tử dữ liệu có kích thước 1 byte
Kiểu dữ liệu dw ấn định mỗi phần tử dữ liệu có kích thước 2 byte
Kiểu dữ liệu dd ấn định mỗi phần tử dữ liệu có kích thước 4 byte

Để có thể sử dụng được các vùng dữ liệu đã khai báo trong chương trình,
người ta “đánh dấu” các vị trí đó bằng cách đặt các nhãn ngay trước khai báo
kiểu:

chuoi db 'chao'
tongso db 0
dayso db 5,6,7,8

Sau đó có thể khai thác các vùng nhớ này như sau:

Gán địa chỉ (offset) của chuoi vào thanh ghi dx:
mov dx, offset chuoi
hoặc
lea dx, chuoi

Gán giá trị đang lưu tại ô nhớ tongso (1 byte) vào thanh ghi al:
mov al, byte ptr tongso
Gán giá trị trong al vào ô nhớ tongso (1 byte):
mov byte ptr tongso,al

Gán giá trị của ô nhớ thứ 1 trong dayso vào al:
mov al, tongso[0] ; AL sẽ bằng 5
Gán giá trị của ô nhớ thứ 2 trong dayso vào al:
mov al, tongso[1] ; AL sẽ bằng 6
Khi tham chiếu đến một vùng nhớ, nên mô tả tường minh về loại dữ liệu bằng
chỉ định byte ptr hoặc word ptr . Nếu không mô tả thì trình hợp dịch sẽ
lấy theo kiểu dữ liệu đã khai báo.

3.5.4 Sử dụng các chức năng hệ thống:

Có nhiều đoạn mã lệnh dùng để điều khiển các thiết bị được thiết kế sẵn trong
BIOS hoặc OS. Các chương trình viết cho PC thường dùng các đoạn mã lệnh
này hơn là phải thực hiện lại từ đầu. Cách thức này được gọi là sử dụng các
chức năng của hệ thống.

*Một số chức năng hệ thống đơn giản của DOS:

Chờ đọc một phím, có in lại phím này ra màn hình
mov ah,1
int 021h
Sau khi thực hiện AL = mã ASCII của phím được gõ vào

In một ký tự ra màn hình
mov dl,<ky_tu_can_in>
mov ah,2
int 021h

In một chuỗi ký tự ra màn hình
mov dx,offset <chuoi_can_in>
mov ah,9
int 021h
Chuỗi ký tự phải kết thúc bằng ký tự $,

Một số các ký tự điều khiển có ảnh hưởng đến chức năng in như sau:

7 : Bell  beep một tiếng
8 : Back Space (BS)  xóa ký tự bên trái
10 : Line Feed (LF)  xuống hàng
13 : Carriage Return (CR)  về đầu dòng

*Một số chức năng hệ thống đơn giản của BIOS:

Chờ đọc một phím, không in lại phím này ra màn hình
mov ah,0
int 016h
Sau khi thực hiện AL = mã ASCII của phím được gõ vào
AH = scan code của phím
AL bằng 0 khi một số các phím chức năng được bấm
Đọc trạng thái của bàn phím
mov ah,2
int 016h
Sau khi thực hiện AL = byte trạng thái của bàn phím

In chuỗi ký tự với thuộc tính màu, bắt đầu tại vị trí row và col:
mov ax,01301h
mov bh,0
mov bl,<color_code>
mov bp,offset <chuoi_can_in>
mov cx,<So_ky_tu_trong_chuoi>
mov dh,<row> ; 0 - 24
mov dl,<col> ; 0 - 79
int 010h

Màn hình PC trong text mode có 25 dòng, mỗi dòng 80 ký tự.

Màu của ký tự được tạo thành từ màu nền (Background color) và màu ký tự
(Foreground/Text color) theo công thức sau:
Color_code = Foreground_Color + 16*Background_Color

Hãy dùng Tech Help để tham khảo các chức năng của BIOS và DOS