Михайлов Алексей Анатольевич@MinimumLaw
Linux Kernel, Bare metal, Embedded developer
Информация
- В рейтинге
- Не участвует
- Откуда
- Пушкин, Санкт-Петербург и область, Россия
- Дата рождения
- Зарегистрирован
- Активность
Специализация
Инженер встраиваемых систем, Архитектор программного обеспечения
Старший
От 350 000 ₽
Рыбки - это уже про другое. Из сцены интересны только те, которые максимум в 1К размером, а лучше 256 байт. Вот тут чудеса упрощения алгоритмов и оптимизации. Даже 4К уже не настолько вылизаны.
Помимо тетриса и змейки есть еще реверси, ветка (или как там она в оригинале), арканоид, сокобан. Это из того, что на слуху. Список наверняка не полный. Они все предельно просты и категорически нетребовательны к ресурсам. Самое интересное, что находятся и относительно современные варианты. В частности flappy birds (или я чего-то не знаю)?
А еще часто используются старые находки демосцены. Огонь, бублик, полет над планетой и через космос. Но они, как правило, не интерактивны и используются именно как демо.
если верить мануалу к монитору, то можно было 1024х768 черезстрочно. В Windows 3.11 это работало. Здесь так и не завел. Помимо прочего создатели монитора (как много бы я дал тогда за эту информацию...) посадили один из выводов будущего DDC канала на землю. Когда-то именно это было признаком подключенного монохромного монитора. И очень многие это трактовали именно как монохром - как у Hercules'ов. В частности Norton Utilites ни в какую не хотели быть цветными (по факту оттенками серого), а были именно монохромом. И то ли Linux, то ли XFree86 туда же. Помню что даже пересобирал что-то, дабы наглухо отключить эту особенность и заставить считать это дело цветным безоговорочно. Это было сильно важнее, чем черестрок завести.
Да, первый Linux, который был поставлен и получен доступ к консоли. Повозиться с конфигом иксов для цироза в PS/2 машинке с монохромным VGA пришлось повозиться. Но 800x600 тогда получилось.
У меня первый монитор был монохромным (те самые оттенки серого). В принципе, даже в lines играть можно было. Но исключать тот факт, что именно по этой причине меня куда больше влекло программирование, нежели гейминг исключать нельзя.
Сегодня включать детям такое... Я бы не стал. Хотя... Возможно, что-то в этом есть....
Поздно заметил тег "перевод". Каюсь. Думал статья "живого" автора. А так да, абсолютно согласен.
Ну, сказав "А", неплохо бы сказать и "Бе". Приведите реализацию поставленной задачи на Pascal. Так, чтоб все компиляторы ее съедали. Попкорн я уже заготовил.
Реализуйте эту же задачу на вашем любимом языке. Желательно чтоб у того не было единственного, богами созданного, компилятора и был принятый стандарт языка.
А за одно объясните нам практическую ценность. А то правда не очень понятно зачем это надо и как это использовать.
Ну да. С ростом кодовой базы, начинаем топтать те же грабли, что и C. Особенно опускаясь к тому же уровню исполнения. И с теми же проблемами. Этот арканоид никогда не будет работать, на чем-то отличном от PC c VGA. Но "зоопарк архитектур" уже начинает влиять.
Вообще мы с вами на разных языках разговариваем. Начиная с того, что память, разделяемая на память-память с произвольным доступом и порты ввода-вывода с доступом только с использованием пары специальных ассемблерных инструкций - это чуть ли не уникальный костыль PC. Понятно откуда взявшийся, но от этого не менее уникальный. От костыля этого, по сути, уже отказались и держат исключительно для совместимости с legacy решениями. Сравнивать его даже с регистрами периферийных блоков STM32 или AVR не самая корректная идея. Это физически очень разные сущности. Не говоря уже про программные каналы где бы то не было.
Да и ассемблер, в общем случае, оперирует очень небольшим количеством базовых типов (из которых тот же Rust плодит производные). И очень небольшим количеством операндов. Ваше строгое "нельзя" точно не соответствует истине. В конце-концов и при трансляции все сводится к ассемблерным инструкциям. Другое дело, что целесообразность этих операций вызывает серьезные вопросы. А вот вопрос как относиться к человеку, который пишет asm! - как к вредителю, не желающему пользоваться средствами языка, или как к профи, обходящему бутылочное горлышко... Впрочем, ваш ответ понятен. Имеете право.
Ну давайте так - этот проект одна из множества попыток поиграть на embedded поле. Без runtime, без аллокатора, и даже без ОС. И в отличии от обычных Skeleton-ов тут есть какой-то ощутимый результат. Тем и интересен. Потому и пошел смотреть, а не пролистал как обычно.
Да, есть "золотой фонд" - змейка, тетрис, арканоид. Ну еще с пламя, бублик и ряд других находок с демосцены. Достаточно простые в реализации, не требовательные к ресурсам. Все они в некотором смысле "Hello, World!". Тем и интересны.
Только вот по embedded правилам игра идет несколько по шуллерски (или по читерски если хотите). В этом нет ничего плохого, но просто надо понимать - тогда это не Embedded, а скорее Demo. Что в обзем случае тоже совсем не плохо. Да, здесь нет ОС. Но кто-то должен проинициализировать память, накопители, прочитать BOOT сектор, передать управление. Т.е. подготовить поляну для работы кода. В реальной жизни embedded проекта этого всего, как правило, нет и этим озадачен сам проект. Тут этим всем занимается BIOS. Ну да бог с ней - это не страшно, а скорее полезно. Хотя, чего тут - тот же код, но подменяющий не BOOT сектор, а образ. BIOS (раз уж он такой независимый) - это было бы сильно интереснее и показательнее и куда как ближе к тому самому embedded (хотя, безусловно, на порядок сложнее).
В частности здесь я без ассемблера не очень понимаю как и кем готовится поляна, и в первую очередь в части памяти. Поэтому предполагаю что живет она частично на предварительно подготовленном стеке, а частично делается той самой new() (допускаю, что плюсы меня сильно отравили, но все же). При этом я не вижу привычных операций по подготовке стека, очистки и инициализации сегментов данных и прочего. Того круче - я вообще не вижу обозначенных границ доступной памяти во всем проекте.
Т.е. какой-то очень специфический embedded/demo получается. И становится интересно - это недоработки проекта, полагания на то, что BOOT сектор на любой машине окажется по фиксированным адресам с фиксированнымы настройками сегментов памяти или это я слепой и не вижу где и как это все делается. В таких случаях мой арбитр всегда один - итоговый код. Ему работать - а значит в нем все будет.
А вообще интересно. Есть ли у Rust опция, которая позволяет оставлять промежуточные файлы (как у gcc)? Тот вполне в состоянии предоставить тот самый подстрочник. В реальном embedded весьма востребованный инструмент. Не ежедневного использования, но все же.
P.S.
О недоверии ассемблерным вставкам говорю не я. Я этому скорее удивляюсь. И пытаюсь понять почему так.
Ага. Осмотрелся повнимательнее. Я правильно понимаю, что это заклинание как раз сделало то, что категорически не приветствуется. Объявило unsafe контекст на весь код. И дальше не столь важно будет или не будет вложенный блок (функция) помечена как unsafe - это уже ничего не изменит. А данный пример, делает по сути не больше и не безопаснее, чем аналогичный С код? Так получается?
Тем более интересно посмотреть подстрочную трансляцию. И в первую очередь третьей строчки в этом частичном листинге.
И еще - а что реально такая большая разница между asm! в Rust и asm{} в С? Я полагал что это куда как более близкие родственники, чем #define.
Потом - не всякий ассемблер небезопасен. В частности примеры автора - надо сильно много думать, чтоб придумать их небезопасное поведение. nop как инструкция абсолютно безопасна - она просто не делает ничего (кроме инкремента PC). Чтение порта... Ну, черт знает. Была бы запись - да, возможно. Чтение... На вскидку даже не предположу что и как оно может поломать. Правда и на 100% уверенно сказать что не может не возьмусь. Но на 99,9 точно уверен - не может. Если к кого есть пример как оно может поломать - пишите. Будет интересно заняться цифровой археологией. Раз уж все равно клавиатуру из 0x60-ого порта считываем (это даже не юность - это мое детство).
Собственно потому и удивляет безусловное недоверие ассемблерным вставкам. Фобией попахивает. Или параноей. Кому что ближе.
Спасибо, стало понятнее
На Rust пишут полубоги и боги - они читают документацию на все, и все без исключения. А на unsafe функции с особой тщательностью. А на C быдлокодеры, которые документацию не читают и не пишут в принципе. Вообще и никогда. И отладке не обучены - потому где программа ломается они не знают.
А если серьезнее, то мне казалось что unsafe - это указание компилятору о том, что результат функции не безопасен и может выходить за пределы ожидаемых значений. Возможно, потребуется дополнительный контроль и выброс исключения.
Теперь буду знать, что unsafe - это не для компилятора, а для программиста. Указание на то, что надо посмотреть документацию или реализацию.
Ладно, подождем когда оно в мой мир доползет. Там и будем разбираться серьезнее. Вообще, очень хотелось бы посмотреть на ассемблерный код данного примера в режиме параллельного перевода. Как это бы транслировалось с С я понимаю. Интересно чем будет отличаться кодогенерация с Rust.
Знаете, я уже третий раз пытаюсь ответ написать. Так чтоб ненароком не обидеть тонкие чувства. Но:
Это не ответ на заданный вопрос. Если любой asm! автоматически считается небезопасным, то зачем это указывать явно в коде?
Использовать у себя код, которому нет доверия? Вы серьезно?
Если у обертки asm! не стоит unsafe, то по той же логике мы вполне доверяем. И чего спрашивается? Или это работает как-то по другому?
Впрочем, ну его. И так скорее всего из банальной опечатки столько текста наплодили.
Тем более, что главная-то претензия не здесь была. Она была к нарезки времени пустым циклом. Очень зависимо от конкретного ПК и даже его настроек энергосбережения. В свое время над Digger'ом ржали. Там такое решение было, в итоге даже на 386 он носился как наскипедаренный. А именно эту часть пропустили.
Впрочем оно тоже понятно - библиотеки с задержкой нет. А значит тут "путь самурая".
<сарказм: включено>
Ничего личного, но не спросить не могу
Думаете с мужчинами будет проще?
<сарказм: выключено>
Это ритуал такой? Типа обязательной утренней молитвы?
Или тотальное недоверие программисту по определению не умеющему safe на ассемблере?
И зачем тогда требовать его явно указывать, если это реально ВСЕГДА так?
По сути принято и понято. По факту мне сложно представить как "nop" или "in" на это способны. Если in, хоть и с большим трудом и аппаратными особенностями, но можно притянуть, то nop... Я просто хочу понять логику автора кода. И да, я крайне плохо знаю Rust. Потому часть вопросов задаю с позиции привычных мне языков (С/asm).
т.е. unsafe fn здесь реально бесполезна, как я писал в первом комментарии, как и блок unsafe вокруг asm? А опасения @Deosis абсолютно беспочвенны?
Опция "хозяйственная" исключена в принципе? Или подразумевается по-умолчанию? Или ради нее чем-то еще придется пожертвовать?
Интересно... А вариант использовать unsafe вокруг "core::arch::asm!("in al, dx", out("al") value, in("dx") port);" как это сделано в main() вокруг "nop" не прокатит? Компилятор просто выбросит не проверяя что именно функция делает?
И что же это получается - "великий и могучий" использует худшие практики SUN'овского компилятора - выбрасывать и переставлять ассемблерные вставки пользователя если ему это специально не запретить? А за одно не избавляет от избыточно умных оптимизаций кода (главная проблема на-Си-льников во встраиваемых системах)?
Вот интересно, что было бы если бы подобное было написано d основном цикле на C? А так да - великий и могучий Rust.
И еще вопрос.
А здесь-то почему unsafe? Казалось бы безопаснее функции, чем чтение порта и придумать сложно. Оно гарантированно завершится с абсолютно известным результатом?