Важная информация

User Tag List

Страница 1 из 3 123 ПоследняяПоследняя
Показано с 1 по 10 из 29

Тема: Программирование голого железа Raspberry Pi

  1. #1
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Программирование голого железа Raspberry Pi

    Я уже затрагивал тему программирования голого железа (bare metal). Заметку на эту тему опубликовал здесь же на форуме. Сейчас решил вернуться к этой теме. Но понял, что она слишком обширна и, наверное, не до конца отвечает тематике нашего форума. В общем, в этой теме буду по мере появления у меня настроения потихоньку публиковать материалы по теме, а также отвечать на вопросы, если таковые возникнут.

    Начну с того, без чего невозможно стартануть, чтобы запустить свой код на голом железе. Необходимо понимать как организован процесс загрузки Raspberry Pi. В какой файл нужно поместить свой код, с какого адреса скомпилировать и т.д. Вот ссылка на заметку Как загружается Raspberry Pi. Не стал публиковать эту информацию на форуме, чтобы не засорять его непрофильной информацией.
    Последний раз редактировалось CityAceE; 19.08.2023 в 22:10.
    С уважением, Станислав.

  2. Эти 4 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    genka_z (27.02.2024), Grand (02.09.2023), Outcast (07.03.2024), USERHOME (27.09.2023)

  3. #1
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  4. #2
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Чтобы сделать первый шаг в программировании голого железа, неплохо бы понимать, а что можно реализовать с помощью такого подхода. За одно нелишним будет понимать, что из такого софта уже существует.

    Для этого я подготовил небольшой обзор, который даст представление о bare metal софте под Raspberry Pi.

    В обзоре есть упоминание эмулятора Спектрума. Также обратите внимание на демку Pi on Fire, в которой звуковое сопровождение написано под два AY.

    Обзор bare metal программ для Raspberry Pi

    P.S.В этой заметке я написал, что полноценного эмулятора Raspberry Pi не существует, но на самом деле эмулировать Raspberry Pi можно, но с некоторыми оговорками. Об этом я расскажу чуть позже.

    Вот пример bare metal игры, написанной на чистом ассемблере:
    Последний раз редактировалось CityAceE; 18.08.2023 в 15:48.
    С уважением, Станислав.

  5. Эти 4 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    ALS (18.08.2023), creator (18.08.2023), Oleg N. Cher (18.08.2023), Outcast (07.03.2024)

  6. #3
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    В обзор добавил информацию об ещё одном эмуляторе ZX Spectrum - πBacteria. Эмулятор написан на ассемблере, а исходники доступны.

    С уважением, Станислав.

  7. #4
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Программа "Hello, World!"

    Для тех, кто хотел бы сделать первый шаг и, возможно, немного поэкспериментировать, приведу последовательность действий, которые необходимо произвести, чтобы запустить простейшую программу на ассемблере на голом железе под эмулятором. Здесь я буду описывать процесс для Windows.

    Итак, для начала скачайте и установить эмулятор QEMU. Последнюю сборку под Windows можно скачать отсюда: https://qemu.weilnetz.de/w64/
    Также нам потребуется кросс-ассемблер FASMARM для Windows. Скачать его можно отсюда: https://arm.flatassembler.net/

    Далее скопируйте текст программы в блокнот и сохраните в файл HelloWorld.s:
    Код:
    org 0x6001000
        mov r0, 0x9000  ; Загружаем в регистр r0 адрес консоли 0x10009000, вначале младшую половину
        movt r0, 0x1000    ; а потом старшую половину
        adr r1,text    ; Загружаем в регистр r1 адрес начала текста
        mov r2,0    ; Обнуляем счётчик в регистре r2
    loop:
        ldrb r3,[r1,r2] ; Загружаем в регистр r3 код следующего символа надписи
        str r3,[r0]    ; Выводим в консоль код символа из регистра r3
        add r2,1    ; Увеличиваем счётчик на единицу
        cmp r3,10    ; Сравниваем код символа с кодом перевода строки
        bne loop    ; Переходим к следующему символу, если код символа не равен коду перевода
    finish:
        b finish    ; В конце программы зацикливаем строку саму на себя
    text:
        db "Hello, World!", 10
    Сам я лично вместо стандартного блокнота пользуюсь Notepad++ и подсветкой синтаксиса, которую сделал похожей на привычный мне PyCharm:



    Распакуйте архив с ассемблером. Оттуда понадобится только исполняемый (.exe) файл. И положите рядом с ним ваш HelloWorld.s. Теперь всё готово для компиляции! Открываем консоль, переходим в папку с ассемблером и нашим файлом, и подаём команду:
    Код:
    fasmarm HelloWorld.s


    На выходе получаем файл HelloWorld.bin объёмом 54 байта. Теперь осталось только его запустить под эмулятором. Для запуска подаём такую команду в консоли:
    Код:
    "c:\Program Files\qemu\qemu-system-arm.exe" -M vexpress-a9 -serial stdio -kernel HelloWorld.bin
    И наслаждаемся результатом:



    Появились вопросы? Задавайте!
    Последний раз редактировалось CityAceE; 24.08.2023 в 15:32.
    С уважением, Станислав.

  8. Эти 3 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    andrews (28.08.2023), creator (26.08.2023), Outcast (07.03.2024)

  9. #5
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Система команд Thumb

    Итак, давайте потихоньку двигаться дальше. Предлагаю внести в пример из предыдущего сообщения небольшие изменения. А именно, после строки с директивой org добавить ещё три строки:
    Код:
        blx start
        thumb
    start:
    То есть по итогу должно получиться вот так:


    Так как мы что-то добавили в программу, то исполняемый код должен увеличиться на несколько байт. Давайте скомпилируем и проверим. И что мы видим? Исполняемый код стал объёмом 46 байт, то есть ещё короче чем был! А был, напомню, 54 байта.

    Что же произошло? Давайте попробуем разобраться и дизассемблировать код обеих вариантов с помощью популярного дизассемблера IDA Pro.

    Вот так выглядит код первоначального варианта (54 байта):



    Всё совпадает с ассемблерным текстом! (На команду MOV R0 не обращайте внимания. По умолчанию IDA для простоты восприятия заменяет некоторые последовательности команд в метакоманды. Вот и здесь она заменила две команды загрузки регистра R0 по половинкам (MOV и MOVT) в одну длинную загрузку, которая на самом деле отсутствует в наборе команд процессоров ARM. Где-то в настройках IDA Pro это можно отключить и тогда всё будет отображаться, как есть.)

    А вот так выглядит дизассемблер модифицированного варианта (46 байт):



    И тоже всё совпадает, и даже дополнительная команда BLX появилась. Но при этом код стал короче!

    А произошло следующее: директивой thumb мы дали команду ассемблеру все дальнейшие команды вместо стандартного 32-х битного режима ассемблировать в 16-битном режиме thumb. А, собственно, командой BLX мы дали понять процессору, что код, на который будет осуществлён дальнейший переход, будет исполняться в режиме thumb.

    В режиме thumb все команды, в отличие от 32-х битного режима, кодируются только двумя байтами. В результате исполняемый код такой программы становится более компактным. И всё было бы отлично, если бы не кое-какие ограничения. И прежде всего это ограниченный набор команд - их всего лишь 36. Есть и другие ограничения, но сейчас не будем на них останавливаться.

    Что касается меня, то режим thumb привлёк моё внимание именно ограниченным набором команд. Дело в том, что за долгую историю архитектуры ARM было выпущено несколько поколений процессоров. Для них было придумано большое количество команд, у каждой из которых есть свои особенности. Разобраться и изучить их все довольно проблематично. А здесь же мы имеем только 36 команд, с помощью которых можно запрограммировать практически любое действие. При этом, если вам когда-нибудь вдруг станет тесно в рамках thumb, вы всегда сможете перейти на 32-х битную систему команд без необходимости что-то менять в своём коде. Наверное, здесь можно привести аналогию с процессорами i8080 (КР580ВМ80А) и Z80. Если писать код для процессора i8080 (аналогия с thumb), то код будет работать и на i8080, и на Z80. Но если вам становится тесно, то вы можете начать использовать дополнительные регистры и команды процессора Z80 (аналогия с 32-х битным режимом ARM), но тогда уже потеряете совместимость с i8080.

    В конце хочу привести полный список из 36 команд процессоров ARM в режиме thumb:

    Мнемоника Команда Пример Эквивалент кода ARM
    1 ADC Сложение с учетом переноса ADC Rd, Rs ADCS Rd, Rd, Rs
    2 ADD Сложение ADD Rd, Rs, Rn ADD Rd, Rs, Rn
    3 AND Логическое "И" AND Rd, Rs ANDS Rd, Rd, Rs
    4 ASR Арифметический сдвиг вправо ASR Rd, Rs MOVS Rd, Rd, ASR Rs
    5 B Безусловный переход B label B label
    6 BCC Переход по условию CC BCC label BCC label
    7 BIC Сброс битов (маскирование) BIC Rd, Rs BICS Rd, Rd, Rs
    8 BL Переход со ссылкой BL label BL label
    9 BX Переход и смена режима ядра BX Hs BX Hs
    10 CMN Сравнение с отрицанием CMN Rd, Rs CMN Rd, Rs
    11 CMP Сравнение CMP Rd, #Offset8 CMP Rd, #Offset8
    12 EOR Исключающее "ИЛИ" EOR Rd, Rs EORS Rd, Rd, Rs
    13 LDMIA Групповая загрузка регистров LDMIA Rb!, {Rlist} LDMIA Rb!, {Rlist}
    14 LDR Загрузка целого слова LDR Rd, [PC, #lmm] LDR Rd, [PC, #lmm]
    15 LDRB Загрузка байта LDRB Rd, [Rb, Ro] LDRB Rd, [Rb, Ro]
    16 LDRH Загрузка полуслова LDRH Rd, [Rb, #lmm] LDRH Rd, [Rb, #lmm]
    17 LSL Логический сдвиг влево LSL Rd, Rs, #Offset5 MOVS Rd, Rs, LSL #Offset5
    18 LDRSB Загрузка байта со знаком LDRSB Rd, [Rb, Ro] LDRSB Rd, [Rb, Ro]
    19 LDRSH Загрузка полуслова со знаком LDRSH Rd, [Rb, Ro] LDRSH Rd, [Rb, Ro]
    20 LSR Логический сдвиг вправо LSR Rd, Rs MOVS Rd, Rd, LSR Rs
    21 MOV Пересылка MOV Rd, #Offset8 MOVS Rd, #Offset8
    22 MUL Умножение MUL Rd, Rs MULS Rd, Rs, Rd
    23 MVN Пересылка с инверсией MVN Rd, Rs MVNS Rd, Rs
    24 NEG Инверсия (побитовое "НЕ") NEG Rd, Rs RSBS Rd, Rs, #0
    25 ORR Логическое "ИЛИ" ORR Rd, Rs ORRS Rd, Rd, Rs
    26 POP Извлечение регистров из вершины стека POP {Rlist} LDMIA R13!, {Rlist}
    27 PUSH Размещение регистров в вершине стека PUSH {Rlist} STMDB R13!, {Rlist}
    28 ROR Циклический сдвиг вправо ROR Rd, Rs MOVS Rd, Rd, ROR Rs
    29 SBC Вычитание с переносом SBC Rd, Rs SBCS Rd, Rd, Rs
    30 STMIA Групповое сохранение регистров STMIA Rb!, {Rlist} STMIA Rb!, {Rlist}
    31 STR Сохранение целого слова STR Rd, [Rb, Ro] STR Rd, [Rb, Ro]
    32 STRB Сохранение байта STRB Rd, [Rb, Ro] STRB Rd, [Rb, Ro]
    33 STRH Сохранение полуслова STRH Rd, [Rb, Ro] STRH Rd, [Rb, Ro]
    34 SWI Программное прерывание SWI Value8 SWI Value8
    35 SUB Вычитание SUB Rd, Rs, Rn SUBS Rd, Rs, Rn
    36 TST Побитовая проверка TST Rd, Rs TST Rd, Rs

    Rs - Регистр-источник (Register source)
    Rd - Регистр-приёмник (Register destination)
    Ro - Отступ (Register offset)
    Rn - Второй аргумент в арифметических операциях
    Rlist - Список регистров
    Последний раз редактировалось CityAceE; 24.08.2023 в 15:18.
    С уважением, Станислав.

  10. Эти 5 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    ALS (24.08.2023), creator (26.08.2023), Oleg N. Cher (25.08.2023), Outcast (07.03.2024), svofski (24.08.2023)

  11. #6
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Регистры процессоров ARM

    В предыдущем сообщении я привёл список команд, с помощью которых можно запрограммировать любую процедуру. Однако осталось кое-что, о чём следует иметь представление, прежде чем делать свои первые шаги в программирования на ассемблере ARM. И речь идёт о регистрах процессора.

    В отличие от Спектрума тут всё довольно просто - у процессоров есть 16 регистров, которые обозначаются как r0-r15, а также два специальных регистра - CPSR и SPSR. Собственно, на этом всё

    Но, на самом деле, как обычно, есть нюансы. Их много, но я остановлюсь лишь не некоторых из них.

    Начнём с регистров общего назначения. Как уже было написано выше их всего 16. И все они 32-х битные, то есть каждый из них может хранить 4 байта, и, соответственно, процессор за одну команду может оперировать с таким объёмом данных. Однако не всеми регистрами Rxx вы можете распоряжаться, как заходите. Некоторые из них имеют специальное назначение, а некоторые и вовсе недоступны из режима Thumb.

    Первые 8 регистров (r0-r7) - это регистры общего назначения, которые доступны из любого режима процессора, не важно Thumb (CODE16) это или ARM (CODE32). Пять следующих регистров (r8-r12) доступны только из режима ARM. Остаётся ещё три регистра, которые отведены под специальные задачи и помимо традиционного обозначения r13-r15 имеют псевдонимы.

    r13 (SP) - это указатель стека, такой же как на ZX Spectrum, только разрядностью побольше.
    r14 (LR) - это, так называемый, регистр связи. Он необходим, например, для вызова подпрограмм. На ZX Spectrum, когда мы вызываем подпрограмму по команде CALL, адрес возврата записывается на стек. В процессорах же АРМ всё происходит несколько иначе - адрес возврата записывается не на стек, а как раз в этот самый регистр связи. Причём, если вы потом из подпрограммы вызовете ещё одну подпрограмму, то адрес возврата затрёт предыдущий и из первой подпрограммы вы уже не сможете вернуться. Вот поэтому при вложенных подпрограммах необходимо самому заботится о сохранении регистра LR и его своевременном восстановлении.
    r15 (PC) - это программный счётчик. Тут без особенностей, он такой же, как на Z80.

    Вот так будет нагляднее:



    CPSR (Current Program Status Register) - это регистр, который хранит флаги, а также информацию для обработки прерывания.
    SPSR (Saved Program Status Register) - этот регистр хранит копию CPSR при обработке прерывания. Опять же, для нас этот регистр пока неактуален, как и всё, что связано с прерываниями.

    На прерываниях останавливаться не будем, а вот про флаги поговорить, безусловно, стоит. В общем-то почти все флаги нам знакомы по процессору Z80:

    Q (Saturation) - насыщение/переполнение в DSP-операциях (для нас пока неактуально)
    V (oVerflow) - переполнение (знаковое)
    C (Carry) - перенос бита (беззнаковый)
    Z (Zero) - нулевой результат (равенство)
    N (Negative) - отрицательное значение (бит 31 установлен)

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

    Предикат
    Отрицание Флаги Комментарий
    EQ NE Z ==
    CS / HS CC / LO C >= (беззнаковое)
    MI PL N < 0
    VS VC V переполнение
    HI LS zC > (беззнаковое)
    GE LT NV || nv >= (знаковое)
    GT LE NzV || nzv > (знаковое)
    AL - - Безусловная команда

    Как и в Z80, здесь есть команда условного перехода, в качестве суффикса которой как раз используются обозначения условий из таблицы. И мы в программе "Hello, World!" уже использовали условный переход:

    Код:
        cmp r3,10    ; Сравниваем код символа с кодом перевода строки
        bne loop    ; Переходим к следующему символу, если код символа не равен коду перевода
    В первой строчке мы сравниваем содержимое регистра r3 с числом 10. А во второй команде, при условии BNE (branch if not equal - bne) мы переходим на метку loop. На Спектруме аналогом этой команды была бы команда jr nz,loop.

    Любопытно, но по умолчанию почти все команды никак не затрагивают флаговый регистр. Вы можете до посинения вызывать команду SUB R1,1 и ожидать, что рано или поздно произойдёт обнуление регистра, сторожа его командой BEQ:
    Код:
        mov r1,100
    loop:
        sub r1,1
        beq exit  ; Данная команда никогда не сработает
        b  loop
    exit:
    Однако вас будет ожидать разочарование - команда BEQ никогда не сработает. А всё потому, что флаговый регистр не будет реагировать на результат команды SUB. И вот чтобы флаговый регистр всё-таки отреагировал, вам необходимо явно указать, что вам требуется реакция флагового регистра. Делается это довольно просто - суффиксом S. То есть вместо SUB, вам нужно использовать команду SUBS.

    Код:
        mov r1,100
    loop:
        subs r1,1
        beq exit  ; Команда сработает, когда в R1 будет 0
        b  loop
    exit:
    В качестве бонуса, суффикс S вы можете использовать даже в команде MOV. То есть вот такая команда BEQ вполне себе сработает после MOVS:

    Код:
        movs r1,0
        beq label  ; Данная команда сработает
    Но и это еще не всё! Помимо команд условного перехода практически любая команда может быть исполнена по условию, заданному в суффиксе. Например, команда MOVEQ будет выполнена только, если результат предыдущей операции, влияющий на флаговый регистр, будет равен нулю:

    Код:
        movs r1,0
        moveq r2,1  ; Команда сработает
        movne r2,2  ; Команда не сработает
    Правда, если вы дизассемблируете код вот с такими условными командами, то вы увидите, что компилятор добавил к ним одну или несколько команд IT, которые как раз позволяют процессору эти самые условия обрабатывать. То есть суффикс с условием транслируется в некоторую конструкцию команд IT. Это вас не должно никак беспокоить, если только вы не бьётесь за каждый байт исполняемого файла.

    Думаю, что для начала этой информации о регистрах процессоров ARM вам будет достаточно.
    Последний раз редактировалось CityAceE; 25.08.2023 в 10:18.
    С уважением, Станислав.

  12. Эти 3 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    creator (26.08.2023), Oleg N. Cher (25.08.2023), Outcast (07.03.2024)

  13. #7
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Демо FreeFulll

    Вывод в консоль фразы "Hello, World!" - это, конечно, хорошо, но малоинтересно. Гораздо интереснее что-то графическое, цветастое, с анимацией и чтобы ещё попроще было в коде. И такая штука у меня есть для вас! Крохотная демка под названием FreeFull. Размер исполняемого файла всего лишь 254 байта, но выглядит всё довольно эффектно!



    Не поленитесь, скомпилируйте и запустите её самостоятельно! Сделать это можно по аналогии с упомянутым примером "Hello, Wolrd!".

    >> Вот << прямая ссылка на исходный текст.

    Изучить этот исходник будет довольно интересно. Несмотря на то, что там всего лишь 94 строки текста, вы сможете увидеть, например, как инициализируется графический экран и как затем на нём попиксельно формируется картинка.

    Интересно, хоть один человек найдётся, который отважится на компиляцию и запуск? А то у меня складывается ощущение, что я тут всё это сам себе рассказываю
    Последний раз редактировалось CityAceE; 25.08.2023 в 18:57.
    С уважением, Станислав.

  14. Эти 2 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    creator (26.08.2023), Oleg N. Cher (27.08.2023)

  15. #8
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Адаптировал демку из предыдущего сообщения к железу Raspberry Pi и запустил её на реальных Raspberry Pi Zero, 1 и 2:

    С уважением, Станислав.

  16. Эти 2 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    creator (27.08.2023), Oleg N. Cher (27.08.2023)

  17. #9
    Administrator Аватар для CityAceE
    Регистрация
    13.01.2005
    Адрес
    г. Москва
    Сообщений
    4,574
    Записей в дневнике
    7
    Спасибо Благодарностей отдано 
    399
    Спасибо Благодарностей получено 
    1,207
    Поблагодарили
    394 сообщений
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Итак, двигаемся дальше. Буквы в терминале - хорошо, красивая картинка на экране - ещё лучше! Но хочется какого-то интерактива. И вот здесь не всё так просто, как хотелось бы. Но об этом чуть ниже. А пока предлагаю вам текст короткой программы, которая опрашивает клавиатуру и выводит в терминал код нажатой клавиши:

    Код:
    org 0x6001000
        blx start
        thumb
    
    start:
    ; Опрашиваем клавиатуру
        movw r0,0x6004  ; Keyboard Status Register
        movt r0,0x1000
        ldrb r1,[r0]
        and r1,0x10
        cmp r1,0x10
        bne finish
        movw r0,0x6008  ; Keyboard Data
        movt r0,0x1000
        ldrb r1,[r0]
        and r1,0xff
    
    ; Преобразуем байт в ASCII-строку в HEX-представлении
        adr r2,key_code+1
        mov r3,2
        mov r0,r1
    hex_convert:
        and r1,0xf
        cmp r1,0xa
        addcs r1,0x7
        add r1,0x30
        strb r1,[r2]
        sub r2,1
        lsr r1,r0,4
        subs r3,1
        bne hex_convert
    
    ; Выводим строку в консоль
        movw r0,0x9000  ; Адрес консоли 0x10009000
        movt r0,0x1000
        ldrb r1,[key_code]
        strb r1,[r0]
        ldrb r1,[key_code+1]
        strb r1,[r0]
        ldrb r1,[key_code+2]
        strb r1,[r0]
     
    finish:
        b start
    
    key_code:
        db "00 "
    Результат работы программы:



    В эмулируемом компьютере клавиатура подключена с помощью MMIO (Memory-mapped I/O) контроллера PL050, порты которого смотрят прямо в память, а базовым является адрес 0x10006000:

    Address Type Description
    Base + 0x00 rw Control register.
    Base + 0x04 r Status register.
    Base + 0x08 rw Received data (read)/ Data to be transmitted (write).
    Base + 0x0c rw Clock divisor register.
    Base + 0x10 r Interrupt status register.


    А это значения битов статусного регистра:

    Bits Name Description
    0 KMID This bit reflects the status of the KMIDATAIN line after synchronizing.
    1 KMIC This bit reflects the status of the KMICLKIN line after synchronizing and sampling.
    2 RXPARITY This bit reflects the parity bit for the last received data byte (odd parity).
    3 RXBUSY This bit indicates that the PrimeCell KMI is currently receiving data. 0 = idle, 1 = receiving data.
    4 RXFULL This bit indicates that the receiver register is full and ready to be read. 0 = receive register empty, 1 = receive register full, ready to be read.
    5 TXBUSY This bit indicates that the PrimeCell KMI is currently sending data. 0 = idle, 1 = currently sending data.
    6 TXEMPTY This bit indicates that the transmit register is empty and ready to transmit. 0 = transmit register full, 1 = transmit register empty, ready to be written.
    7 - Reserved. Read unpredictable.


    Здесь используется стандартный набор 2 скан-кодов AT-клавиатуры:

    PS/2 keyboard scan codes (scan code set 2)


    KEY MAKE BREAK ----- KEY MAKE BREAK ----- KEY MAKE BREAK
    A 1C F0,1C 9 46 F0,46 [ 54 FO,54
    B 32 F0,32 ` 0E F0,0E INSERT E0,70 E0,F0,70
    C 21 F0,21 - 4E F0,4E HOME E0,6C E0,F0,6C
    D 23 F0,23 = 55 FO,55 PG UP E0,7D E0,F0,7D
    E 24 F0,24 \ 5D F0,5D DELETE E0,71 E0,F0,71
    F 2B F0,2B BKSP 66 F0,66 END E0,69 E0,F0,69
    G 34 F0,34 SPACE 29 F0,29 PG DN E0,7A E0,F0,7A
    H 33 F0,33 TAB 0D F0,0D U ARROW E0,75 E0,F0,75
    I 43 F0,43 CAPS 58 F0,58 L ARROW E0,6B E0,F0,6B
    J 3B F0,3B L SHFT 12 FO,12 D ARROW E0,72 E0,F0,72
    K 42 F0,42 L CTRL 14 FO,14 R ARROW E0,74 E0,F0,74
    L 4B F0,4B L WIN E0,1F E0,F0,1F NUM 77 F0,77
    M 3A F0,3A L ALT 11 F0,11 KP / E0,4A E0,F0,4A
    N 31 F0,31 R SHFT 59 F0,59 KP * 7C F0,7C
    O 44 F0,44 R CTRL E0,14 E0,F0,14 KP - 7B F0,7B
    P 4D F0,4D R WIN E0,27 E0,F0,27 KP + 79 F0,79
    Q 15 F0,15 R ALT E0,11 E0,F0,11 KP EN E0,5A E0,F0,5A
    R 2D F0,2D APPS E0,2F E0,F0,2F KP . 71 F0,71
    S 1B F0,1B ENTER 5A F0,5A KP 0 70 F0,70
    T 2C F0,2C ESC 76 F0,76 KP 1 69 F0,69
    U 3C F0,3C F1 05 F0,05 KP 2 72 F0,72
    V 2A F0,2A F2 06 F0,06 KP 3 7A F0,7A
    W 1D F0,1D F3 04 F0,04 KP 4 6B F0,6B
    X 22 F0,22 F4 0C F0,0C KP 5 73 F0,73
    Y 35 F0,35 F5 03 F0,03 KP 6 74 F0,74
    Z 1A F0,1A F6 0B F0,0B KP 7 6C F0,6C
    0 45 F0,45 F7 83 F0,83 KP 8 75 F0,75
    1 16 F0,16 F8 0A F0,0A KP 9 7D F0,7D
    2 1E F0,1E F9 01 F0,01 ] 5B F0,5B
    3 26 F0,26 F10 09 F0,09 ; 4C F0,4C
    4 25 F0,25 F11 78 F0,78 ' 52 F0,52
    5 2E F0,2E F12 07 F0,07 , 41 F0,41
    6 36 F0,36 PRNT
    SCRN
    E0,12,
    E0,7C
    E0,F0,
    7C,E0,
    F0,12
    . 49 F0,49
    7 3D F0,3D SCROLL 7E F0,7E / 4A F0,4A
    8 3E F0,3E PAUSE E1,14,77,
    E1,F0,14,
    F0,77
    -NONE-
    [свернуть]


    То есть каждая клавиша имеет скан-коды для нажатия (make) и для отпускания (break). Так, при нажатии клавиши "A" мы получаем скан-код 0x1C, и продолжаем получать его вплоть до отпускания клавиши. А в момент отпускания генерируется двухбайтный скан-код 0xF0, 0x1C.

    Теперь для тренировки вы можете попробовать подправить программу таким образом, чтобы она выводила не скан-код клавиши, а непосредственно её значение.
    Последний раз редактировалось CityAceE; 28.08.2023 в 09:43.
    С уважением, Станислав.

  18. Эти 2 пользователя(ей) поблагодарили CityAceE за это полезное сообщение:

    Outcast (07.03.2024), parallelno (27.08.2023)

  19. #10
    Master
    Регистрация
    15.02.2015
    Адрес
    г. Могилёв, Беларусь
    Сообщений
    835
    Спасибо Благодарностей отдано 
    12
    Спасибо Благодарностей получено 
    98
    Поблагодарили
    65 сообщений
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Для программирования голого распберри есть версия Лазаруса -Ультибо.
    http://www.freepascal.ru/forum/viewtopic.php?t=11237
    https://ultibo.org/wiki/Main_Page
    https://ultibo.org/
    Есть графический движок для Ультибо https://bshark.org/
    ¡Un momento, señor fiscal!


  20. Эти 3 пользователя(ей) поблагодарили Smalovsky за это полезное сообщение:

    CityAceE (27.08.2023), Oleg N. Cher (27.08.2023), svofski (29.08.2023)

Страница 1 из 3 123 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Raspberry Pi 400 - альтернатива ZX Spectrum Next?
    от CityAceE в разделе Зарубежные компьютеры
    Ответов: 26
    Последнее: 03.11.2020, 23:48
  2. Эмуляторы ZX Spectrum для Raspberry Pi
    от CityAceE в разделе Эмуляторы
    Ответов: 32
    Последнее: 01.10.2019, 18:23

Ваши права

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