Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



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

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

 

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

 

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

 

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

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

 


/* Функція обчислення суми слів 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-вказівників у функціях зміни та копіювання текстових відеозображень.

 


 

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

 

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

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

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

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

 

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


 

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

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

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

 

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

 

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

 

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


Для звертання до відеопам'яті використовують або 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); /* повертає код і атрибути символа */

}


Для звертання до двобайтових слів відеопам'яті у функції 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.


Записана далі функція 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;

}

}

 


Наступна функція 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; /* копіювання символів з атрибутами */

}


 

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

 





Переглядів: 1266

<== попередня сторінка | наступна сторінка ==>
Короткі та довгі вказівники. Модифікатори вказівників | Особливості звертання до динамічної пам'яті через функції Borland C

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

  

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.023 сек.