Низькорівневе програмування контроллера клавіатури
Введення
Системне програмування (або програмування систем) - рід діяльності, що полягає в роботі над системним програмним забезпеченням. Основна відмінна риса системного програмування в порівнянні з прикладним програмуванням полягає в тому, що результатом останнього є випуск програмного забезпечення, що пропонує певні послуги користувачам (наприклад, текстовий процесор). Тоді як результатом системного програмування є випуск програмного забезпечення, що пропонує сервіси по взаємодії з апаратним забезпеченням (наприклад, дефрагментація жорсткого диска), що має на увазі сильну залежність таких програм від апаратної частки. Зокрема виділимо наступне: програміст повинен зважати на специфіку апаратної частки і інші властивості системи в якій функціонує програма, використовувати ці властивості, наприклад, застосовуючи спеціально оптимізований для даної архітектури алгоритм.
Зазвичай використовується низькорівнева мова програмування або такий діалект мови програмування, яка дозволяє функціонування в оточенні з обмеженим набором системних ресурсів.
Працює максимально ефективно і має мінімальне запізнювання за часом завершення.
Має маленьку бібліотеку часу виконання (RTL) або не має її взагалі.
Дозволяє пряме управління (прямий доступ) до пам'яті і логіки, що управляє.
Дозволяє робити асемблерні вставки в код.
Відладка програми може бути утруднена при неможливості запустити її у відладчику із-за обмежень на ресурси, тому може застосовуватися комп'ютерне моделювання для вирішення цієї проблеми.
Системне програмування істотно відрізняється від прикладного, що зазвичай приводить до спеціалізації програміста в одному з них.
1. Огляд низькорівневих команд
Низькорівнева мова програмування (мова програмування низького рівня) - мова програмування, близький до програмуванню безпосередньо в машинних кодах використовуваного реального або віртуального (наприклад, Java, Microsoft .NET) процесора. Для позначення машинних команд зазвичай застосовується мнемонічне позначення. Це дозволяє запам'ятовувати команди не у вигляді послідовності двійкових нулів і одиниць, а у вигляді осмислених скорочень слів людської мови (зазвичай англійських).
Інколи одне мнемонічне позначення відповідає цілій групі машинних команд, що виконують однакову дію над різними елементами пам'яті процесора. Окрім машинних команд мови програмування низького рівня можуть надавати додаткові можливості, такі як макровизначення (макроси). За допомогою директив є можливість управляти процесом трансляції машинних кодів, надаючи можливість заносити константи і літеральні рядки, резервувати пам'ять під змінні і розміщувати виконуваний код по певних адресах. Часто ці мови дозволяють працювати замість конкретних елементів пам'яті із змінними.
Як правило, використовує особливості конкретного сімейства процесорів. Загальновідомий приклад низкоуровнего мови - мова асемблера, хоча правильніше говорити про групу мов асемблера. Більш того! Для одного і того ж процесора існує декілька видів мови асемблера! Вони збігаються в машинних командах, але розрізняються набором додаткових функцій (директив і макросів).
Також до мов низького рівня умовно можна зарахувати MSIL, вживаний в платформі Microsoft .NET, Форт, Java байт-код.
Спочатку, програмісти безвариантно писали на мові асемблера. Експерименти з підтримкою устаткування в мовах високого рівня (1960s привели до появи таких, як BLISS і BCPL. Проте, мова програмування Сі, що зіграла значну роль в створенні UNIX, завоювала велику популярність і розповсюдилася повсюдно до 1980-м роках.
В даний час (2006) деяке застосування знайшлося для вбудовуваного C++. Реалізація основних часток в операційній системі і при використанні мереж потребує розробників системного ПО. Наприклад, реалізація постраничности (через віртуальну пам'ять) або драйвери пристроїв.
Термін Системне програмування безпосередньо пов'язаний з терміном Системний програміст. Це програміст, що працює (що створює, відладжує, діагностує і т. п.) над системним програмним забезпеченням.
Мова асемблера (автокод) - мова програмування низького рівня. На відміну від мови машинних кодів, дозволяє використовувати зручніші для людини мнемонічні (символьні) позначення команд. При цьому для перекладу з мови асемблера в машинний код, що розуміється процесором, потрібна спеціальна програма, звана асемблером.
Команди мови асемблера один до одного відповідають командам процесора, фактично, вони є зручнішою для людини символьною формою запису (мнемокод) команд і їх аргументів.
Крім того, мову асемблера забезпечує використання символічних міток замість адрес елементів пам'яті, які при асемблюванні замінюються на абсолютні або відносні адреси, що автоматично розраховуються, а також так званих директив (команд, що не переводяться в процесорні інструкції, а виконуваних самим асемблером).
Директиви асемблера дозволяють, зокрема, включати блоки даних, задати асемблювання фрагмента програми по умові, задати значення влучний, використовувати макровизначення з параметрами.
Кожна модель (або сімейство) процесорів має свій набір команд і відповідну йому мову асемблера. Найбільш популярні синтаксиси: Intel-синтаксис і AT&T-синтаксис.
Існують комп'ютери, що реалізовують як машинного мову програмування високого рівня, фактично в них він є «асемблером».
Майстерний програміст, як правило, здатний написати ефективнішу програму на асемблері, ніж ті, що генеруються трансляторами з мов програмування високого рівня, тобто для програм на асемблері характерне використання меншої кількості команд і звернень в пам'ять, що дозволяє збільшити швидкість і зменшити розмір програми.
Забезпечення максимального використання специфічних можливостей конкретної платформи, що також дозволяє створювати ефективніші програми з меншими витратами ресурсів.
При програмуванні на асемблері можливий безпосередній доступ до апаратури, у тому числі портів ввода-вывода, регістрів процесора, і ін.
Мова асемблера застосовується для створення драйверів устаткування і ядра операційної системи
Мова асемблера використовується для створення «прошивок» BIOS.
За допомогою мови асемблера створюються компілятори і інтерпретатори мов високого рівня, а також реалізується сумісність платформ.
Існує можливість дослідження інших програм з відсутнім початковим кодом за допомогою дизасемблера.
Але є в цієї програми і недоліки. Головна перевага асемблера практично повністю нівелюється хорошою оптимізацією в сучасних компіляторах мов високого рівня.
Через свою машинну орієнтацію («низького» рівня) людині в порівнянні з мовами програмування високого рівня складніше читати і розуміти програму, вона складається з дуже «дрібних» елементів - машинних команд, відповідно ускладнюються програмування і відладка, росте трудомісткість, велика вірогідність внесення помилок. В значній мірі зростає складність спільної розробки.
Як правило, менша кількість доступних бібліотек в порівнянні з сучасними індустріальними мовами програмування.
Відсутня переносимість програм на комп'ютери з іншою архітектурою і системою команд (окрім двійково-сумісних).
Історично можна розглядувати асемблер як друге покоління мов програмування ЕОМ (якщо першим рахувати машинний код). Недоліки асемблера, складність розробки на нім великих програмних комплексів привели до появи мов третього покоління - мов програмування високого рівня (Фортран, Лісп, Кобол, Паскаль, Сі і ін.). Саме мови програмування високого рівня і їх спадкоємці в основному використовуються в даний час в індустрії інформаційних технологій. Проте, мови асемблера зберігають свою нішу, обуславливаемую їх унікальними перевагами в частці ефективності і можливості повного використання специфічних засобів конкретної платформи.
На асемблері пишуться програми або фрагменти програм, для яких критично важливі:
- швидкодія (драйвери, ігри);
- об'єм використовуваної пам'яті (завантажувальні сектори, вбудовуване (англ. embedded) програмне забезпечення, програми для мікроконтролерів і процесорів з обмеженими ресурсами, віруси, програмні захисту).
З використанням програмування на асемблері проводяться:
- оптимізація критичних до швидкості ділянок програм написаних на мові високого рівня, такому як C++. Це особливо актуально для ігрових приставок, біля яких фіксована продуктивність, і для мультимедійних кодеків, які прагнуть робити менш ресурсоємними і популярнішими;
- створення операційних систем (ОС). ОС часто пишуть на Сі, мові, яка спеціально була створена для написання однієї з перших версій Unix. Апаратні залежні ділянки коду, такі, як завантажувач ОС, рівень абстрагування від апаратного забезпечення - HAL і ядро, часто пишуться на асемблері. Асемблерний коду в ядрах Windows або Linux зовсім небагато, оскільки автори прагнуть до переносимості і надійність, але проте він присутній. Деякі любительські ОС, такі, як MENUETOS, цілком написані на асемблері. При цьому MENUETOS поміщається на дискету і містить графічний багатовіконний інтерфейс;
- програмування мікроконтролерів (МК) і інших вбудовуваних процесорів. На думку професора Танненбаума, розвиток МК повторює історичний розвиток комп'ютерів новітнього часу. На сьогоднішній день для програмування МК вельми часто застосовують ассемблер;
- створення драйверів. Деякі ділянки драйверів, що взаємодіють з апаратним забезпеченням, програмують на асемблері. Хоча в цілому в даний час драйвери прагнуть писати на мовах високого рівня у зв'язку з підвищеними вимогами до надійності. Надійність для драйверів грає особливу роль, оскільки в Windows NT і Linux драйвери працюють в режимі ядра. Одна помилка може привести до краху системи;
- створення антивірусів і інших захисних программ;
- написання трансляторів мов програмування.
Програмування на мові асемблера характерний також для нелегальних сфер діяльності в ІТ, зокрема, з використанням асемблера проводяться:
Злом програм. «Оригінал» ПО, копії якого продаються незаконно, якщо в нім використовувалися технічні засоби захисту авторських прав, ймовірно, був зламаний за допомогою відладчика і знань мови асемблера. Це дозволяє за допомогою відладчика або дизасемблера знайти усередині коду програми функцію, відповідальну за введення коду активації або припинення роботи демонстраційної версії програми. Зломщик може змінити початковий код програми за допомогою спеціального редактора, або створити генератор ключа. Перший спосіб простіший для кінцевого користувача. Другою менш караний (УК РФ, ст. 272: до 2 років).
Створення вірусів і інших шкідливих програм (УК РФ, ст. 273: до 3 років, при тяжких наслідках до 7 років).
2. Види асемблерів
Асемблери для DOS. Найбільш відомими асемблерами для операційної системи DOS були Borland Turbo Assembler (TASM), Microsoft Macro Assembler (MASM), і Watcom Assembler (WASM). Також свого часу був популярний простою асемблер A86.
Microsoft Windows. При появі операційної системи Microsoft Windows з'явилося розширення TASM, іменоване TASM32, що дозволило створювати програми для виконання в середі Windows. Остання відома версія TASM - 5.3, що підтримує інструкції MMX, на даний момент включена в Turbo C++ Explorer. Але офіційний розвиток програми повністю зупинено.
Microsoft підтримує свій продукт під назвою Microsoft Macro Assembler. Вона продовжує розвиватися і до цього дня, останні версії включені в набори DDK. Але версія програми, направлена на створення програм для DOS, не розвивається. Крім того, Стівен Хатчессон створив пакет для програмування на MASM під назвою «MASM32».
GNU і GNU/Linux. Сюди перенаправляється запит «GNU Assembler». На цю тему потрібна окрема стаття.
Сюди перенаправляється запит «gas». На цю тему потрібна окрема стаття.
До складу операційної системи GNU входить пакет binutils, асемблер gas (GNU Assembler), що включає, використовуючий AT&T-синтаксис, на відміну від більшості інших популярних асемблерів, які використовують Intel-синтаксис.
Переносимі асемблери. Також існує відкритий проект асемблера, версії якого доступні під різні операційні системи і який дозволяє отримувати об'єктні файли для цих систем. Називається цей асемблер NASM (Netwide Assembler).
Yasm - це переписана з нуля версія NASM під ліцензією BSD (з деякими виключеннями).
flat assembler (fasm) - молодий асемблер під модифікованою для заборони перелицензирования (включаючи під GNU GPL) BSD-лицензией. Є версії для KOLIBRIOS, GNU/Linux, DOS і Microsoft Windows, використовує Intel-синтаксис і підтримує інструкції AMD64.
8051 - класична архітектура мікроконтролера. Для неї існує крос-асемблер ASM51, випущений корпорацією MetaLink. крім того багато фірм, розробники програмного забезпечення, такі як IAR або keil, представили свої варіанти асемблерів. У ряді випадків застосування цих асемблерів виявляється ефективнішим завдяки зручному набору директив і наявності середи програмування, об'єднуючу в собі професійний асемблер мова програмування СІ, відладчик і менеджер програмних проектів.
3. Програмування порту клавіатури на асемблері
3.1 Принцип роботи контроллера клавіатури і його інтерфейс з BIOS
Контроллер клавіатури працює таким чином: при натисненні або відпуску будь-якої клавіші генерується байт (так званий скан-код), перші 7 бітів якого містять порядковий номер клавіші, а останній, сьомий біт, скинутий, якщо клавіша натискувала, і встановлений, якщо відпущена. Цей скан-код можна прочитати через порт 60h (насправді усередині контроллера клавіатури є якась черга скан-кодов, а порт 60h лише відображує верхній код, але про це можна і не знати). І ще. Як тільки клавіша натискується або відпускається, викликається 9-е переривання (IRQ 1).
Але не завжди натиснення або відпуск клавіші генерує один скан-код. Наприклад, натиснення клавіші Pause викликає генерацію відразу 5-и кодів. Натиснення білої стрілки вгору викликає скан-код 72, а чорної стрілки вгору - відразу 2 коди: 224 і 72. І для кожного з цих скан-кодов викликається 9-е переривання.
Таким чином, процедура обробки клавіатури BIOS, що "сидить" на 9-м перериванні, просто аналізує значення 60h-го порту і відповідним чином модифікує буфер введення. Всі процедури BIOS далі працюють не з поточному значенням порту, а з буфером введення, що дозволяє здійснювати введення з випередженням, тобто навіть тоді, коли система зайнята.
3.2 Програмні переривання і підпрограми обробки переривань
Операційна система MS-DOS надає програмістові, що працює на мові асемблера, великий набір підпрограм, що виконують різні корисні дії. Всі ці підпрограми оформлені як підпрограми обробки переривань, і для кожної підпрограми в керівництві по MS-DOS вказаний номер відповідного нею переривання. Розрізняють апаратні і програмні переривання. Програма обробки апаратного переривання викликається, якщо процесор отримує сигнал запиту переривання від одного з системних пристроїв. Ця підпрограма повинна містити, окрім власне команд, призначених для виконання деяких дій з обробки переривання, визначених програмістом, спеціальні команди, керівники контроллерами переривань. У зв'язку з цим, подпрограммы-обработчики апаратних переривань рідко безпосередньо використовуються програмістами. Підпрограма обробки програмного переривання викликається по команді INT n процесора (n - номер переривання в системній таблиці векторів переривань). Скорочено прийнято самі підпрограми обробки переривань називати "перериваннями", хоча це не правильно. У ПЕВМ IBM РС AT всі програмні переривання підрозділяються на переривання BIOS ( підсистеми управління вводом/выводом ), переривання ОС і переривання користувача. Підпрограми обробки переривань BIOS зазвичай знаходяться в ПЗП, вони поставляються розробниками апаратури для забезпечення єдиного інтерфейсу ОС з різними типами устаткування. Основу системи переривань ОС MS DOS складає переривання з номером 21h, зване перериванням MS DOS. Це переривання забезпечує API прикладних програм (Application Programm Interface - інтерфейс прикладних програм) в середі ОС MS DOS. Залежно від значення, що міститься при виклику переривання в регістрі AH, MS-DOS виконує при цьому один з декількох десятків підпрограм, які прийнято називати функціями DOS. Для кожного переривання і кожної функції DOS в керівництві описаний набір вхідних і вихідних параметрів, що передаються через регістри, а також перелік можливих помилок.
У даній роботі будуть описані переривання і функції DOS і BIOS, що відносяться до роботи з клавіатурою і екраном ПЕВМ IBM РС AT.
3.3 Програмування клавіатури
У клавіатурі IBM РС AT є мікропроцесор, який постійно сканує її в пошуку клавіш, що натискують. Процесор клавіатури пов'язаний з контроллером клавіатури. Від контроллера на клавіатуру поступають команди управління клавіатурою, а з клавіатури коди підтвердження і коди сканування .
За винятком клавіші "PAUSE" всі останні клавіші 101- клавішної клавіатури працюють на нажатие/отжатие .При натисненні генерується код натиснення, при утриманні клавіші він повторюється через певні інтервали часу, а при відпуску генерується код віджимання. Код натиснення і код віджимання разом називаються кодами сканування клавіатури (scan-коды). Код віджимання є двобайтовим: перший байт рівний F0h, а другий байт збігається з кодом натиснення.
Є три рівні програмування підсистеми клавіатури:
1) на фізичному рівні (програмування портів 60h і 64h контроллера клавіатури);
2) за допомогою BIOS ( INT 09h, INT 16h );
3) за допомогою переривання DOS ( INT 21h ).
Для виконання введення даних з клавіатури програмістові в більшості випадків досить використовувати описані нижче функції DOS. У складніших випадках використовується переривання BIOS INT 16h, що дає деякі додаткові можливості. Максимум можливостей програміст може отримати, перехоплюючи апаратне переривання від клавіатури 09h і працюючи безпосередньо з портами ввода/вывода.
3.3.1 Використання BIOS для роботи з клавіатурою
Переривання INT 09h є апаратним перериванням, яке викликається по лінії запиту переривання IRQ1 всякий раз коли заповнюється вихідний буфер контроллера клавіатури, тобто коли поступає байт від клавіатури. Обробник даного переривання прочитує scan-код з порту 60h, перетворить scan-код в код доступний BIOS або виконує спеціальну функцію (виклик деяких інших переривань, наприклад INT 05h після натиснення Prt Scr і ін.). Обробник переривання поміщає для більшості клавіш відповідний їм в BIOS двобайтовий код в спеціальну область пам'яті - буфер клавіатури (див. табл.2). Коди деяких клавіш обробник не поміщає в буфер, інформація про їх натиснення або віджимання записується в байти стану клавіатурРозгледимо докладніше спосіб формування двобайтового коду, INT, що поміщається, 09h в буфер клавіатури. Scan-код, що отримується обробником переривання з клавіатури, відповідає деякій клавіші або комбінації клавіш. BIOS використовує для кодування інформації стандарт кодування ASCII, вживаний для всіх пристроїв, що використовують посимвольний обмін. Таблиця 3 містить коди ASCII. Разом із звичайними символами, застосовуються символи, що управляють (наприклад, CR - повернення каретки, LF - перехід на наступний рядок і т. п.). Кожному ASCII-коду BIOS ставить у відповідність деякий scan-код, що приймається з клавіатури. Якщо натискує клавіша або комбінація клавіш, якою відповідає ASCII-код, обробник переривання INT 09h поміщає в буфер scan-код клавіші і відповідний ASCII-код. Проте, навіть для 83-клавішної клавіатури IBM РС XT, є значна кількість комбінацій клавіш (і відповідно scan-кодов), що не мають відповідних еквівалентів ASCII. До них відносяться клавіші управління курсором, функціональні клавіші і ін. Для подібних клавіш в буфер поміщається спеціальний байт розширеного коду, а другий байт дорівнює нулю. Таблиця 4 містить містить розширені коди деяких клавіш. Більшість нових клавіш і їх комбінацій для 101-клавішної клавіатури (F11,F12 і ін.) кодуються аналогічним чином: для них використовуються незадіяні раніше розширені коди. Проте, для лави клавіш ("сірі" клавіші управління курсором, Delete, End і ін.), продубльованих на 101-клавішній клавіатурі, і їх комбінацій з іншими клавішами, використовується розширений код їх "оригіналів", а другий байт для таких кодів рівний E0h.
При натисненні комбінації клавіш Ctrl-Break переривання INT 09h встановлює ознака запиту по Ctrl-Break (байт 471h) і викликає переривання BIOS INT 1Bh, яке зазвичай перехоплюється MS DOS. Це переривання устанавлиает прапор CTRL-C, після чого управління передається INT 23h, яке перевіряє цей прапор, і в разі його установки викликає дострокове припинення виконання програми. Деякі функції MS DOS перевіряють натиснення CTRL-C і викликають INT 23h. Таким чином, Ctrl-Break є прапором BIOS, а CTRL-C - прапором MS DOS. Ці прапори перевіряються при виконанні функцій 01h-0Ch переривання MS DOS. Функція 33h переривання MS DOS дозволяє розповсюдити контроль по Ctrl-Break на всі функції ввода/вывода.
Переривання BIOS INT 16h дозволяє працювати з клавіатурою на декілька вищому рівні, ніж INT 09h, і нижчому рівні, ніж функції MS DOS. Фактично всі описані нижче функції DOS використовують в своїй роботі переривання 16h, проте програміст може використовувати його і безпосередньо, якщо в цьому є необхідність.
Залежно від значення в регістрі AH переривання INT 16h може виконати одну з наступних функцій.
Функція 00h виконує читання символу з буфера клавіатури. Якщо буфер порожній, функція чекає натиснення клавіші. Якщо клавіша натискує, значення коду заноситься в регістр AX. Функція повертає в Аl ASCII-код, а в AH - scan-код якщо це можливо. Інакше в AH повертається розширений код, а AL дорівнює нулю. Функція не обробляє натиснення клавіш, код яких не поміщається в буфер перериванням INT 09h (Ctrl, Shift і тому подібне), а також додаткових клавіш 101-клавішної клавіатури.
Функція 01h перевіряє, чи є символи в буфері клавіатури. Якщо є, то прапор нуля скидається ( ZF=0 ), якщо немає
- прапор встановлюється ( ZF=1 ). За наявності символу його код заноситься в регістр AX, в тому ж вигляді, як для функції 00h, проте з буфера код не віддаляється. Таким чином, якщо після цього ще раз викликати ту ж функцію, то вона ще раз прочитає той же символ.
Функція 02h записує в регістр AL перший з чотирьох байтів стану клавіатури.
Функції 10h і 11h аналогічні функціям 00h і 01h, але дозволяють обробляти також і додаткові клавіші 101-клавішної клавіатури.
Функція 12h виконує дії, аналогічні 02h, але крім того поміщає в AH другий байт стану клавіатури (див. табл.1).
Функція 03h дозволяє встановити затримку і частоту повторення для клавіатури, а функція 05h - помістити двобайтовий код в буфер клавіатури.
3.3.2 Функції DOS для роботи з клавіатурою
Функція 01h ( тобто переривання 21h при значенні AH=01h ) виконує введення з клавіатури з очікуванням натиснення клавіші, якщо буфер клавіатури порожній. Код введеного символу поміщається в регістр AL. Введений символ відображується на екрані ( эхо-отображение).
Функція 01h перевіряє також, чи не натискував користувач в ході роботи програми комбінацію клавіш Ctrl/C ( або Ctrl/Break ). В цьому випадку управління передається на підпрограму обробки Ctrl/C, яка зазвичай припиняє виконання програми користувача.
Якщо на клавіатурі натискувала одна з клавіш, яким не відповідає ніякий код ASCII, то функція 01h повертає в регістрі AL значення 0. У цих випадках слід ще раз викликати ту ж функцію, тоді буде виданий розширений код даної клавіші або комбінації клавіш.
Функція 08h працює аналогічно 01h, за винятком того, що не виконується эхо-отображение введеного символу.
Функція 07h працює аналогічно 01h, за винятком того, що не виконується эхо-отображение і не перевіряється натиснення Ctrl/C.
Функція 06h може виконувати як введення з клавіатури, так і вивід на екран. Якщо у момент виклику регістр DL містить значення 0ffh, то дана функція виконує введення без очікування. Якщо буфер не порожній, то прапор нуля ZF скидається в 0, а код символу з буфера заноситься в AL. Якщо ж буфер порожній, то встановлюється ZF=1, при цьому значення в AL не грає ролі. Таким чином, ця функція не чекає, поки натискуватиме клавіша, а відразу видає якийсь результат. Функція 06h не виконує эхо-отображения і не перевіряє натиснення Ctrl/C.
Функція 0Вh не виконує введення символу, а тільки перевіряє, чи є символи в буфері. Якщо є, то встановлюється AL=0ffh, якщо немає, то AL=00h. Виконується також перевірка на Ctrl/C.
Функція 0Аh виконує введення рядка, що буферизує, з клавіатури. При цьому символи вводяться один за іншим, як при багатократному застосуванні функції 01h, до тих пір, поки не буде введений код 0dh ( код клавіші "Enter" ), що завершує рядок. В ході введення рядка користувач може редагувати рядок, і зокрема - використовувати "забій". При введенні виконується також перевірка на Ctrl/C.
При виклику функції 0Аh потрібний, щоб в регістрі DX містив зсув ( у сегменті даних ) області пам'яті ( буфера ), в яку система помістить введений рядок. У першому байті цього буфера має бути записана його довжина, тобто максимальне число символів ( включаючи 0dh ), яке можна записати в буфер. Ця довжина має бути принаймні на 2 менше, ніж число зарезервованих байт. Після закінчення введення рядка функція поміщає в другий байт буфера дійсне число введених символів ( не рахуючи 0dh ), а зачинаючи з третього байта буфера розміщуються введені символи. Останнім завжди буде код 0dh.
Функція 0Сh спочатку очищає буфер клавіатури ( тобто "забуває" попередні натиснення клавіш ), а потім виконує будь-яку з функцій 01h, 06h, 07h, 08h або 0Аh. Номер цієї функції задається в регістрі AL.
Розглянемо приклади роботи з клавіатурою. У головній програмі для "відкриття" клавіатури потрібно викликати OpenKeyboard з параметром, який говорить, чи потрібно блокувати обробник BIOS.
void irq_keyboard(void)
{
char scan,tmp;
/* отримуємо сканкод */
scan = inb(0x60);
/* проводимо його обробку */
...
/********************************/
/* ось ця частка мені не зрозуміла */
/********************************/
/* через порт 0x61 відключають клавіатуру */
tmp = inb(0x61);
outb(tmp|0x80,0x61);
/* потім назад включають */
outb(tmp,0x61);
/********************************/
/* скидання контроллера переривань */
outb(0x20,0x20);
}
Якщо встала необхідність прямої роботи з клавіатурою, застосовується наступний метод: на 9-е переривання встановлюється "латка", яка насамперед обробляє стан порту, а потім, за бажання, передає управління старому обробникові клавіатури BIOS. Якщо управління BIOS не передається, необхідно не забути команду виведення значениа 20h а порт 20h, щоб вирішити наступні переривання від клавіатури.
IDEAL
P386
MODEL MEDIUM
STACK 400
DATASEG
PressCounter DW ?
OldKbdIntOffset DW ?
OldKbdIntSegment DW ?
CharInputFlag DB 0
ASCIICode DB 0
label RusNorm byte
DB 0,0,'1','2','3','4','5','6'
DB '7','8','9','0','-','=',0,0
DB 'й','ц','у','к','е','н','г'
DB 'ш','щ','з','х','ъ',0,0
DB 'ф','ы','в','а','п','р','о'
DB 'л','д','ж','э','Ё',0,'\'
DB 'я','ч','с','м','и','т','ь'
DB 'б','ю','.',0,'*',0,' '
ENDS
CODESEG
PROC KeyboardDriver
mov AX, DGROUP
mov DS,AX
mov [PressCounter],0
call SetKeyboardInterrupt
@@NextChar:
cmp [CharInputFlag],0
je @@NextChar
mov [CharInputFlag],0
mov DL,[ASCIICode]
mov AH,2h
int 21h
inc [PressCounter]
cmp [PressCounter],80
jb @@NextChar
call RestoreOldKeyboardInterrupt
mov AH,4Ch
int 21h
ENDP KeyboardDriver
proc KeyboardInterrupt far
pusha
push DS
mov AX,DGROUP
mov DS,AX
in AL,60h
push AX
mov AL,20h
out 20h,AL
pop AX
sti
cmp AL,39h
ja @@End
xor BX,BX
mov BL,AL
add BX, offset RusNorm
mov AL,[BX]
cmp AL,32
jb @@END
mov [ASCIICode],AL
mov [CharInputFlag],1
@@End: pop DS
popa
iret
endp KeyboardInterrupt
PROC SetKeyboardInterrupt NEAR
pusha
push ES
mov AX,0
mov ES,AX
mov AX,[ES:9*4]
mov [OldKbdIntOffset],AX
mov ax,[ES:9*4+2]
mov [OldKbdIntSegment],AX
cli
mov AX,offset KeyboardInterrupt
mov [ES:9*4],AX
mov AX,CS
mov [ES:9*4+2],AX
sti
pop ES
popa
ret
ENDP SetKeyboardInterrupt
PROC RestoreOldKeyboardInterrupt NEAR
pusha
push ES
mov AX,0
mov ES,AX
cli
mov AX,[OldKbdIntOffset]
mov [ES:9*4],AX
mov AX,[OldKbdIntSegment]
mov [ES:9*4+2],AX
sti
pop ES
popa
ret
ENDP RestoreOldKeyboardInterrupt
ENDS
END
А ось приклад розробки програми на мові С:
void interrupt (*SvInt09)(void)=NULL;
int IsBIOSActive=1;
char KeyPressed[256];
char CurKey;
void ProcessKeyb(void)
{ static PrevKey=0;
char key,IsGray;
key=inportb(0x60);
if(PrevKey==224) IsGray=0x80; else IsGray=0;
if(key!=224) /* если не признак черной клавиши"... */
{ if(key&0x80) /* клавиша отпущена */
KeyPressed[(key&0x7F)|IsGray]=0;
else /* клавиша нажата */
KeyPressed[(key&0x7F)|IsGray]=1;
}
if(!(key&0x80)) CurKey=key|IsGray;
PrevKey=key;
}
void interrupt NewInt09(void)
{ ProcessKeyb();
if(IsBIOSActive) SvInt09(); /* не блокировать BIOS? */
else outportb(0x20,0x20); /* ... нужно блокировать */
}
void CloseKeyboard(void); /* предварительное определение */
void OpenKeyboard(int LockBIOS)
{ memset(KeyPressed,0,256); CurKey=0;
SvInt09=getvect(9);
setvect(9,NewInt09);
IsBIOSActive=!LockBIOS;
atexit(CloseKeyboard);
}
void CloseKeyboard(void)
{ if(!SvInt09) return; /* клавиатура не открыта */
setvect(9,SvInt09); SvInt09=NULL;
}
Безумовно, існують і інші можливості по програмуванню контроллера клавіатури (наприклад, включение/выключение її лампочок). Проте ці можливості використовуються вже дуже рідко.
На закінчення можна привести одну корисну інформацію про обробника клавіатури BIOS. Байт пам'яті з адресою 40h:17h містить інформацію про стан спеціальних клавіш клавіатури:
Бит 7 - INSert активний
Бит 6 - CapsLock активний
Бит 5 - NumLock активний
Бит 4 - ScrollLock активний
Бит 3 - Alt натиснутий
Бит 2 - Ctrl натиснутий
Бит 1 - LeftShift натиснутий
Бит 0 - RightShift натиснутий
Висновок
Навіщо може знадобитися низькорівневе програмування клавіатури? Саме, мабуть, головне, це те, що при написанні дуже багатьох програм (в основному, звичайно, ігор) необхідно уміти "уловлювати" одночасне натиснення декількох клавіш (наприклад, одночасне натиснення стрілки вгору і пропуску і т.д). Стандартні засоби BIOS дозволяють це робити, але тільки не з будь-якими клавішами, а з функціональними (такими, як Shift, Alt і др). Насправді, у недосвідченого програміста може скластися враження, що, наприклад, Shift - клавіша особлива, оскільки вона, нібито, змінює значення останніх, тоді як насправді вона з погляду контроллера клавіатури абсолютно нічим не відрізняється від всіх останніх клавіш. Відмінності здійснюються тільки на рівні BIOS.
Інша причина прямого програмування контроллера клавіатури - це небажання програміста вирішувати BIOS обробку клавіш, що натискують, наприклад, з метою блокування роботи комбінацій Ctrl+Break або Ctrl+Alt+Del. Відмова від використання буфера введення - теж вимушена необхідність, оскільки деякі версії BIOS при натисненні на клавішу видають дуже короткий звуковий сигнал, який, звичайно, буде порить власні звуки програми (наприклад фонову музику).
Список літератури
1. Вострікова З. П. Программірованіє на мові асемблера ЄС ЕОМ. М.: Наука, 1985.
2. Галісєєв Г. В. Ассемблер для Win 32. Самовчитель. - М.: «Діалектика», 2007. - З. 368. - ISBN 978-5-8459-1197-1
3. Зубків С. В. Ассемблер для DOS, Windows і UNIX.
4. Кіп Ірвіна. Мова асемблера для процесорів Intel = Assembly Language for Intel-Based Computers. - М.: «Вільямс», 2005. - З. 912. - ISBN 0-13-091013-9
5. Магда Ю. З. Асемблер. Розробка і оптимізація Windows-приложений. СПб.: БХВ-Петербург, 2003.
6. Нортон П., Соухе Д. Язик асемблера для IBM РС. М.: Комп'ютер, 1992.
7. Владислав Пірогов. Асемблер для Windows. - СПб.: БХВ-Петербург, 2007. - 896 з. - ISBN 978-5-9775-0084-5
8. Владислав Пірогов. Асемблер і дизасемблювання.. - СПб.: БХВ-Петербург, 2006. - 464 з. - ISBN 5-94157-677-3
9. Сингер М. Міні-ЕВМ PDP-11: Програмування на мові асемблера і організація машини. М.: Мир, 1984.
10. Ськенлон Л. Персональниє ЕОМ IBM РС і XT. Програмування на мові асемблера. М.: Радіо і зв'язок, 1989.
11. Юров Ст, Хорошенко З. Assembler: учбовий курс. - СПб.: «Пітер», 2000. - З. 672. - ISBN 5-314-00047-4
12. Юров Ст І. Assembler : підручник для вузів. / 2-е видавництво СПб.: «Пітер», 2004.
13. Юров Ст І. Assembler. Практикум. : підручник для вузів / 2-е видавництво СПб.: «Пітер», 2004.
14. Юров Ст І. Assembler. Спеціальний довідник. СПб.: «Пітер», 2000.
15. Річард Саймон. Microsoft Windows API Довідник системного програміста.
16. Фрунзе А. Ст Мікроконтролери? Це ж просто! Т. 1.
1