Nano Hash - криптовалюты, майнинг, программирование

Обработка прерывания клавиатуры с помощью Turbo C++ 3.0

У меня есть проект. Это простая игра «Падающие блоки». Игровая зона представляет собой сетку размером 20х20. Сверху экрана будут падать блоки, а внизу герой, который будет стрелять по блокам. Цель игры состоит в том, чтобы стрелять по блокам до того, как они достигнут нижней линии. Он всегда остается в нижней строке. Всякий раз, когда пользователь нажимает кнопку пробела на клавиатуре, я генерирую пулю, и герой перемещается по нижней строке с помощью клавиш со стрелками вправо и влево. У меня нет представления об обработке этих прерываний клавиатуры с помощью Turbo C++ 3.0. Запрещено также использование "dos.h" и "int 21H". Не могли бы вы дать мне подсказки об этих проектах?

Изменить: я нашел эту информацию, но я не мог понять, как ее реализовать:

Когда клавиша нажата на клавиатуре, генерируется прерывание вместе со скан-кодом, называемым «создать код», а когда клавиша отпущена, контроллер клавиатуры генерирует «код прерывания». На ПК клавиатура управляется чипом и назначается портам с номерами 60h и 61h. Когда клавиша нажата на клавиатуре, значение сканирования помещается в регистр на 60h. Вы можете получить этот скан-код с помощью следующей команды: in al,60h После получения скан-кода вы должны сбросить клавиатуру, запрограммировав регистр команд чипа в 61h, с помощью следующих команд: in al,61h или al,82h out 61h ,al и al,7fh out 61h,al В конце каждой процедуры обработки прерывания вы очищаете служебный бит PIC, отправляя команду End Of Interrupt (EOI) 20h на порт PIC по адресу 20h. mov al,20h out 20h,al


  • Почему вы используете Turbo C++ 3.0? Ему 20 лет; с тех пор язык значительно улучшился. 03.12.2011
  • :) Вы правы, но это домашнее задание :( 03.12.2011
  • Попробуйте получить(). Символы курсора: 00 + Another_byte 03.12.2011
  • получить() ?? Я должен использовать сборку 16 бит 03.12.2011
  • @хасан: асм? Тогда почему Турбо С++? Что именно вы должны делать и что вы можете использовать, а что нет? 03.12.2011
  • Среда разработки: Turbo C++ 3.0 Язык программирования: Assembly, ANSI C 03.12.2011
  • НАЧАТЬ vitaly_filatov.tripod.com/ng/asm/asm_001.8.html в вашем дисплее/основном цикле прочитайте указатель хвоста буфера pos (0:041Ch), если он изменился с прошлого раза, прочитайте 2 байта, на которые он указывает, если код ascii равен 0x20 и с X секунд не было брошено ни одной пули, чтобы создать новый пуля. НАЧАТЬ 03.12.2011
  • Вы также можете перехватить INT 09h или INT 15h, но зачем беспокоиться :-D 03.12.2011

Ответы:


1

Файл kbdc.c:

#include <stdio.h>

extern void SetNewIrq9Isr(void);
extern void RestoreOldIrq9Isr(void);

#define SCAN_BUF_SIZE 1024

extern volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
extern volatile unsigned ScanReadIdx;
extern volatile unsigned ScanWriteIdx;

const char ScanToChar[] =
  "??1234567890-=??"
  "QWERTYUIOP[]??AS"
  "DFGHJKL;\"`?\\ZXCV"
  "BNM,./??? ";


int IsScanCodeAvailable(void)
{
  return ((ScanWriteIdx - ScanReadIdx) & (SCAN_BUF_SIZE - 1)) != 0;
}

unsigned char GetScanCode(void)
{
  unsigned char code;

  while (!IsScanCodeAvailable());

  code = ScanBuf[ScanReadIdx];

  ScanReadIdx++;
  ScanReadIdx &= SCAN_BUF_SIZE - 1;

  return code;
}

int main(void)
{
  SetNewIrq9Isr();

  printf("Press keys to see scan codes.\nPress ESC to exit.\n");

  for (;;)
  {
    unsigned code, symbol;

    code = GetScanCode();

    symbol = code & 0x7F;
    symbol = (symbol < sizeof(ScanToChar)) ? ScanToChar[symbol] : '?';

    printf("scan code: 0x%02X, symbol: \"%c\"\n", code, (char)symbol);

    if (code == 1)
    {
      break;
    }
  }

  RestoreOldIrq9Isr();
  return 0;
}

Файл kbda.asm:

GLOBAL _SetNewIrq9Isr, _RestoreOldIrq9Isr
GLOBAL _ScanBuf, _ScanReadIdx, _ScanWriteIdx

SEGMENT _TEXT PUBLIC CLASS=CODE USE16

; void SetNewIrq9Isr(void);
_SetNewIrq9Isr:
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, [es:bx]
        mov     [_pOldIrq9Isr], ax
        mov     word [es:bx], _NewIrq9Isr

        mov     ax, [es:bx + 2]
        mov     [_pOldIrq9Isr + 2], ax
        mov     [es:bx + 2], cs

        sti

        pop     es
        pop     bx
        ret

; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr:
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, [_pOldIrq9Isr]
        mov     [es:bx], ax

        mov     ax, [_pOldIrq9Isr + 2]
        mov     [es:bx + 2], ax

        sti

        pop     es
        pop     bx
        ret

_NewIrq9Isr:
        pusha
        push    ds

        mov     ax, _DATA
        mov     ds, ax

        in      al, 60h
        push    ax

        in      al, 061h
        mov     ah, al
        or      al, 080h
        out     061h, al
        mov     al, ah
        out     061h, al

        pop     ax

        ; ScanBuf[ScanWriteIdx] = scan code;
        ; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
        mov     bx, [_ScanWriteIdx]
        mov     [_ScanBuf + bx], al
        inc     bx
        and     bx, 1023
        mov     [_ScanWriteIdx], bx

        mov     al, 20h
        out     20h, al

        pop     ds
        popa
        iret

SEGMENT _DATA PUBLIC CLASS=DATA

_pOldIrq9Isr      resd    1

; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf          resb    1024
_ScanReadIdx      dw      0
_ScanWriteIdx     dw      0

Вывод:

Press keys to see scan codes.
Press ESC to exit.
scan code: 0x10, symbol: "Q"
scan code: 0x90, symbol: "Q"
scan code: 0x11, symbol: "W"
scan code: 0x91, symbol: "W"
scan code: 0x12, symbol: "E"
scan code: 0x92, symbol: "E"
scan code: 0x02, symbol: "1"
scan code: 0x82, symbol: "1"
scan code: 0x03, symbol: "2"
scan code: 0x83, symbol: "2"
scan code: 0x04, symbol: "3"
scan code: 0x84, symbol: "3"
scan code: 0x01, symbol: "?"

Теперь несколько слов о том, как это скомпилировать.

Скомпилируйте файл сборки с помощью NASM, используя nasm.exe -f obj kbda.asm. Это произведет kbda.obj. Создайте проект в Borland/Turbo C/C++ IDE, включите в него kbdc.c и kbda.obj. Убедитесь, что код будет скомпилирован в модели малой или крошечной памяти (по сути, нам нужно убедиться, что SetNewIrq9Isr() и RestoreOldIrq9Isr() будут вызываться как близлежащие функции). Скомпилируйте это.

Есть несколько предостережений.

Во-первых, ни одна из функций getc(), gets(), scanf() и т. д. не будет работать, если ее вызывать между SetNewIrq9Isr() и RestoreOldIrq9Isr(). Они повесят программу.

Во-вторых, код не отслеживает ключи shift, control и alt. Для вас это означает, что если вы запустите эту программу из IDE, нажав ctrl+F9, когда программа завершится, IDE, скорее всего, подумает, что ctrl все еще нажата. Чтобы «разблокировать» клавиатуру, вам нужно будет нажать и отпустить ctrl. То же самое может относиться к другим подобным клавишам, если они удерживаются нажатыми при запуске этой программы. Вы можете включить дополнительный код, чтобы дождаться освобождения всех shift, control и alt. Я считаю, что вы можете найти их текущее состояние в области данных BIOS.

Конечно, вы можете преобразовать файл сборки из синтаксиса NASM в синтаксис TASM и скомпилировать его с помощью TASM. Я просто использую бесплатные инструменты, Turbo C++ 1.01 и NASM.

ОБНОВЛЕНИЕ. Вот asm-файл для TASM:

PUBLIC _SetNewIrq9Isr, _RestoreOldIrq9Isr
PUBLIC _ScanBuf, _ScanReadIdx, _ScanWriteIdx

        .386

_TEXT SEGMENT PUBLIC 'CODE' USE16
        ASSUME CS:_TEXT, DS:_DATA

; void SetNewIrq9Isr(void);
_SetNewIrq9Isr PROC NEAR
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, es:[bx]
        mov     _pOldIrq9IsrOfs, ax
        mov     word ptr es:[bx], offset _NewIrq9Isr

        mov     ax, es:[bx + 2]
        mov     _pOldIrq9IsrSeg, ax
        mov     es:[bx + 2], cs

        sti

        pop     es
        pop     bx
        ret
_SetNewIrq9Isr ENDP

; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr PROC NEAR
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, _pOldIrq9IsrOfs
        mov     es:[bx], ax

        mov     ax, _pOldIrq9IsrSeg
        mov     es:[bx + 2], ax

        sti

        pop     es
        pop     bx
        ret
_RestoreOldIrq9Isr ENDP

_NewIrq9Isr PROC NEAR
        pusha
        push    ds

        mov     ax, _DATA
        mov     ds, ax

        in      al, 60h
        push    ax

        in      al, 061h
        mov     ah, al
        or      al, 080h
        out     061h, al
        mov     al, ah
        out     061h, al

        pop     ax

        ; ScanBuf[ScanWriteIdx] = scan code;
        ; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
        mov     bx, _ScanWriteIdx
        mov     _ScanBuf[bx], al
        inc     bx
        and     bx, 1023
        mov     _ScanWriteIdx, bx

        mov     al, 20h
        out     20h, al

        pop     ds
        popa
        iret
_NewIrq9Isr ENDP

_TEXT ENDS

_DATA SEGMENT PUBLIC 'DATA' USE16

_pOldIrq9IsrOfs   dw      ?
_pOldIrq9IsrSeg   dw      ?

; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf          db      1024 dup (?)
_ScanReadIdx      dw      0
_ScanWriteIdx     dw      0

_DATA ENDS

END

Вы компилируете его, используя tasm.exe /ml kbda.asm. В остальном то же самое.

03.12.2011
  • Конечно, это INT 9, IRQ 1, а не IRQ 9. Но это только название. 04.12.2011

  • 2

    Я тоже когда-то прошел подобный курс. По сути, вам нужно перехватить прерывание клавиатуры до того, как оно будет обработано системным обработчиком прерывания клавиатуры. Вам нужно создать свой собственный обработчик прерывания и привязать его к прерыванию клавиатуры. как только вы закончите свою работу, вызовите исходный обработчик прерываний системной клавиатуры.

    03.12.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..