Разработка видеокарты своими мозгами. Символьный вывод

Вступление

Всем привет! С вами Ш. Сергей и я продолжаю разрабатывать видеоадаптер. В прошлой статье я рассказывал о возможности создания одного из простейших видеоадаптеров.

В этой статье будет задета возможность вывода символов на наш виртуальный монитор.

Использую я Logisim Evolution 3.8.0. И видеокарта будет собрана только в схеме. Сколько бы я не хотел протестировать в реальности свои наработки, пока возможности нет. Возможно повезёт и когда-нибудь получится реализовать.

Упрощённая структурная схема

Так как прошлая статья была немного сумбурная, тут я решил немного более собрано всё расписать.

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

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

Рис. 1. Упрощённая схема видеоадаптера.

Рис. 1. Упрощённая схема видеоадаптера.

  • УУ — управляющее устройство.

  • УС — устройство согласования.

  • ШД — шина данных.

  • ШУ — шина управления.

Да, на схеме моя ошибка, от памяти к ШУ не идёт ни каких данных.

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

Данный разрабатываемый адаптер делает обработку входящих сигналов и подготавливает выходящие. Как вы реализуете подачу и забор сигналов, будет зависеть от вас самих. В данной схеме будет пример, но этот пример для модуля Logisim »RGB видео». Для реальных устройств он маловероятно что подойдёт (это не точно, я не знаю всех устройств, которые выводят изображение).

На что будем ориентироваться при реализации видеоадаптера в данной статье

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

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

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

В данной схеме рассмотрим возможность избежать данной проблемы. Но работать будем только с текстовым режимом. Почему? Надеюсь вы сами сможете ответить себе на этот вопрос если дочитаете статью и разберётесь в схеме видеоадаптера.

Сразу стоит обратить внимание, предоставленный видеоадаптер работает только с символами! Ни какого графического режима здесь нет.

Сделал пример работы видеоадаптера и постарался рассказать по работе данного адаптера.

Основная схема

Рис. 2. Основная схема.

Рис. 2. Основная схема.

Основная схема на вид стала меньше, а входящих сигналов больше. Но как видно по схеме, добавлена схема MyRAM, и если заглянуть внутрь (далее рассмотрим), то поймём, что схема не стала ни меньше ни проще, чем прошлая.

В данном случая я использовал монитор из Logisim »RGB видео», как и в прошлый раз, с маленькими изменениями, теперь разрешение монитора 32 на 32 пикселя. Остальное я ни чего не менял для монитора!

Стало больше входящих сигналов. Это и не удивительно, ведь теперь нам надо согласовывать приходящие от ЦП символы и данные вместе с ним поступающие: цвет фона, цвет символа и координаты (в знакоместах). Остался прежний сигнал о конце прорисовки EndDraw и добавился сигнал который оповещает что на прорисовку выставлен новый символ NextSymbol. Так же должен быть ещё один сигнал, который посылается для ЦП и оповещает его, что можно посылать следующий символ.

Сигналы Reset и TG думаю понятны для чего. Остальные сигналы нужны для эмулятора сигналов от монитора (в прошлом видео рассматривал, кто не видел, смотрите под спойлером, таймеры выставлены), эти сигналы не отображают дейстительности, но я постарался их приблизить к возможности эмулировать псевдореальные сигналы.

Необходимы данные для нашего монитора я прописал, если менять размеры монитора (выводимой области), то эти данные надо вычислять.

прошлое видео

Схема MyRAM

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

Рис.3. MyRAM

Рис. 3. MyRAM

В наш видеоадаптер мы добавлен банк памяти ПЗУ, которое как раз будет содержать необходимое количество символов. Каждый символ будет (8 бит на 2 бита на 8 байт) = 64 бит (8 байт). Каждый байт как раз содержит в себе 8 бит и 2 бита будут обозначать включен бит или выключен. Само ПЗУ нужно только для того чтоб содержать информацию о выводимых символах, и ни чего больше (в данном случае).

Входящие сигналы от ЦП перенаправлены в данную схему, и немного изменены их названия. И данная схема принимает сигналы от схемы EmuGenerate (эмулятора сигналов). Стоит отметить сигналы TGInRAM — тактовый сигнал подаваемый для записи данных в ОЗУ из ПЗУ согласно полученных сигналов и InSyncToRAM — тактовый сигнал подаваемый для чтения данных из ОЗУ для передачи на монитор. Сигнал ChangeBank отвечает за переключение банков памяти. XIn и YIn — координаты для вывода изображения из одного из банков ОЗУ. Сигнал InNexSymbol — подаст оповещение о том что новый символ от ЦП пришёл.

В данном случае мы не будем учитывать возможность выхода символов за экран и смещение всего что было выведено, при поступлении новой строки которая выходит за пределы выводимой области. Проверку выхода за пределы делать надо обязательно, чтоб адреса не наложились друг на друга (в этом случае мы вернёмся на начальные адреса и перекроем ранее выводимую информацию, так это не должно работать, надо делать скроллинг экрана). Но и это на данный момент реализовывать не будем.

Исходящие сигналы будут (для данного «монитора» RGB видео): сигнал сброса — ResetVGA; сигнал синхронизации — SyncTime; сигнал записи данных — WriteVGA (в данном случае всегда равно 1); координаты — XOut, YOut; цвет — ColorOut. Так же дополняем схему сигналом согласования о том, что данные переданные с ЦП были записаны в память — EndNexSymbol. Это нужно для тех моментов, когда ЦП и видеоадаптер работают на разных частотах, но на самом деле лучше всего всегда делать согласование сигналов, во избежание различных проблем.

В данной схеме в ПЗУ выделено место под 64 символа, завёл я только 26 для тестирования и если вы смотрели видео, то видели, что их ещё разворачивать надо. Но сейчас меня это не сильно волнует, ведь нам нужно было протестировать сам видеоадаптер.

ПЗУ: разрядность адреса — 6, разрядность данных 64. Входящее значение InSymb будет как раз указывать на 64-х битный адрес ПЗУ, а это как раз определённый символ. В данной реализации 0-й символ — это символ «A».

Банки памяти тоже изменились. ОЗУ: разрядность адреса — 7, разрядность данных — 64.

Всё это надо для было сделать для реализации быстрой записи данных в ОЗУ, согласно входящих данных и данных о символе хранящихся в ПЗУ.

Ну кто догадался как всё будет работать, может наверно уже заканчивать чтение статьи. При поступлении сигнала от ЦП, читаем данные, узнаём что за символ, выдёргиваем из ПЗУ нужные данные записываем их в ОЗУ и при поступлении сигнала синхронизации всё что поступило в ОЗУ выводим (меняем банки памяти для вывода).

Финете ля комедия, все расходимся.

Скоро сказка сказывается, да не скоро дело делается

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

Начнём с того, что если мы просто будем копировать данные из ПЗУ в ОЗУ, то ни какого ускорения мы не получим (уже писалось выше). Для того чтоб ускорить наш видеоадаптер нам надо переделать работу (взаимодействие) памяти и работу шин (появляются новые проблемы и приходится добавлять сигналы).

Стоит ли разбирать, по какой причине мы не получаем ускорения, если просто добавим ПЗУ и будем считывать информацию согласно полученной информации?

Думаю что стоит, для большего понимания происходящего. ЦП начинает передавать строку для её вывода на экран. Поступают сигналы для первого символа: InSymbX, InSymbY, InColor1, InColor2, InSymb и InNexSymbol — оповещающее что данные пришли.

Видеоадаптер начинает обрабатывать данные, забирает их и выставляет сигнал EndNexSymbol. Теперь видеоадаптер должен записать из ПЗУ символ в ОЗУ. Читает первый байт (8 бит указывают включен данный пиксель или нет, и исходя из этого происходит выборка записываемого цвета) и будем считать что это был такт. Потом надо прочитать второй байт, третий… восьмой… Итого для записи в память мы потратили 8 тактов (условно, вероятнее больше).

Что же делает процессор в это время? ЦП выставил второй символ для отрисовки и ждёт, пока придёт ответ от видеоадаптера EndNexSymbol что данные были обработаны, но видеоадаптер не даёт такого сигнала, потому что идёт обработка первого символа и процессор простаивает. А теперь представьте что видеоадаптер работает на меньшей частоте, чем процессор… В общем смысла становится достаточно немного, хотя он конечно есть, если мы будем сравнивать со схемой в прошлой статье.

Если процессор будет заниматься тем же самым, то в этом случае надо будет пересылать каждый пиксель на обработку, а это займёт 64 такта процессора (8 на 8 байт). Но ускорение в данном случае может быть не очень большим (всё надо проверять на практике).

Какие же есть решения для данной проблемы?

  1. Мы можем добавить видеоадаптеру ещё памяти и поступающие символы записывать в эту память. Получим своеобразный кэш. В этот кэш мы сможем записать в очередь сразу неколько символов, скажем 256 и освободить процессор от ненужных ожиданий. Но если поле вывода большое (например монитор 1024 на 768 — это, кстати, достаточно не маленькая область вывода) и надо выводить большой массив данных, то надо увеличивать память в видеоадаптере ещё сильнее, и это может продолжаться почти до бесконечности…

  2. Есть вариант переделать взаимодействие ПЗУ и ОЗУ в видеоадаптере и расширить внутреннюю шину передачи данных. В этом случае мы сможем записать в ОЗУ сразу весь символ за один такт (условно) и ЦП не надо будет ожидать пока будет обработан очередной символ, потому что символ будет обработан почти сразу же и освободит место для следующего символа.

Вероятнее всего есть ещё варианты решений. Но рассматривать будем в данном случае второй вариант.

Я старался не отходить от основных схем и основываться на элементах которые существуют в Logisim для того чтоб, если кто-то решится протестировать в реальности схему, у него не возникало проблем с реализацией (или возникало как можно меньше). Я конечно задавался вопросом: есть ли схемы ОЗУ которые могут читать по широкой шине, а передавать по узкой? Я лично не знаю, честно говоря вопрос себе задавал, но сильно не интересовался.

Давайте немного отойдём в сторону от видеоадаптера и коснёмся памяти. Проблема не в том чтоб реализовать необходимую память, а проблема в том, что реализация, на самом деле, должна быть наиболее полной. Память видеоадаптера должна уметь как записывать так и читать данные по любой заданной ширине шины! Это и есть сама проблема. Мы должны иметь возможность записать как байт, так и 8 байт (или больше?) сразу. И так же должно происходить с чтением из памяти.

Запись данных по широкой шине, не может решить всех проблем. Потому что данные могут приходить как для одного пикселя, где не нужна широкая ШД, так и для какого-то широкого фрагмента экрана (например линия спрайта, в данном случае символа). По большей части я уверен, что подобная память уже реализована достаточно давно и возможно я делаю из мухи слона. Но вот в Logisim нет реализации подобной памяти… и её надо как-то реализовать.

Исходя из всего вышесказанного, мы не будем реализовывать «универсальную» память, оставим для данного видеоадаптера только возможность вывода текстовой информации и на этом и будем основываться. Нам останется реализовать память и шину только для данного устройства. Синхронизировать чтение приходящих данных от ЦП с данными из ПЗУ и записать нужные цвета в ОЗУ согласно этим данным. А так же реализовать передачу данных для ОЗУ с широкой ШД на узкую ШД для возможности вывода на наш монитор.

Разветвитель

Я конечно прошёл бы мимо этой темы, но тут она оказалась актуальной. В Logisim для проводов и шин часто используется Разветвитель. Если вы обратите внимание, то на предоставленных мной схемах, многие разветвители находятся в «собранном» состоянии. Мы можем творить с разветвителями интересные вещи: выставьте »веерный выход» на 6 (например), а »разрядность входа» на 16. Теперь выставьте »Бит 0»,»Бит 1»,»Бит 2»,»Бит 3» и »Бит 4» согласно значений от 0 до 4-х, а все остальные биты выставьте на 5 (при выборе можно цифру 5 нажимать или любую другую).

Смотрите схемы внимательно, я в некоторых местах сжал 64-х битные шины до 8-ми входов! Не ошибитесь!

Схемы

EmuGenImp — разбирать не будем, изменений не было. Это смоделированный мной счётчик, специально для данного видеоадаптера делал.

Рис. 4. EmuGenImp

Рис. 4. EmuGenImp

ConvertSymToRAM — данная схема предназначена для передачи данных цвета в банк ОЗУ согласно входящих данных: AddrIn (это начальные данные по Y), заданным цветам (идёт выборка цвета) и поступивших с ПЗУ данных о входящем символе. Примерный принцип работы: все данные о поступившем символе распределяются по D-триггерам в схемах InOut8bit(смотрим ниже), кроме начальных, начальные данные сразу отправляются на, скажем так, «декодировщик» и соответствующий биту цвет записывается в ОЗУ. Как видим данные поступают в параллели и записывается сразу 8 цветов (на 8 пикселей).

Рис. 5. ConvertSymToRam

Рис. 5. ConvertSymToRam

Это и есть та самая схема, которая позволяет ускорить обработку принятых данных от ЦП и разгружающая его.

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

Рис. 6. InOut8bit

Рис. 6. InOut8bit

Memory64to8×8 — схема для последовательной передачи данных на монитор. Приходит 64-х битное значение и его надо разбить на восемь 8-ми битных значений. Как и в схеме ConvertSymToRAM первое значение сразу передаётся на монитор, остальные записываются в d-триггера.

Рис. 7. Memory64to8x8

Рис. 7. Memory64to8×8

Провода, шины

Для более полного понимания, надо рассматривать работу схемы. Рассматривать будем в основном рисунок 2, но так же шины находятся и в других схемах. На рисунке достаточно широкими обозначена шина данных (ШД). Тонкими «проводочками» (по большей части) обозначена шина управления (ШУ). Не надо думать, что так просто выделить всё в какую-то отдельную шину. В любом случае схему надо изначально реализовать, а уже позже пытаться оптимизировать.

Да, в схемах не все провода одиночные относятся к ШУ, часть из них может оказаться относящейся к ШД, по той причине, что мне надо было выделить отдельные провода из шины. Так же не все оставшиеся провода относятся к ШУ (ну например я бы не относил сигнал Reset к ШУ, но я могу ошибаться).

Изучайте схемы и я думаю вы разберётесь со всем что вас интересует.

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

Все работы выполнены под свободной лицензией ZLib.

В завершении

Что я могу сказать по данной реализации видеоадаптера?

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

Были ли какие-то затруднения?
Да! Тут больше происходили бодания с Logisim, так как я его плохо знаю (ладно, не очень хорошо) и в Logisim иногда проскакивают какие-то непонятные баги. Иногда удалял один элемент, ставил на его место такой же и баг пропадал.)))

Будет ли выложена данная схема в общий доступ?
Она уже выложена в данной статье. Где-то на другом ресурсе выкладывать не буду.
Да, я делаю это специально, для тех, кому это в самом деле интересно! Поработайте руками и головой, это вам полезно будет. Соберите схему сами, всё уже выложено.)))

Тут можно сказать что всё это было достаточно долго. Я потратил не мало времени на всю реализацию, со всеми устранениями неполадок и доведения работы адаптера до ума. Кстати, недоработки до сих пор остались в моей реализации, потому будьте внимательнее!

Буду ли я дальше заниматься реализацией каких-то функций видеоадаптера?

Я не уверен. Уходит слишком много сил и времени на это на всё. Даже простейшая функциональность убивает тонны времени, а для реализации полноценного видеоадаптера с 2D ускорением сделано только полшага. Было желание сделать переключение режимов (выбор нужного режима), работы со спрайтовой графикой и работой с 2D примитивами (хотел их реализовать не используя математику).

Так же нет возможности (пока) реализовать схему в реальности, чтоб я мог протестировать свою работу полноценно. А это так же желание отбивает.

Не сложно сделать видеоадаптер самому, достаточно понять как это всё реализовывается и можно сказать задача решена.

Но время… время… время…

Хотя кто знает, может меня в очередной раз пробьёт и я докину пару функций.

Я надеюсь данная статья вам помогла и вы решились себе сварганить свой видеоадаптер.)))

Всем успехов!

© Habrahabr.ru