А может вообще быть иерархическим. То есть мы программируем периферию, встроенную в процессор, она по какому-то протоколу общается с микросхемой-переходником, и уже та управляет устройством. Простейший пример - то, что называется "ногодрыг". Встроенная периферия - GPIO (по сути, отображение отдельных битов прямо на ножки микросхемы), ручная реализаци на нем, скажем, SPI, по которому подключен диспелей.

win-принтеры, модемы и прочие "безмозглые" устройства, куда драйвер сам заливает прошивку

"как-то" это "как скажет производитель". Карта памяти в помощь. Картинку я присылал.

Здесь можно сделать отсылку на непрямые эффекты в 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)

Вот здесь втыкаемся в ограничения даже не Rars, а ассемблера. Уж больно много приходится писать, чтобы проиллюстрировать алгоритм. В своем цикле я к этому моменту уже перешел на Си. Хотя UART, который был в самом начале, был на ассеблере, конечно.

Здесь было бы достаточно наглядно, если бы сделать эмулятор консоли. Растеризацию букв в набор пикселей, вывод одну за другой и т.д. Если хотите, могу попробовать это реализовать. Но даже так, вам придется хотя бы вкратце описать что происходит. "вот у нас есть массив изображений символов, вот переменная, хранящая текущую позицию на экране, при вызове ecall копируем одно в другое, ...". Да, "если хотите" это значит, я жду подтверждения. Для себя-то я это реализовывал уже не раз: в обычных дисплеях ведь тоже нет встроенного знакогенератора, а выводить текст бывает полезно.

Георгий Курячий Ну да, в пингвине подарочном я такое видел ☺

Магич... а нет, наконец-то константы. Правда, названия я бы выбрал более говорящие, хотя бы DISP_BASE, DISP_W, DISP_H.

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

В реальности нет. Зачастую дисплеи имеют специальный FSMC-интерфейс, то есть для контроллера выглядят просто как внешняя микросхема памяти. Правда, лично я с такими не работал. Интерфейс SPI тоже обеспечивает достаточную скорость, но требует куда меньше ножек. А их и так не хватает. Впрочем, такой выбор есть только для "маленьких" дисплеев, до 480х320, дальше уже совсем специальные интерфейсы.

Например, нарисовать часы. Хоть цифровые, хоть стрелочные. Кстати, в Rars есть ecall 30. А если упороться, можно через ecall 1024 + ecall 63 + ecall 57 вывести, скажем, загрузку процессора... Кажется, я знаю, какое ДЗ будет у меня...

Георгий Курячий Непонятно, как выглядят тесты к такому Д/З.

P.S. я бы все-таки предложил несколько переформатировать порядок глав. В частности, поднять MMIO повыше, чтобы быстрее разобраться с "магией" ecall и превращения байтов в картинку на мониторе.

Георгий Курячий MMIO введена в этом месте, чтобы разбавить сложную тему с обработчиками в прошлой и следующей лекции. Мне-то как раз кажется, что нет ничего проще и понятнее линейной видеопамяти (я вот по молодости лет с EGA/VGA разбирался, вот где была жесть — слои, страницы и т. п.). К тому же MMIO — это разговор про внешние устройства, было бы не прлохо, чтобы он был недалеко от прерываний с внешних устройств.

Для меня в свое время именно этот переход был самым непонятным. И курс по ассемблеру в институте сделал только хуже. А вот контроллеры как раз принесли понимание. Кое-что на эту тему я набросал, и если вы готовы потратить какое-то время, можем это обсудить.

Георгий Курячий У меня, наоборот, особых проблем ни с магией ecall, ни тем более с превращением байтов в картинку на мониторе не было даже в школе. Ecall — это в каком-то смысле «магия по по определению», и мы в курсе в ней не «разбираемся», ну, магия и магия. А видеопамять — это вообще какая-то подразумеваемая база, не вполне понятно даже, что там объяснять. Вот контроллеры, наоборот, приносят только непонимание, ибо вечно там что-нибудь не по теории.

LecturesCMC/ArchitectureAssembler2026/08_Input_Output/COKPOWEHEU (последним исправлял пользователь FrBrGeorge 2026-04-05 22:47:30)