Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Низкоуровневое программирование > Assembler
Регистрация

Восстановить пароль
Повторная активизация e-mail


Донат для форума - использовать для поднятия настроения себе и модераторам

А ещё здесь можно купить рекламу за 25 тыс руб в месяц! ) пишите сюда - alarforum@yandex.ru

Ответ
 
Опции темы
Старый 27.11.2018, 17:29   #1
Alexis_777
Пользователь
 
Регистрация: 08.11.2017
Сообщений: 48
Репутация: 10
По умолчанию DOS. Работа с клавиатурой не могу понять

Здравствуйте, пытаюсь разобраться с буфером клавиатуры, прошу помочь объяснить некоторые моменты:
1. как работает процедура PrnHex, сам вникал, но так и не понял почему используются именно эти команды (особенно как работает команда das не могу понять почему вычитает именно 60 и 66)
2. также не могу понять эту часть кода: как наша клавиша загружается в ax (с прерыванием 16h и 0 функцией попроще (я вроде понял), а тут напрямую организована работа с буфером я понять не смог):
Код:
start:
;------ Очиcткa буфepa клавиатуры пepeд нaжaтием клaвиши --------------//
        push  ds  0                 ;
        pop   ds                    ;
        mov   al,byte[ds:41Ah]      ; выравниваем
        mov   byte[ds:41Ch],al      ;     ..голову и хвост буфера
 
;------ Пpoвepяeм нaличиe cимвoлa в буфepe ----------------------------//
sleep:  mov   ax,word[ds:41Ah]      ;
        mov   bx,word[ds:41Ch]      ;
        cmp   ax,bx                 ; голова равна хвосту?
        je    sleep                 ; да - циклимся..
 
;------ Читаем ASCII/SCAN нажатой клавиши -----------------------------//
        mov   si,ax                 ;
        add   si,400h               ; SI = адрес начала буфера
        lodsw                       ; берём от туда слово
        pop   ds                    ;
        cmp   al,13                 ; Enter --> выход!
        je    exit                  ;
        push  ax ax ax              ; запоминаем клавишу..
Прошу помочь объяснить или прокоментировать данные моменты, т.к. сам не могу понять((
Код взят мной с форума для ознакомления:
Код:
; fasm code.....
; Читает клавиши напрямую с буфера клавиатуры
org 100h
jmp start
 
mes0    db    13,10,' Symbol: $'
mes1    db    32,32,' Ascii: $'
mes2    db    32,32,' Scan: F0,$'
 
start:
;------ Очиcткa буфepa клавиатуры пepeд нaжaтием клaвиши --------------//
        push  ds  0                 ;
        pop   ds                    ;
        mov   al,byte[ds:41Ah]      ; выравниваем
        mov   byte[ds:41Ch],al      ;     ..голову и хвост буфера
 
;------ Пpoвepяeм нaличиe cимвoлa в буфepe ----------------------------//
sleep:  mov   ax,word[ds:41Ah]      ;
        mov   bx,word[ds:41Ch]      ;
        cmp   ax,bx                 ; голова равна хвосту?
        je    sleep                 ; да - циклимся..
 
;------ Читаем ASCII/SCAN нажатой клавиши -----------------------------//
        mov   si,ax                 ;
        add   si,400h               ; SI = адрес начала буфера
        lodsw                       ; берём от туда слово
        pop   ds                    ;
        cmp   al,13                 ; Enter --> выход!
        je    exit                  ;
        push  ax ax ax              ; запоминаем клавишу..
 
;------ Вывод данных на экран ------------------------------------------//
        mov   dx,mes0               ;
        call  Message               ;
        pop   ax                    ;
        int   29h                   ; выводим символ
 
        mov   dx,mes1               ;
        call  Message               ;
        pop   ax                    ;
        shl   ax,8
        call  PrnHex                ; выводим Ascii
 
        mov   dx,mes2               ;
        call  Message               ;
        pop   ax                    ;
        call  PrnHex                ; выводим Scan
 
        jmp   start                 ; читаем сл.клавишу..
exit:   int   20h                   ; на выход!
 
;нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
Message:                            ; мессага DOS
        mov   ah,9                  ;
        int   21h                   ;
        ret                         ;
;------------------------------------------------------------------------
PrnHex: xchg  dx,ax                 ; вывод чисел в HEX
        mov   cx,2                  ; разрядов в числе (число в AH)
@@1:    shld  ax,dx,4               ;
        rol   dx,4                  ;
        and   ax,0Fh                ;
        cmp   al,0Ah                ;
        sbb   al,69h                ;
        das                         ;
        int   29h                   ;
        loop  @@1                   ;
        ret                         ;
Alexis_777 вне форума   Ответить с цитированием
Старый 27.11.2018, 21:28   #2
jillitil
Форумчанин
 
Аватар для jillitil
 
Регистрация: 17.10.2018
Адрес: DS:SI
Сообщений: 117
Репутация: 256
По умолчанию

Цитата:
Сообщение от Alexis_777 Посмотреть сообщение
... (особенно как работает команда das не могу понять почему вычитает именно 60 и 66)
2. также не могу понять эту часть кода: как наша клавиша загружается в ax (с прерыванием 16h и 0 функцией попроще (я вроде понял), а тут напрямую организована работа с буфером я понять не смог):
1. Откуда берутся 60 и 66 см. детально как работает инструкция ДАС (Десимал Аджюст афтэр Сабстракшн): https://www.felixcloutier.com/x86/DAS.html
2. Клавиатура аппаратно дёргает прерывание 9 оно же IRQ 1, вызывая обработчик БИОСа. Он в свою очередь опрашивает клавиатуру на предмет что изменилось/нажалось/отпустилось и записывает сканкод в кольцевой буфер на 16 символов, расположенный по адресу 40:1E, при этом обновляя указатель на голову. Когда вызываете прерывание 0х16 происходит считывание с кольцевого буфера и его обновление, а не опрос клавиатуры как можно предположить.
Т.о. ваша программа вместо корректного запроса у БИОСа что было нажато последовательно, в обход нагло считывает первый сканкод и удаляет всё остальное.

Код:
INT 9 - Keyboard Interrupt (Hardware Handler)
	related memory:
	40:17 = updates keyboard flag byte 0
	40:18 = updates keyboard flag byte 1
	40:1A = queue head ptr is set to buffer start if Ctrl-Break is hit
	40:1C = updates buffer tail pointer for each keystroke; sets
		queue tail ptr is set to queue start if Ctrl-Break is hit
	40:1E = updates keyboard buffer (32 bytes)
	40:71 = updates bit 7 of the BIOS break flag if Ctrl-Break is hit
	40:72 = updates reset flag with 1234H if Ctrl-Alt-Del pressed
	40:96 = indicates keyboard type (AT,PS/2)
	40:97 = updates keyboard LED flags (AT,PS/2)
	FFFF:0 = reboot code called if Ctrl-Alt-Del pressed

	related interrupts:

	INT 5     invoked if print screen key pressed
	INT 1B    invoked if Ctrl-Break key sequence pressed
	INT 15,85 invoked on AT if system request key is pressed
	INT 15,4F invoked on machines after PC/AT with AL = scan code


	- records key press and key release via IRQ1/8259 and
	  stores scan codes in the BIOS buffer located at 40:1C
	- keyboard controllers also buffer data when interrupts are
	  disabled at the 8259 interrupt controller
	- keyboard controller is capable of storing 16 keystrokes
	  even when interrupts are disabled at the 8259
	- normal INT 9 execution takes approximately 500 microseconds;
	  at least one standard XT BIOS is known to take up to 1.3
	  milliseconds to execute
jillitil вне форума   Ответить с цитированием
Старый 27.11.2018, 22:07   #3
R71MT
Профессионал
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,339
Репутация: 1082
По умолчанию

Цитата:
Сообщение от Alexis_777 Посмотреть сообщение
особенно как работает команда das не могу понять почему вычитает именно 60 и 66
псевдо-код инструкции DAS гласит:
Код:
• если AL > 99h, или флаг(CF) стал =1,
  то сделать AL = (AL-60h);

• если AL > 09h, или флаг(AF) стал =1,
  то сделать AL = (AL-06h)
-- CF взводится в том случае,
когда ст.бит перейдёт из AL в AH (переполнение AL = 1.0000.0000).
-- AF взводится в том случае,
когда из мл.тетрады AL, бит переходит в ст.тетраду AL (0001.0000).

Теперь, смотрим на код процедуры "PrnHex"..
Здесь инструкцией SBB мы принудительно от тетрады(AL) отнимаем байт(69h).
Значит по псевдо-коду, DAS всегда будет отнимать от AL 60h, т.к. AL всегда будет >99h.
При этом по флагам будет вычитаться ещё и CF и 06h.
Код:
Пример: AL = 03h
        --------
        sbb  al,69h = (03h-69h) = 9Ah-01h(CF) = 99h
        das         = (99h-60h) = 39h-06h = 33h = ascii-код тройки

Пример: AL = 0Ah
        --------
        sbb  al,69h = (0Ah-69h) = A1h
        das         = (A1h-60h) = 41h = ascii-код символа(A)
Цитата:
Сообщение от Alexis_777 Посмотреть сообщение
как наша клавиша загружается в ax
Клавиатурный буфер может хранить коды последних 16-ти клавиш, в формате ascii/scan - итого 32 байта. Зная его адрес, можно читать инфу прямо из этого буфера. Здесь я приводил его описание: http://www.programmersforum.ru/showt...36#post1752436
__________________
Нашедшего выход - затаптывают первым..
R71MT вне форума   Ответить с цитированием
Старый 27.11.2018, 23:00   #4
Alexis_777
Пользователь
 
Регистрация: 08.11.2017
Сообщений: 48
Репутация: 10
По умолчанию

R71MT, Спасибо) Очень помогли разобрался с das)) Просто не сразу понял что по умолчанию 60 отнимается)) Из-за этого запутался))

Последний раз редактировалось Alexis_777; 27.11.2018 в 23:02.
Alexis_777 вне форума   Ответить с цитированием
Старый 27.11.2018, 23:08   #5
Alexis_777
Пользователь
 
Регистрация: 08.11.2017
Сообщений: 48
Репутация: 10
По умолчанию

Может кто-нибудь сможет объяснить как работает данная конструкция)) А то я не могу понять этого (наверное, слишком сложно для меня):
Код:
mov   si,ax                 ;
        add   si,400h               ; SI = адрес начала буфера
        lodsw                       ; берём от туда слово
        pop   ds
Просто этот пример более наглядный) Я сначала делал с прерыванием 16h и 0 функцией) Там всё просто, но не наглядно)
Alexis_777 вне форума   Ответить с цитированием
Старый 28.11.2018, 09:17   #6
R71MT
Профессионал
 
Аватар для R71MT
 
Регистрация: 16.06.2011
Сообщений: 1,339
Репутация: 1082
По умолчанию

это/всё для LODSW, который читает в AX из DS:SI
чтобы получить в SI указатель на начало буфера, сначала в AX берётся смещение с адреса 1Ah (внутри буфера), а потом к нему прибавляется база 400h.

кстати один-и-тотже адрес, можно указывать двумя способами, т.е. вот эти 2 адреса одинаковы: 0040:001Ah и 0000:041Ah - в коде выше приводится второй вариант.
__________________
Нашедшего выход - затаптывают первым..
R71MT вне форума   Ответить с цитированием
Старый 05.08.2019, 15:06   #7
Nif-naf
Форумчанин
 
Аватар для Nif-naf
 
Регистрация: 05.09.2016
Сообщений: 69
Репутация: -47
По умолчанию

Bce mak u cmpoku y4u
__________________
Немного о GoAsm.
Nif-naf вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Паскаль: Помогите понять основу для написания простейшей программы. Не могу понять суть. romanya Паскаль 2 18.03.2016 21:35
Не могу понять в чем ошибка...(работа с файлами) Lapochka Помощь студентам 0 28.04.2012 17:58
работа с циклами, не могу понять theGamer Помощь студентам 1 13.11.2011 13:08
Работа с циклом ( находим сумму) - не могу понять , где ошибся ) zipo666 Помощь студентам 3 01.11.2011 12:51
Работа с клавиатурой посредством dos.h - geninterrupt templton Общие вопросы C/C++ 3 06.04.2011 09:18


16:36.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.