- ВУ может быть не сложнее трёх проводов с кнопкой, а может быть целым специализированным компьютером со своим процессором, памятью, регистрами и т. п.
А может вообще быть иерархическим. То есть мы программируем периферию, встроенную в процессор, она по какому-то протоколу общается с микросхемой-переходником, и уже та управляет устройством. Простейший пример - то, что называется "ногодрыг". Встроенная периферия - GPIO (по сути, отображение отдельных битов прямо на ножки микросхемы), ручная реализаци на нем, скажем, SPI, по которому подключен диспелей.
- Логику сложных ВУ надо уметь программировать непосредственно при работе (а что вообще в них за процессоры стоят?)
win-принтеры, модемы и прочие "безмозглые" устройства, куда драйвер сам заливает прошивку
- Соответствие конкретных адресов конкретным интерфейсам ВУ определяется как-то
"как-то" это "как скажет производитель". Карта памяти в помощь. Картинку я присылал.
- MMIO-регистры бывают:
Здесь можно сделать отсылку на непрямые эффекты в CSR. Вот в MMIO запись числа в регистр передачи обычно заставляет периферию начать передачу. Чтение из регистра приемника сбрасывает флаг "принят байт". Для регистров GPIO (грубо говоря, отображение 32-битного машинного слова напрямую на торчащие из процессора проводки) нередки специальные регистры вроде toggle (запись вызывает переключение с 0 на 1 и наоборот, чтение всегда возвращает ноль), запись по маске и другие хитрые штуки. Если в CSR это экзотика, которой следует избегать, то в MMIO это основной функционал. MMIO без побочных эффектов - просто память.
- Замечание: пункт «бессмысленное ожидание»
Даже без прерываний это решается конечным автоматом.
Георгий Курячий Предполагаю, что — нет не решается.
while(1){
do_smth();
if( device_is_ready() )send_byte();
do_smth();
}Георгий Курячий Ну и вот. Во-первых, это вырожденный конечный автомат из одного стостояния, а во-вторых он не решил проблему, а только ухудшил её. Теперь вместо одного вызова функции do_smth() у нас есть два, причём буквально первый вызов следует сразу после второго, во вторых — это вечный цикл (в примере был предусмотрен выход из поллинга), в-третьих — оперативность работы как зависела от скорости do_smth(), так и зависит, если do_smth() работает час, результат мы увидим только через час, а не по готовности.
И да, такой подход нередко используется даже при наличии прерываний. Например, для той же матричной клавиатуры, когда при каждом вызове функции опроса обрабатывается следующая строка. Ну просто клавиатура штука слишком медленная и нетребовательная, чтобы тратить на нее целый таймер. С матричным дисплеем примерно тоже самое. Иногда даже с USB (хотя казалось бы, интерфейс крайне быстрый, надо реагировать соответственно... но вот не всегда).
- В учебно-тренировочных целях протокол управления цифровым блоком сделан максимально неудоб-приближенным к обычной практике разработки таких устройств.
Недожали. В реальности у того же семисегментника еще и сегменты могут быть в хаотическом порядке по управляющему регистру разбросаны. А то и по нескольким. Это не говоря про динамическую индикацию.
- Например, при выполнении следующего кода:
Магические чиселки!
.eqv DIGLAB, 0xFFFF0010 .eqv LEDS1, 0 .eqv LEDS2, 1 .eqv KBD_CTL, 2 .eqv KBD_IE, 3 .eqv KBD_STAT, 4 li t0, DIGLAB li t1, 0xDB sb t1, LEDS1(t0) li t1, 0x66 sb t1, LEDS2(t0)
- Итак, для того, чтобы просканировать, нажата ли какая-нибудь клавиша в ряду «0-1-2-3», надо:
Вот здесь втыкаемся в ограничения даже не Rars, а ассемблера. Уж больно много приходится писать, чтобы проиллюстрировать алгоритм. В своем цикле я к этому моменту уже перешел на Си. Хотя UART, который был в самом начале, был на ассеблере, конечно.
- Графический дисплей
Здесь было бы достаточно наглядно, если бы сделать эмулятор консоли. Растеризацию букв в набор пикселей, вывод одну за другой и т.д. Если хотите, могу попробовать это реализовать. Но даже так, вам придется хотя бы вкратце описать что происходит. "вот у нас есть массив изображений символов, вот переменная, хранящая текущую позицию на экране, при вызове ecall копируем одно в другое, ...". Да, "если хотите" это значит, я жду подтверждения. Для себя-то я это реализовывал уже не раз: в обычных дисплеях ведь тоже нет встроенного знакогенератора, а выводить текст бывает полезно.
Георгий Курячий Ну да, в пингвине подарочном я такое видел ☺
- Зададим константами размеры дисплея и базовый адрес
Магич... а нет, наконец-то константы. Правда, названия я бы выбрал более говорящие, хотя бы DISP_BASE, DISP_W, DISP_H.
- Наконец, напишем программу, заполняющую дисплей отрезками случайного цвета
Вообще-то, для рисования отрезков традиционно используется алгоритм Брезенхема, использующий только сложения и умножения. Ваш алгоритм более простой, но использует тяжеловесное деление, да к тому же по одной точке может пройтись несколько раз или наоборот, отсавить дырку. Будем считать, что он выбран ради наглядности. Но даже в таком случае упомянуть Брезенхема стоит.
- В силу природы MMIO прямая запись в видеопамять — операция долгая и ресурсоёмкая.
В реальности нет. Зачастую дисплеи имеют специальный FSMC-интерфейс, то есть для контроллера выглядят просто как внешняя микросхема памяти. Правда, лично я с такими не работал. Интерфейс SPI тоже обеспечивает достаточную скорость, но требует куда меньше ножек. А их и так не хватает. Впрочем, такой выбор есть только для "маленьких" дисплеев, до 480х320, дальше уже совсем специальные интерфейсы.
- Д/З
Например, нарисовать часы. Хоть цифровые, хоть стрелочные. Кстати, в Rars есть ecall 30. А если упороться, можно через ecall 1024 + ecall 63 + ecall 57 вывести, скажем, загрузку процессора... Кажется, я знаю, какое ДЗ будет у меня...
Георгий Курячий Непонятно, как выглядят тесты к такому Д/З.
P.S. я бы все-таки предложил несколько переформатировать порядок глав. В частности, поднять MMIO повыше, чтобы быстрее разобраться с "магией" ecall и превращения байтов в картинку на мониторе.
Георгий Курячий MMIO введена в этом месте, чтобы разбавить сложную тему с обработчиками в прошлой и следующей лекции. Мне-то как раз кажется, что нет ничего проще и понятнее линейной видеопамяти (я вот по молодости лет с EGA/VGA разбирался, вот где была жесть — слои, страницы и т. п.). К тому же MMIO — это разговор про внешние устройства, было бы не прлохо, чтобы он был недалеко от прерываний с внешних устройств.
Для меня в свое время именно этот переход был самым непонятным. И курс по ассемблеру в институте сделал только хуже. А вот контроллеры как раз принесли понимание. Кое-что на эту тему я набросал, и если вы готовы потратить какое-то время, можем это обсудить.
Георгий Курячий У меня, наоборот, особых проблем ни с магией ecall, ни тем более с превращением байтов в картинку на мониторе не было даже в школе. Ecall — это в каком-то смысле «магия по по определению», и мы в курсе в ней не «разбираемся», ну, магия и магия. А видеопамять — это вообще какая-то подразумеваемая база, не вполне понятно даже, что там объяснять. Вот контроллеры, наоборот, приносят только непонимание, ибо вечно там что-нибудь не по теории.
