惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
«Брус-16»: учебная игровая приставка с оригинальной минималистичной архитектурой
true-grue (Y · 2026-04-28 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение12 мин

Охват и читатели29

«Брус-16» — это новая игровая приставка. За полтора месяца мы спроектировали ее архитектуру, а также создали виртуальную машину, компилятор и аппаратную реализацию на FPGA. Специально для «Брус-16» написано более десяти игр. Если вам интересны «серьезные» темы системного программирования, компьютерных архитектур и цифровой схемотехники, а также темы «несерьезные» — разработка игр в духе ретро-инди, демосцена и эстетика минимализма, — то читайте дальше. Кстати, картинка выше состоит ровно из 64 прямоугольников. Это важно. Впрочем, обо всем по порядку!

FPGA-реализация Брус-16 в действии

FPGA-реализация Брус-16 в действии

Введение

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

Тем не менее целостное понимание машины остается важным для системного программиста и сегодня. Особенно это проявляется в работе с микроконтроллерами и специализированными ускорителями, где нужно жестко экономить аппаратные ресурсы и писать код, выполняющийся без ОС (bare-metal).

Поскольку я преподаю в университете, меня закономерно волнуют вопросы: как заинтересовать новичков специализированными компьютерными архитектурами, как дать «почувствовать вкус» системного программирования?

Здесь мне близка мысль физика Р. Фейнмана: «Чего не могу создать, того не понимаю». В учебных целях разумнее начать не с изучения особенностей промышленного решения, а воссоздать его наглядную, идеализированную, но рабочую модель. Этот подход не нов, и его замечательно иллюстрирует, к примеру, Андрей Карпатый, когда в видеолекциях с нуля реализует нейросети и языковые модели без использования сторонних библиотек.

Известный учебный проект Nand to Tetris демонстрирует, что ключом к целостному пониманию является междисциплинарный подход, объединяющий цифровую схемотехнику, компьютерные архитектуры, системное и низкоуровневое программирование. Nand to Tetris и другие подобные проекты хорошего уровня отличаются использованием компьютерной архитектуры, которая специально спроектирована для задач обучения.

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

Разумеется, можно попробовать взять в качестве изучаемой архитектуры одну из реально существовавших в прошлом игровых систем, например, Atari 2600 или NES. В реальности подобные архитектуры оказываются не такими уж простыми и имеют ряд тонких исторических нюансов, которые лишь отвлекают и мешают изучать фундамент. Кроме того, для старых систем уже написаны многие сотни игр, а также известны основные низкоуровневые трюки, поэтому писать что-то свое, пожалуй, уже не так интересно.

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

По описанным выше причинам, а также чтобы не заскучать на собственных лекциях, я решил спроектировать новую игровую приставку. Оригинальная архитектура здесь используется еще и для того, чтобы побудить молодых системщиков выйти из зоны комфорта в виде запросов к Google и языковым моделям. А «старикам» — помочь выбраться из ностальгического плена привычки к старым моделям компьютеров и восьмибитным игрушкам.

«Брус-16» изначально спроектирована не только для программной, но и для аппаратной реализации. Ведь какая радость для автора игры – увидеть, что его творение успешно работает в «железе»! Хотя речь пока идет о самых недорогих моделях FPGA, но кто знает: быть может, чип «Брус-16» будет когда-нибудь выпущен на заводе.

Архитектура

«Брус-16» — игровая приставка, которая могла появиться при некоторых фантастических допущениях в параллельном мире начала 80-х. По возможностям она ближе не к классическим Sega Mega Drive или TurboGrafx-16, а, скорее, напоминает первую в мире 16-битную приставку Mattel Intellivision.

Архитектура Брус-16

Архитектура Брус-16

С аппаратной точки зрения «Брус-16» представляет собой систему реального времени на кристалле, без использования такой дорогой в наше время внешней памяти. В состав «Брус-16» входят:

  • 16-битный двухстековый процессор (CPU) для игровой логики, с разделенными пространствами кода и данных (гарвардская архитектура).

  • Аппаратный графический ускоритель (GPU), который позволяет одновременно отобразить на экране до 64 закрашенных прямоугольников в разрешении 640x480 с 16-битным цветом и на скорости 60 к/с. Вместо экранного буфера — список команд (display list).

  • Аппаратный ускоритель для звука (SPU) на основе аддитивного синтезатора с 16 синусоидальными осцилляторами и с выводом 16-битных звуковых семплов.

  • Контроллер прямого доступа к памяти (DMA), который позволяет автоматически обновлять параметры ускорителей, отображенные в память данных CPU.

  • Контроллер ввода для двух джойстиков.

Процесс проектирования в основном заключался не в добавлении, а в удалении лишнего — всего, что помешало бы обычному студенту написать игру или виртуальную машину за вечер, компилятор — за неделю, а FPGA-реализацию — за две-три недели.

Отмечу, что проектирование «Брус-16» доставило мне немало удовольствия и, по существу, оказалось метаигрой — игрой в выстраивание правил для создания игр. Хотя «Брус-16» и состоит почти из одних ограничений, здесь уместно вспомнить высказывание Леонардо да Винчи: «Искусство живет ограничениями и умирает от свободы». Поэтому главная трудность оказалась в подборе таких ограничений, которые задают жизнеспособную и оригинальную форму игровых произведений. Минимализм решений «Брус-16» роднит его с демосценой и, как и в случае демосцены, важно было добиться оправданных с аппаратной точки зрения, а не надуманных архитектурных ограничений.

Пожалуй, надо сказать пару слов и о причинах такого названия приставки. Почему брус? Бруски напомнили мне о советском деревянном конструкторе. Так же можно назвать закрашенные прямоугольники, которые рисует GPU. Еще существовали АОНы с созвучным названием в духе «Русь-24». Кстати, число 16 в названии обозначает разрядность приставки, в том же стиле, что и для классической TurboGrafx-16. Наконец, самая очевидная аллюзия — это, конечно, компьютерная архитектура «Эльбрус», которая в своей советской версии тоже являлась стековой.

Программную реализацию «Брус-16» (Windows/Linux/Web) можно найти в github-репозитории. FPGA-реализация, выполненная студентом Кириллом Павловым и успешно проверенная на FPGA-чипах Tang Nano 9K/20K, Tang Primer 25K и Xilinx XC7A200T находится в отдельном репозитории.

Поиграть в игры для «Брус-16» можно с помощью онлайн-эмулятора. Наверное, начать имеет смысл с игры Gerion — нашего «AAA-проекта"»для Брус-16. Оригинальный игровой процесс, десятки уровней, динамическое изменение масштаба камеры, звук и музыка… но лучше об игре расскажет ее автор, Пётр Косых. Обязательно посмотрите также глубоко переработанный порт известной игры Alter Ego от Василия Литвиненко, получивший одобрение автора NES-версии игры, @shiru8bit. Конечно, не стоит забывать и автора оригинала — Дениса Грачёва.

Теперь пришло время подробнее разобрать, почему подсистемы «Брус-16» имеют именно такой вид.

Компилятор и CPU

В названии этого раздела «компилятор» стоит на первом месте неслучайно. В целом программно-аппаратное проектирование процессора можно провести тремя путями:

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

  2. Берем готовую программную инфраструктуру (x86, CUDA, …) и проектируем процессор под нее.

  3. Будем совместно проектировать язык, компилятор и специализированную процессорную архитектуру для поиска компромиссного решения (HW/SW co-design).

В вариантах 2 и 3 именно компиляторщик занимается высокоуровневым проектированием аппаратуры. «У нас есть опыт в области разработки компиляторов. Почему бы нам не подумать о создании процессора?» — это слова Дж. Хеннесси, автора архитектуры MIPS и нескольких классических работ по технологиям компиляции. Компиляторщик Дж. Кок спроектировал архитектуру первого RISC-компьютера IBM 801, опираясь на статистику, полученную с помощью компилятора (при этом аппаратура и компилятор развивались одновременно). Другой компиляторщик, Дж. Фишер, автор архитектуры VLIW, занимался совместным проектированием с оптимизацией аппаратных параметров под конкретные приложения.

Для проектирования CPU выбран самый естественный и поучительный вариант — третий. И раз уж у нас язык, компилятор и архитектура развиваются одновременно, лучше сразу избавить прикладного программиста от необходимости писать на языке ассемблера. Главное, чтобы компилятор вел себя достаточно разумно (и это не неуловимый sufficiently smart compiler, о котором легко говорить, но сложно разработать).

Я задал жесткое ограничение на размер исходного текста учебного компилятора: не более 200 строк (SLOC). Это ограничение сразу направляет на поиск самых простых решений для языка, компилятора и архитектуры.

Языком программирования игр для «Брус-16» является встроенный в Python предметно-ориентированный язык (DSL). Синтаксически это «безобидный» Python — точнее, его подмножество. Однако смысл конструкций языка (семантика) близок к языку C, а местами оказывается даже более низкоуровневым — это плата за простоту реализации компилятора.

Многие современные DSL на Python используют перегрузку операций, при этом декоратором помечаются аппаратно-ориентированные функции, которые необходимо транслировать в код, например, AI-ускорителя. В «Брус-16» используется иной подход: компилятор реализован с использованием модуля ast из стандартной библиотеки.

Этот подход значительно мощнее перегрузки операций. Он позволяет, подобно макросам языка Lisp, задавать новую аппаратную семантику для привычных конструкций Python. В процессе трансляции DSL-программы в дерево абстрактного синтаксиса (ДАС) используется готовый фронтенд компилятора Python. В промышленных решениях подход на основе ast применяют достаточно широко: можно вспомнить, к примеру, реализацию компилятора Triton. Подробнее о создании DSL различной сложности с помощью ast можно узнать из моего доклада на PiterPy.

Вот как выглядит простая программа для изображения круга в псевдографике:

from brus16 import *

def send(c): # макроопределение
    return f'poke(-1, {ord(c)})' # Вывод символа в отладочный порт терминала (адрес -1)

save_game('circle.bin', f'''
# Функция main может иметь любое другое название, поскольку старт программы начинается
# с первой команды, то есть мы сразу попадаем в тело первой определенной функции.
def main():
    circle(8)
    while 1: # генерируем пустые кадры
        wait()

def circle(r):
    y = -r
    while y < r:
        x = -r
        while x < r:
            if x * x + y * y < r * r:
                {send('O')}
            else:
                {send(' ')}
            x += 1
        {send('\n')}
        y += 1
''')

В этом примере f-строка используется для организации препроцессора «для бедных». Подобных нюансов в языке много, и они продиктованы желанием предельно упростить компилятор. Поэтому, например, поддерживается цикл while, но отсутствует for. Разумеется, есть возможность написать код на DSL и в отдельном файле. Подробнее о DSL можно прочитать в документации.

При проектировании CPU я сразу определился с рядом архитектурных ограничений:

  • Процессор должен быть стековым. Это избавляет компилятор от громоздкой процедуры распределения регистров. Стековые архитектуры сегодня редко встречаются «в кремнии», но для софт-процессоров на FPGA они используются весьма широко.

  • Разрядность – 16 бит. 8 бит потребовали бы утомительного ручного кодирования или все того же «достаточно умного» компилятора. 16-битные микроконтроллеры используются достаточно широко и сегодня, а 32-битный тракт данных потребовал бы большего числа аппаратных ресурсов. В результате CPU в его FPGA-воплощении оказался в 2 раза компактнее 32-битного RISC-V (PicoTiny).

  • Фиксированная длина команд и слов данных (16 бит). Это упрощает декодер и делает виртуальную машину «Брус-16» несложной в реализации даже для новичков.

  • Однотактное выполнение. В отличие от многотактного PicoTiny, CPU выполняет команды за один такт.

  • Гарвардская архитектура и два стека. Для упрощения однотактного процессора память данных (8192 слова) и память кода (8192 слова) физически разделены. 32 КБ блочной памяти – не проблема для современных FPGA. Аналогично разделены стек данных (32 слова) и стек адресов возврата (16 слов).

  • Базовое АЛУ + аппаратное умножение. Поддерживаются основные операции базового целочисленного подмножества RISC-V. При этом добавлено умножение, которое легко отображается на аппаратные умножители современных FPGA. Умножение особенно важно для вычислений с фиксированной точкой, на которых строится физика в играх.

Вот простой пример кода:

def is_installed():
    return hook_box_pos_y >= {SCREEN_H - BOX_W * 3}

Компилятор транслирует его во вполне предсказуемое стековое представление:

LABEL is_installed
PUSH hook_box_pos_y
LOAD
PUSH 450
GE
RET 0

При проектировании удачной системы команд (ISA) важно заранее иметь набор целевых программ, с учетом которых оптимизируется архитектура. Для «Брус-16» такими программами оказались первые игры, написанные на промежуточном представлении (IR) компилятора.

Поверхностный анализ IR привел к явно неоптимальной ISA, показанной ниже.

Первый вариант ISA

Первый вариант ISA

Здесь мы видим два формата команд: для загрузки литерала и для остальных безоперандных команд. Можно ли сделать лучше?

Для этого я провел детальный анализ часто встречающихся фрагментов кода в наборе программ. Получилась следующая картина:

Статистика часто встречающихся фрагментов кода

Статистика часто встречающихся фрагментов кода

На основе полученной статистики шаблонные фрагменты удалось «свернуть» в специализированные команды:

  • Бинарные операции с константным аргументом.

  • Операции обращения к памяти со смещением-константой.

Однако даже от самых изощренных команд мало толку, если компилятор не умеет ими пользоваться (и нет, ручные intrinsics – не выход!). Поэтому в компилятор «Брус-16» для этих целей добавлено несколько простых правил peephole-оптимизации:

1. PUSH x + binop => binop x
2. ADD 0 | OR 0 | SHL 0 | ... => _
3. ADD x + LOAD 0 => LOAD x
4. ADD x + STORE 0 => STORE x

С использованием этих правил размер игры Gerion, к примеру, удалось сократить на более чем 900 команд:

Влияние peephole-правил на сокращение размера кода

Влияние peephole-правил на сокращение размера кода

В реальности сокращение размера кода оказывается скромнее из-за аппаратных нюансов: при однотактной работе процессора в FPGA результат чтения из памяти доступен не сразу, а на дополнительном такте. Здесь возникает обратная связь со стороны аппаратного проектирования, которая приводит к компромиссу на уровне компилятора: выполняем LOAD только в связке с новой командой PUSH_MR (занести прочитанный результат на стек).

Вот как выглядит финальный вариант ISA:

Финальный вариант ISA

Финальный вариант ISA

Что же касается таинственной команды WAIT, которая фигурирует в примере кода для изображения круга, то она используется для реализации аппаратной сопрограммы (да, в духе async/await). Процессор «засыпает», добравшись до WAIT, и его работа возобновляется по внешнему сигналу. Так CPU синхронизируется с другими подсистемами «Брус-16». В частности, WAIT требуется, чтобы сигнализировать GPU, что параметры очередного кадра сформированы и готовы к отправке на экран. И раз уж я заговорил о кадрах, самое время посмотреть, как устроена графика «Брус-16».

GPU

Помните заглавную картинку статьи? Я упомянул, что она состоит ровно из 64 прямоугольников. Это ограничение GPU, больше в одном кадре просто не нарисовать. Теперь пора объяснить, откуда взялось такое странное ограничение.

GPU поддерживает разрешение 640x480 c 16-битным цветом, закодированном в формате RGB565, популярном во встраиваемых системах. Если бы мы захотели использовать классический экранный буфер, то для хранения одного кадра потребовалось бы более 600 КБ блочной памяти. Это за пределами возможностей недорогих FPGA, пришлось бы использовать внешнюю память. Такой вариант «Брус-16» уже нельзя назвать компактной системой на кристалле.

По этой причине вместо экранного буфера в специальной области памяти данных CPU формируется список из 64 команд для рисования закрашенных прямоугольников — ограниченный вариант векторной 2D-графики. Каждый прямоугольник описывается следующими параметрами:

  • абсолютные или относительные (от предыдущего “абсолютного прямоугольника”) координаты abs и rel,

  • координата x,

  • координата y,

  • ширина w,

  • высота h,

  • цвет rgb.

Вот простой пример такого векторного описания спрайта:

Птичка из игры Flippy

Птичка из игры Flippy

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

Признаюсь, векторная 2D-графика в играх мне нравилась еще со времен старого шедевра Another World от Э. Шайи. Современные игры часто грешат визуальным шумом: слишком много мелких и ненужных деталей, перегруженные интерфейсы, кислотные цвета. Мне же хотелось добиться эстетики минимализма строгих форм. Что может быть проще и лаконичнее прямоугольника? К слову, в современных 2D API зачастую нет функции «нарисовать пиксель», базовым примитивом выступает именно прямоугольник.

Но достаточно ли 64 прямоугольников для создания игр? Честно говоря, ограничение в 64 прямоугольника оказалось тем самым архитектурным решением, которое в «Брус-16» было труднее всего отстаивать. В первую очередь хотелось упростить аппаратную реализацию GPU. Но посмотрите на картинки из игр, ведь получился оригинальный визуальный стиль, этакий «брус-арт»:

Примеры брус-арта

Примеры брус-арта

Что дальше?

Материал и так получился довольно объемным, а звуковая подсистема все еще не описана. Поэтому я сохраню интригу и не буду сейчас объяснять, почему, к примеру, я заменил в синтезаторе привычную для старых игровых приставок прямоугольную форму волны на синус. Оставлю это для второй части статьи.

Надеюсь, выйдет и статья Кирилла Павлова — взгляд на реализацию Брус-16 в FPGA с точки зрения начинающего RTL-проектировщика.

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

  • Реализуйте аппроксимацию произвольной картинки прямоугольниками GPU. Как насчет видео Bad Apple?

  • Реализуйте ресинтез произвольного звукового файла с помощью осцилляторов SPU.

Смело создавайте «игры за вечер» для «Брус-16», потому что когда-нибудь мы обязательно проведем игровой конкурс под названием «Брусничный джем»!

Благодарности

Я признателен коллегам-преподавателям и студентам РТУ МИРЭА за интерес к проекту «Брус-16». В частности, хочу сказать спасибо:

  • Студенту Кириллу Павлову за FPGA-реализацию «Брус-16».

  • Профессору Илье Евгеньевичу Тарасову за консультации по FPGA.

  • Студентам Владимиру Миклашевичу и Денису Ананьеву, а также преподавателю Артёму Горчакову за игры.

Отдельное спасибо сторонним разработчикам игр, Петру Косых и Василию Литвиненко, а также замечательному художнику pixelrat.