Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
8
Добавлен:
12.02.2016
Размер:
552.98 Кб
Скачать

Наприклад, адреса 8C65:12A4h у нормалізованій формі записується так: 8D8F:0004h. Нормалізація забезпечує однозначність запису кожної фізичної адреси й коректність усіх операцій порівняння та адресної арифметики, в тому числі пов'язаних із міжсегментними переходами.

Тому для безпомилкової роботи з блоками даних, обсяги яких перевищують обсяг сегмента, треба використовувати huge-вказівники, хоча при цьому дещо збільшується час виконання програми через додаткові операції нормалізації.

Наступна функція застосовує huge-вказівник для визначення суми всіх машиних слів адресного простору BIOS, починаючи з адреси F000:0000h до FFFF:000Fh включно; сума є унікальною для кожної серії персональних комп'ютерів і може бути використана в програмах захисту інформації.

/* Функція обчислення суми слів BIOS-області. Варіант 1 */ unsigned long Summa_BIOS (void)

{

 

 

unsigned long sum=0;

 

 

unsigned huge* ph =(unsigned huge*)0xf0000000;

/* початок області */

while (ph)

/* остання адреса - ffff:000fh */

sum += *ph++;

 

 

return sum;

 

 

}

 

 

21/37

cs-, ds-, _ssта _es-вказівники

Ефективність безпосереднього програмування оперативної пам'яті зростає у разі застосування спеціальних коротких вказівників, що оголошуються через модифікатори _cs, _ds, _ss та _es (ці специфікатори теж є службовими словами Borland C).

Короткі вказівники зберігають тільки зміщення фізичних адрес, а сегментна частина адреси береться з відповідного системного регістра: CS, DS, SS чи ES.

Для запису в сегментні регістри необхідної адреси початку сегмента використовують спеціальні псевдорегістрові змінні: _CS, _DS, _SS та _ES. Нижче подано альтернативний варіант функції обчислення суми машинних слів адресного простору BIOS, в якому для звертання до даних використано спеціальний короткий вказівник _es.

Час виконання даного варіанта функції істотно менший, ніж попереднього, де використовувався huge-вказівник.

22/37

/* Функція обчислення суми слів BIOS-області. Варіант 2 */

unsigned long BIOS_summa(void)

 

{

 

unsigned _es * p_es = (unsigned _es*)0

/* початкове зміщення */

unsigned long sum;

 

_ES=0xf000;

/* сегмент адреси BIOS-області */

for (sum=*p_es++; *p_es; p_es++)

 

sum += *p_es;

/* сума даних усього сегмента */

return sum;

 

}

 

Застосування спеціальних near-вказівників та відповідних псевдорегістрових змінних вимагає особливої обережності, оскільки в процесі виконання програми значення сегментних регістрів можуть змінюватись.

У цьому випадку, щоб уникнути формування помилкових фізичних адрес, перед наступним звертанням до даних через near-вказівники з модифікаторами _cs, _ds, _es або _ss необхідно відновити потрібне значення відповідного сегментного регістра. Нижче наведено ще два приклади застосування _es- вказівників у функціях зміни та копіювання текстових відеозображень.

23/37

4. Безпосереднє програмування відеопам'яті

Безпосереднє звертання до відеопам'яті комп'ютера є не тільки найшвидшим способом виведення інформації на екран у текстових режимах роботи відеосистеми, а й надає програмістові додаткові можливості для формування та опрацювання текстових повідомлень. Зокрема, саме таким способом (або через BIOS-переривання) можна:

зчитати символ і/або його атрибути із заданої позиції екрана;

змінити виведені на екран символи і/або їх атрибути;

вивести символ у правій нижній позиції екрана або текстового вікна, уникнувши скролінга;

записати і/або зчитати текстову інформацію з ненульової сторінки відеопам'яті.

Стандартним текстовим режимом, який автоматично встановлюється для відеоадаптерів VGA та SVGA, є режим номер 3 (25 рядків по 80 символів, 16кольорів). Вся інформація, що виводиться на екран, зберігається у спеціальній області оперативної пам'яті, яка називається відеопам'яттю. Кожен символ займає у відеопам'яті два байти: у молодшому байті зберігається код, а в старшому - атрибути даного символа (колір фону, колір і яскравість символа, прапорець блимання). Байт коду символа завжди записується у відеопам'ять за парною адресою, а байт атрибутів - за непарною (рис. 3).

24/37

ASCII-код Атрибути символа символа

парний байт непарний байт Адреси відеопам'яті

Рис. 3. Розташування символів у відеопам'яті

Відеопам'ять текстових режимів входить у загальний адресний простір центрального мікропроцесора. Початок відеопам'яті для всіх кольорових відеоадаптерів має однакову адресу B800:0000h, а для монохромних відеоадаптерів - B000:0000h.

Всю відеопам'ять текстових режимів поділено на 8 сторінок, які пронумеровано від 0 до 7. У режимі 25x80 символів обсяг відеосторінки становить 4 Кбайт (4096 байтів). У кожен момент часу на екрані може відображатись тільки одна сторінка, стандартно активною є нульова сторінка відеопам'яті.

Оскільки сторінки відеопам'яті мають фіксовані адреси, то можна безпосередньо звертатись до кожного байта екранного зображення. Зміна значень байтів, що потрапляють у межі активної відеосторінки, відразу ж відображається у відповідній зміні символів і/або атрибутів текстових повідомлень на екрані.

25/37

Для звертання до відеопам'яті використовують або far-вказівники (як це було зроблено в функції PutLastScrSmb (), наведеній у попередньому пункті), або спеціальні короткі _es-вказівники (приклади подамо далі). За сегментний компонент адреси здебільшого приймають адресу початку відеопам'яті (BSOOh для кольорових відеоадаптерів), а зміщення обчислюють за координатами символа на екрані з урахуванням номера відеосторінки:

зміщення = ((рядок -1)*80 + (позиція -1) )*2 + сторінка* 4096

Першою запишемо функцію, яка повертає код і атрибути символа, що висвітлюється у позиції col екранного рядка row і зберігається на нульовій сторінці відеопам'яті.

/* Функція зчитування символа зі заданої позиції екрана */

#include <dos.h>

 

unsigned

GetScrSymbol (int row, int col)

{

 

 

unsigned

far * addr = (unsigned far*)MK_FP(Oxb800, 0);

addr += (row-1) *80+(col-1);

/* адреса символа у відеопам'яті */

return (*addr);

/* повертає код і атрибути символа */

}

 

 

26/37

Для звертання до двобайтових слів відеопам'яті у функції GetScrSymbol () використано довгий вказівник addr. Початково addr отримує адресу першого байта відеопам'яті - ця адреса формується за допомогою бібліотечного макроса MK_FP (), а потім встановлюється на задане знакомісце.

Значенням виразу *addr є числове дане з типом unsigned, у молодшому байті якого записано ASCII-код символа, а в старшому -його атрибути.

Байти коду та атрибутів символа можна легко виділити зі значення, яке повертає функція, використовуючи порозрядні операції. Наприклад:

unsigned int scr_symb,

code, attr;

scr_symb=GetScrSymbol(symy, symx);

code = scr_symb & 0xff;

/* код символа */

attr = scr_symb >> 8;

/* атрибути символа */

Вищої швидкодії звертання до відеопам'яті можна досягти, застосовуючи спеціальні near-вказівники: char _es* та unsigned _es*. Перший з них використовують для побайтової роботи з відеопам'яттю, а другий - у разі запису/зчитування цілих слів.

Нагадаємо, що ці вказівники зберігають тільки зміщення адреси символа, а сегментну частину адреси перед звертанням до відеопам'яті треба занести в системний регістр ES.

27/37

Записана далі функція Invert () візуально виділяє задану частину рядка екрана, інвертуючи двійкові коди атрибутів символів. Параметри х1 та х2 задають номери початкового та кінцевого символів ділянки інвертування у рядку r. Просування по байтах атрибутів у функції Invert () здійснюється через вказівник patr, що має тип char _es * і зберігає зміщення адрес.

/* Функція інвертування атрибутів символів рядка */ void Invert (int r, int x1, int x2)

{

char _es *patr=(char _es*) (((r-l)*80+x1-l)*2+l) ;

_es = 0xb800;

/* сегментна частина адрес */

while (x1++ <= x2) {

 

*patr = ~ *patr;

/* інвертування байта атрибутів */

patr += 2;

 

}

 

}

 

28/37

Наступна функція ScreenCopy () виконує копіювання цілої відеосторінки (точніше, видимої на екрані частини). Сторінка, номер якої задається параметром from_page, переписується на іншу відеосторінку, що має номер to_page. Фактично функція копіює масив обсягом 25x80x2 байт, тому для неї питання швидкодії є особливо важливими.

Оскільки сегментна частина адрес двобайтового слова, що копіюється, та ділянки, в яку воно записується, однакова (це адреса сегмента відеопам'яті), то найбільш ефективним способом адресації даних буде використання двох коротких _es-вказівників pfrom та pto.

/* Функція копіювання відеосторінки */

void ScreenCopy(int from_page, int to_page)

{

unsigned _es *pfrom = (unsigned _es *)(from_page*4096); unsigned _es *pto = (unsigned _es *)(to_page*4096);

int n;

/* номер символа, що копіюється */

_ES = 0xbS00;

/* сегмент адрес */

for (n=0; n< 25*80;

n++, pfrom++, pto++)

*pto = *pfrom;

/* копіювання символів з атрибутами */

}

 

29/37

За допомогою функції ScreenCopy () можна швидко зберегти поточне екранне зображення на вільній відеосторінці, а потім відновити його на екрані, активізувавши дану відеосторінку або повторно скопіювавши її на нульову сторінку відеопам'яті.

30/37

Соседние файлы в папке ТА_Методички