chương 9
Truy nhập trực tiếp vào bộ nhớ
Trong chương này trỡnh bầy cỏc vấn đề:
+ Hai kiểu địa chỉ: Địa chỉ phõn đon và đa chỉ thực
+ Truy nhập ti đa ch phõn đoạn
+ Đổi từ địa chỉ phõn đoạn sang đa chỉ thực
+ Bộ nhớ màn hỡnh, truy nhập trực tiếp vào bộ nhớ màn hỡnh
+ Dựng con trỏ để lấy dữ liệu từ bộ nhớ phõn đon
+ Dựng con trỏ hàm để thực hiện cỏc th tục của DOS
§ 1. Cỏc hàm truy nhập theo địa chỉ phõn đoạn
1. Hàm pokeb: Gửi một ký tự vào bộ nhớ.
+ Nguyờn mẫu trong dos.h như sau:
void pokeb(unsigned seg, unsigned off, char value);
+ Cụng dụng: Gửi giỏ trị tự value vào bộ nh tại địa chỉ phõn
đoạn seg:off
2. Hàm peekb: Nhận mt ký tự từ bộ nhớ.
+ Nguyờn mẫu trong dos.h như sau:
char peekb(unsigned seg, unsigned off);
+ Cụng dụng: Nhận một byte tại địa ch phõn đoạn seg:off
3. Hàm poke: Gửi một s nguyn vào bộ nhớ.
+ Nguyờn mẫu trong dos.h như sau:
void poke(unsigned seg, unsigned off, int value);
+ Cụng dụng: Gửi giỏ trị nguyờn value o bộ nhớ tại địa ch
phõn đoạn seg:off
4. Hàm peek: Nhận mt số nguyờn từ bộ nhớ.
+ Nguyờn mẫu trong dos.h như sau:
int peek(unsigned seg, unsigned off);
+ Cụng dụng: Nhn một word tại đa chỉ phõn đoạn seg:off
5. Hàm movedata: Sao cỏc byte.
+ Nguyờn mẫu trong mem.h như sau:
void movedata(unsigned seg_gui, unsigned off_gui,
unsigned seg_nhan, unsigned off_nhan, int n);
+ Cụng dụng: Sao n byte từ seg_gui:off_gui đến
seg_nhan:off_nhan
§ 2. Bộ nhớ màn hỡnh văn bản
2.1. Cỏch biểu diễn ký tự trong bộ nhớ màn hỡnh
Bộ nhmàn hnh văn bản bắt đầu từ đa chỉ :
(0xb800:0x0000)
Khi đưa một tự vào vựng nhmàn hỡnh, thỡ sẽ hiện lờn
màn hnh. Mỗi ký tự trờn màn hỡnh chiếm 2 byte trong bộ nh màn
hỡnh: byte đầu chứa ASCII, byte th hai biểu diễn mầu hiển thị
gi byte thuộc tớnh. Cỏc bit của byte thuộc tớnh:
B7B6B5B4B3B2B1B0
được chia làm 3 nhúm:
+ Nhúm 1 gồm bit B7 biểu thị sự nhấp nhỏy. Nếu B7=0 thký tự
khụng nhấp nhy, nếu B7=1 thỡ ký tự sẽ nhấp nhỏy.
+ Nhúm 2 gồm cỏc bit B6, B5 và B4. Cỏc bit này chứa được một
số nguyn từ 0 đến 7 và biểu thị 8 mầu nền của ký tự.
+ Nhúm 3 gm cc bit B3, B2, B1 B0. Cỏc bit y cha được
một số nguyn từ 0 đến 15 và biểu thị 16 mầu ca ký tự.
2.2. Trang màn hỡnh
Mỗi trang màn hnh gồm 80x25 tự, do đú cần 80x25x2=4000
byte b nh. Thực tế mỗi trang màn hỡnh được phõn bố 4096 =
0x1000 byte. Như vậy 4 trang màn hỡnh được phõn bố như sau:
491
492
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.
+ Trang màn hỡnh thứ 0 bắt đầu từ địa chỉ 0xB800:0x0000
+ Trang màn hỡnh thứ 1 bắt đầu từ địa chỉ 0xB800:0x1000
+ Trang màn hỡnh thứ 2 bắt đầu từ địa chỉ 0xB800:0x2000
+ Trang màn hỡnh thứ 3 bắt đầu từ địa chỉ 0xB800:0x3000
2.3. Chọn trang hiển thị
Ti mỗi thời điểm chỉ thhiển thị được một trong 4 trang màn
hỡnh. Để hiển thị trang n hnh thứ t (t=0,1,2,3) chỳng ta sử dụng
chức năng 5 ca ngắt 0x10 theo mẫu sau:
union REGS v,r;
v.h.ah = 5 ; // Chức năng 5
v.h.al = t ; // S hiu trang màn hỡnh cần hiển thị
int86(0x10, &v, &r); // Thực hiện ngắt 0x10
2.4. Vớ dụ minh hoạ
Vớ dụ sau dựng hàm pokeb để đưa cỏc ký tự vào cỏc trang của bộ
nhớ màn hnh, sau đú dựng chức năng 5 của ngắt 0x10 đ chọn
trang hiển thị.
//CT9_03.CPP
#include <dos.h>
#include <conio.h>
char d1[]={'C',1*16+14,'H',1*16+14,'U',1*16+14,'C',1*16+14};
char d2[]={'M',2*16+15,'U',2*16+15,'N',2*16+15,'G',2*16+15};
void main()
{
union REGS v,r;
clrscr();
//Mc định hiển thị trang 0
for (int i=0;i<8;++i)
pokeb(0xb800,i,d1[i]);
getch();
//Hien thi trang 1
v.h.ah = 5 ; v.h.al = 1 ;
int86(0x10,&v,&r);
for (i=0;i<8;++i)
pokeb(0xb800,0x1000+i,d2[i]);
getch();
//Hien thi trang 0
v.h.ah = 5 ; v.h.al = 0 ;
int86(0x10,&v,&r);
getch();
//Hien thi trang 1
v.h.ah = 5 ; v.h.al = 1 ;
int86(0x10,&v,&r);
getch();
}
§ 3. chuyển Đổi địa chỉ
3.1. Để chuyển từ địa chỉ thực sang địa chỉ phõn đoạn ta dựng
cỏc macro:
unsigned FP_SEG(địa_chỉ_thực)
unsigned FP_OFF(địa_chỉ_thực)
3.2. Để chuyển từ địa chỉ phõn đoạn sang địa chỉ thực ta dựng
macro:
void far *MK_FP(seg,off)
Vớ dụ 1. Sau khi thực hiện cỏc cõu lệnh:
char buf[100];
unsigned ds,dx;
493
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.
ds = FP_SEG(buf); dx = FP_OFF(buf);
thỡ ds:dx chứa địa chỉ của mảng buf.
Vớ dụ 2. Sau khi thực hiện cỏc cõu lệnh:
char far *pchar;
pchar = (char far*)MK_FP(0xb800:0);
thỡ pchar trỏ tới đa chỉ đầu của bộ nhớ màn hỡnh. Khi đú ta thể
sử dụng cc lệnh gỏn để truy nhập trực tiếp tới bộ nhớ màn hỡnh.
§ 4. cỏc vớ dụ minh hoạ
Chương trỡnh 1. Chương trỡnh minh hoạ cỏch truy nhập trực
tiếp vào bộ nhớ màn hỡnh cú địa chỉ đầu là 0xB800:0. Chương trỡnh
gồm hàm main() và hai hàm sau:
1. Hàm cuaso
void cuaso(int dongt,int cott,int dongd,int cotd,int maucs);
thiết lập một cửa sổ mầu toạ độ gúc trờn-trỏi là (dongt, cott)
gúc dưới-phải (dongd,cotd). Mầu cho bởi tham số maucs. ở đõy sử
dụng hàm pokeb địa chỉ phõn đoạn.
2. Hàm duarmh
void duarmh(char *day, int dong, int cotd, int cotc,int m_nen,
int m_chu);
sẽ đưa ra màn hỡnh một dẫy ký tự (chứa trong dóy) tạing dong, từ
cột cotd đến cotc. Mầu nền cho bởi m_nen, mầu chữ cho bởi m_chữ.
ở đõy sử dụng toỏn tử gn trờn địa chỉ thực.
Trong hàm main() sẽ sử dụng cỏc hàm cuaso và duarmh đ to
hai cửa s và viết haing chữ trờn trang màn hỡnh thứ hai (từ dũng
26 đến dũng 50).
/*
chương trỡnh minh ho cỏch truy nhập trực tiếp vào bộ
nhớ của màn hỡnh
*/
#include "dos.h"
#include "conio.h"
void duarmh(char *day, int dong,I nt cotd, int cotc,I nt m_nen,
int m_chu);
void cuaso(int dongt,int cott,int dongd,int cotd,int maucs);
main()
{
cuaso(26,1,50,80,BLUE);
duarmh("Chuc mung nam moi", 28, 30, 50, MAGENTA,
WHITE);
cuaso(30,20,46,60,RED);
duarmh("Chuc mung nam moi", 40, 30, 50, MAGENTA,
YELLOW);
getch();
}
void cuaso(int dongt,int cott,int dongd,int cotd,int maucs)
/* Dung dia phan doan */
{
int i, j, p, t, dt, dd, mau;
union REGS v, r;
/* Xac dinh thuoc tinh mau */
mau = (maucs << 4)+maucs;
/*
Xac dinh trang man hinh t
va cac chi so dong tren dt, dong duoi dd
trong trang t
*/
t=(dongt-1)/25;
495
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.
dt=(dongt-1)-t*25; dd=(dongd-1)-t*25;
/* Chon t la trang hien thi */
v.h.ah=5;v.h.al=t; int86(0x10,&v,&r);
/*
Dua cac khoang trong (ma 32) va thuoc tinh mau
vao cac vi tri thich hop cua bo nho man hinh
*/
for (i=dt;i<=dd;++i)
{
p=t*4096+i*160+(cott-1)*2;
for (j=0;j<=cotd-cott;++j)
{
pokeb(0xb800,p+2*j,32);
pokeb(0xb800,p+2*j+1,mau);
}
}
}
void duarmh(char *day, int dong, int cotd, int cotc, int m_nen,
int m_chu)
/* Dung dia chi thuc */
{
int i,p,t,d,kt,mau;
char far *buf;
union REGS v,r;
/* Lay dia chi thuc cua bo nho man hinh */
buf=(char far*)MK_FP(0xb800,0);
/* Xac dinh thuoc tinh mau */
mau = (m_nen << 4)+m_chu;
/*
Xac dinh trang man hinh t
va cac chi so dong d trong trang t
*/
t=(dong-1)/25; d=dong-1-t*25;
/* Chon t la trang hien thi */
v.h.ah=5;v.h.al=t; int86(0x10,&v,&r);
p=t*4096+d*160+(cotd-1)*2;
/*
Dua cac ky tu va thuoc tinh mau
vao cac vi tri thich hop cua bo nho man hinh
*/
for (i=0;i<=cotc-cotd;++i)
{
if ((kt=day[i])==0) break;
buf[p+2*i]=kt;
buf[p+2*i+1]=mau;
}
}
Chương trỡnh 2. Biết địa chỉ của cỏc thủ tục xử lý ngắt được lưu
trữ trong bộ nh t địa chỉ 0000:0000 đến 0000:0x0400. Chương
trỡnh sẽ cho biết địa chỉ của thủ tục xử lý ngắt n (giỏ trị n nhập vào
từ bàn phớm). Số hiệu của ngắt được tớnh từ 0, nhưng n được đỏnh
số từ 1.
/*
Xac dinh dia chi cac thu tuc ngat */
#include "dos.h"
#include "conio.h" #include "stdio.h"
497
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.
main()
{
unsigned char far *p; /*p se tro toi bang vecto ngat*/
int n; /* n - so hieu ngat, n=1,2,... */
int k; /* vi tri cua ngat n trong bang vecto ngat */
unsigned seg,off;
/* p tro toi bang vecto ngat */
p=(unsigned char far*)MK_FP(0,0);
clrscr();
while(1)
{
printf("\n So hieu ngat (Bam 0 - Ket thuc): ");
scanf("%d",&n); if(n==0) break;
k=(n-1)*4;
off=p[k]+256*p[k+1]; seg=p[k+2]+256*p[k+3];
printf("\nDia chi %x:%x",seg,off);
}
}
Chương trỡnh 3. Chương trỡnh minh ho cỏch dựng con trỏ hàm
để thực hiện thủ tục khi động lại my của DOS, biết địa chỉ đầu của
thủ tục này là 0xFFFF:0000 . Chương trỡnh yu cầu nhập mật khẩu.
Nếu chọn đng (bấm ABCD và Enter) thỡ chương trỡnh tiếp tục làm
việc, nếu vào sai thỡ sẽ khởi động lại mỏy.
#include <dos.h>
#include <conio.h>
#include <iostream.h>
#include <ctype.h>
typedef void far (*HAM)(void);
void khoi_dong_may(void)
{
HAM f;
f = (HAM)MK_FP(0xFFFF,0);
f();
}
char mat_khau[]= {'A','B','C','D'};
int n = sizeof(mat_khau)/sizeof(char);
void main()
{
char i, ch, sai_mat_khau;
clrscr();
i=0;
sai_mat_khau=0;
cout << "\nMat khau: ";
while(1)
{
ch=getch();
if (ch==13) break;
cout << '*' ;
if (i<n)
{
if (toupper(ch)!=mat_khau[i])
sai_mat_khau=1;
}
else
sai_mat_khau=1;
499
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.