Pull to refresh

Comments 97

я не желаю создавать очередной си-подобный язык высокого уровня !

R0=5

Но согласитесь - очень похоже. :) Хотя бы на препроцессор Си.

Действительно, ассемблерные инструкции часто неудобочитаемы и в целом, сделать человекочитаемый ассемблер не кажется плохой идеей. Я вижу проблемы с портированием специфик различных архитектур, скажем, что делать если инструкция есть на одной системе комманд, но отсутствует на другой. И, кроме того, не очень понятно, как лаконично изложить некоторые армовские инструкции, типа тех, что в состав команды включают условность и прочие подобные.

И в итоге это вырастет в некую упрощённую версию C.

Пришёл чтобы увидеть этот комикс. Он на месте. Баланс соблюдён.

К тому что теперь есть 15 взаимоисключающих проводов которые выглядят одинаково а работают непонятно как? :)

Поэтому "почти".
Работают кое-как, но работают. А другие разъёмы не работали бы вообще :D

А для 8080 – PL/M. На минуточку, на нём была написана ведущая операционка того времени.

Тоже хотел про него напомнить.

Задачу "сделать человекочитаемый ассемблер" решали ещё в Analog Devices в нулевых. Ассемблер Blackfin как пример - восхитительное безумие.

Я писал на ассемблере для ADSP-21xx. Это не безумие. Синтаксис этого ассемблера похож по идеологии, предложенной в этой статье. Синтаксис ассемблера был такой качественный, что написание программ мало отличалось от написания программ на C. Причина, по которой целесообразно было писать тогда на ассемблере - это очень малые ресурсы по памяти и требоваение учета архитектуры для эффективных проектов.
Синтаксис ассеблера ARM имеет исторические корни и изменение его сейчас не очень целесообразно по разным причинам.
Автору статьи - респект за способность мыслить нестандартно.

Ну и я про то же.

Смотришь ты на этот синтаксис. Первая мысль - "что это за дичь вообще". Вторая - "а это прикольный синтаксис". И третья - "почему вообще все ассемблеры не сделаны вот так?"

AD осознали необходимость в "ассемблере с человеческим лицом" для нужд DSP и выкатили своё решение. Жаль даже что эти идеи не получили распространения.

очень даже получили. После знакомства с Си-подобным ассемблером AD, я для всех своих микропроцессоров использовал только подобный синтаксис. Запоминать тьму мнемоник очень сложно. Хотя ассемблер обычно намного богаче и со сложными командами приходится все равно приходится что-то придумывать не похожее на Си.

Синтаксис не очень многое меняет, честно говоря... Если команды из одной вариации ассемблера в другую взаимно-однозначно переводятся – то это только вопрос относительно недолгого привыкания.

У Borland в свое время получился очень удачный ассемблер для x86 - синтаксис Ideal в TASM, в противовес традиционному синтаксису MASM. Я в 90-х даже всерьез взялся за написание книги по нему, а потом перешел на C++, и задача потеряла актуальность. В этом синтаксисе все очень логично и изящно, поддержка параметров и локальных переменных в процедурах сделана очень удобно. Я на нем плотно писал несколько лет, после него читать программы на MASM - сущая пытка.

Асм для dsp-процессоров Analog Devices выглядит примерно так. Хотя облегчает ли это программирование по сравнению с другими процессорами - черт его знает... Когда пришлось под это дело писать, его всё равно надо было плотно осваивать... Может Вы скорее о стандартизации мнемоник различных ассемблеров ???

Для меня вобщем-то примерно подобная задача сейчас тоже актуальна. Есть очень неплохой (на мой взгляд как автора разумеется) самопальный процессор, встраиваемый в FPGA (сейчас потихоньку готовлю серию публикаций о нём). Проблема - на чём его программировать. Усугубляется это в добавок тем, что он управляется микрокодом. Для того чтобы изменить под свою задачу систему команд (в разумных пределах конечно), не надо лезть в дебри верилога. Достаточно описать её на некоем простом языке(микроассемблере), получить микрокод и пересобрать проект(можно даже вообще без пересборки загрузить через аппаратный отладчик). Работы на час-полтора. А вот как менять средства разработки - черт его знает... Пока это у меня решается подробнейшим описанием на русском языке внутренностей ассемблера и симулятора. Чтобы пользователь без труда смог это переписать под свою систему команд. Но это уже ДНИ... Хотелось бы каких-то более фундаментальных решений.

P.S. На всякий случай утащил в закладки. Надеюсь в отличии от сотен и тысяч других, идея не мертворожденная.

P.P.S. Кстати можно подробнее о Вашем редакторе ??? Я сейчас тоже в качестве небольшого хобби и переключения задач пишу нечто, вдохновлённое вот этим https://github.com/rxi/lite , хотя и сильно по-своему.

История зациклилась как ей и предписано.

"С машиной поставлялся автокод АРМУ (Автокод Ряда Машин Урал), который был единым автокодом ряда ЭВМ типа “Урал”. Он был составлен с учетом особенностей этих машин и обеспечивал полную совместимость от меньшей машины к большей. Каждая ЭВМ “Урал” имела собственный транслятор с языка АРМУ на свой машинный язык. Таким образом, совместимость ЭВМ типа “Урал” была ограниченной и существовала только на уровне автокода АРМУ. "

https://computer-museum.ru/histussr/ural11.htm

p.s. первая программа, которой кто то кроме меня пользовался была написана 40 лет назад как раз для Урал-11

эхх.. и где бы почитать продолжение ? :-)

Про Уралы Серия https://computer-museum.ru/histussr/ural.htm

А вообще сайт кто то, к счастью, активно пополняет..

У меня мечта для пенсии, сделать эмулятор Урала с ПУЛЬТОМ

Кстати, я не только застал живым Урал-11 в 1983, но и в 1978 сдал первый зачёт по программированию на АЛГАМС

https://standartgost.ru/g/ГОСТ_21551-76

Господи, как же давно это было! я в 1883 только в МИЭТ поступил!

Я так понял ваш музей чисто виртуальный?

идея похожа в общих чертах...

Почитайте про PL/M и C-- – вроде оба достаточно близки к задаче, которую вы себе поставили, возможно, почерпнёте идеи.

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

Как вам уже написали, делая кроссплатформенный ассемблер, вы приходите к языку высокого уровня.

Выглядит это примерно так: на одном процессоре есть какие-то инструкции, а на другом нет. Значит берём некое очень ограниченное подмножество инструкций, которые есть на всех рассматриваемых процессорах, а потом для каждого конкретного сворачиваем последовательность микрокодов в одну инструкцию с помощью хинтов (фактически - шаблонов), а там, где не свернулось, работает эта самая микропрограмма. пусть и не так эффективно (и даже может быть свёрнута в несколько операндов). Микрокоды, это некая стековая машина, PI код, или LLVM IR, поэтому, фактически, мы можем придти к тому. что сами микрокоды вообще не являются усечённым подмножеством любой из архитектур, а являются полностью виртуальными. На втором шаге, выделив типовые последовательности, микрокодов, для конкретных программ, даём им имена и получаем операторы ЯВУ и конкретный кроссплатформенный язык.

Похоже большинство коментаторов не понимают, чем ассемблер (даже с макросами) отличается от языка высокого уровня. Когда мы пишем на ассемблере, мы сами определяем, какие инструкции и в каком порядке будут исполняться процессором. Когда мы пишем на ЯВУ - мы забываем про инструкции процессора и вообще не думаем о них. То, что делает автор статьи - это ассемблер, несмотря на то, что для разных процессоров одна и та же мнемоника транслируется в разные команды. Мы непосредственно оперируем регистрами и адресами в памяти, а не перекладываем это на компилятор. Мы можем сосчитать, сколько тактов процессора и сколько байт в памяти займет наша программа. Мне не приходилось писать на ассемблере одну программу под разные архитектуры, но, возможно, кому-то это будет полезно.

То что автор предлагает, это ад, мрак с содомия некоторое расширение.. чего? за счет препроцессора? компилятора? кто будет это поддерживать? без вендорного интереса?

ну это не коммерческий проект.. да и до вендоров сейчас даже дальше чем до китая :-)

то что я пытаюсь сделать будет являться неким препроцессором результат которого будет скармливаться gnu as

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

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

вот поэтому я и говорю о некотором подмножестве инструкций максимально приближенных к ассемблеру..

на счет подсчета количества тактов (гм.. со времен AVR этим не занимался) - но задумка редакторе что генерируемый асм код доступен постоянно - так что посчитать можно еще на этапе редактирования программы, а не искать тот или иной фрагмент в листинге компилятора...

Порядок инструкций всё же зависит от процессора. Вот вам ассемблер для семейства TMS320C672x - предположите, что произойдёт раньше:

  1. прыжок по адресу B3 (строка 12) ?

  2. запись A3 в *A4 (строка 16) ?

_SumF3:
    ldw   *B4++,  B5
||  ldw   *A6++,  A5
    ldw   *B4++,  B7
||  ldw   *A6++,  A7
    ldw   *B4++,  B6
||  ldw   *A6++,  A3
    nop   2
    addsp A5,   B5,   A5
    addsp A7,   B7,   A7
    addsp A3,   B6,   A3
||  b   B3
    nop
    stw   A5,   *A4++
    stw   A7,   *A4++
    stw   A3,   *A4
    nop

Но проще понимается, конечно, вот такое:

void SumF3(float *dst, float *src1, float *src2) {
	*dst++ = *src1++ + *src2++;
	*dst++ = *src1++ + *src2++;
	*dst = *src1 + *src2;
}

Вы и на C++ можете ими(адресами, регистр это тоже ячейка памяти) оперировать.

Я думаю в первую очередь мир нуждается в свободном симуляторе цифро-аналоговых цепей, таком как Proteus или может Simics. Потому что очень хочется сначала прототипировать, а потом паять.

Я задумывался над этим вопросом...
Суть проблемы в том что трудно в целом мысленно организовать подобную идею.

Во первых - Многие архитектуры довольно сильно отличаются, потому сделать такую банальную вещь как "относительный переход" довольно запарно. Везде это будет работать по разному. То есть call type_add[ptr] может тупо не собраться и требовать специфических ассемблерных вставок. То есть, уже базовые механизмы работы с потоками управления\данными могут сильно отличаться и требовать неявно вставлять код. (грубо говоря, как AVR не поддерживает float и плодит кучу кода чтоб сделать 1.0+1.0)

Во вторых - этот язык должен быть одновременно "не типизрованным" и уметь в "типизацию". Для большинства архитектур в целом не важно что есть байты в памяти, это может быть как адрес-указатель так и float. При этом нужно учитывать что A + B невалидная операция, ибо что вообще есть +? Это SIMD расширение, 4float или 2double?? Это что-то от FPU? Это число, знаковое число?

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

В четвёртых - Это всё будет нормально работать вплоть до того как не появится второе ядро. Тогда придётся вводить кучу абстракций чтоб победить все эти "страшные многоядерные проблемы".

Ну и в пятых - Это не имеет смысла для процессоров с микрокодом. Потому-что архитектура таких процессоров может неявно обрабатывать какие-то последовательности команд тупо лучше. Как в х86 есть суперкороткая команда, в 2 байта, для for циклов, но она раз в 10 медленнее чем последовательность test+jne+inc+jmp, которая чуть ли не под 16 байт памяти съедает. (точно не помню, но суть в этом)

В сумме к самой архитектуре должны быть предъявлены серьёзные ограничения, что бы она могла собираться из такого "низкоуровневое кода". Продумывание всех этих деталей, лично для меня, слишком геморная задача и я бросил это.

ЗЫ - помимо всего этого, должна быть явная поддержка чистого ассемблера со стороны компилятора + препроцессор (чем мудрёнее тем лучше). Чтоб можно было ручками более чётко прописать что ты хочешь от кода. (И моё ИМХО - не дёргать регистры руками. Этим умеет заниматься компилятор и более эффективно. Если надо то как-то отдельно помечать переменную явно как "регистровую")

Во вторых - этот язык должен быть одновременно "не типизрованным" и уметь в "типизацию". Для большинства архитектур в целом не важно что есть байты в памяти, это может быть как адрес-указатель так и float. При этом нужно учитывать что A + B невалидная операция, ибо что вообще есть +? Это SIMD расширение, 4float или 2double?? Это что-то от FPU? Это число, знаковое число?

Ну тут все таки я говорю об ассемблере, а у него типизация всегда ложилась на голову программиста...

Опять таки, я занимаюсь программированием микроконтроллеров, и там далеко не все задачи требуют full hd сенсорного экрана с wifi... зачастую на микроконтроллерах реализуются намного более простые задачи, и часто вообще без float типов и вычислений !

не считайте меня человеком который готов ассемблер приплетать к любой задаче !! но и поверьте очень очень очень далеко не везде нужен даже просто си... особенно когда нужно еще и уместить в недорогой чип всю функциональность....

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

да, и об этом я говорю в видео.. конечно часть библиотеки будет транслироваться в блоки кода.. а не в одну инструкцию

В четвёртых - Это всё будет нормально работать вплоть до того как не появится второе ядро. Тогда придётся вводить кучу абстракций чтоб победить все эти "страшные многоядерные проблемы".

неее, второе ядро, 480 мгц - это все уже СИ !!! с ума сходить надо потихоньку :-) асм не для таких задач.. и в наше время есть более подходящие языки (тут я первый об этом скажу!)

ЗЫ - помимо всего этого, должна быть явная поддержка чистого ассемблера со стороны компилятора + препроцессор (чем мудрёнее тем лучше). Чтоб можно было ручками более чётко прописать что ты хочешь от кода. (И моё ИМХО - не дёргать регистры руками. Этим умеет заниматься компилятор и более эффективно. Если надо то как-то отдельно помечать переменную явно как "регистровую")

вы просто читаете мои мысли... !

а вы свои размышления никак не формализовывали ? (чтобы я мог почитать) мне очень не хватает любого опыта (положительного, отрицательного, среднего) - просто чтобы примерно понять с тонкостями той или иной реализации...

 и там далеко не все задачи требуют full hd сенсорного экрана с wifi...

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

второе ядро, 480 мгц - это все уже СИ 

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

а вы свои размышления никак не формализовывали ?

Увы но нет, это просто мои потные фантазии как бы я хотел что бы что-то работало. Мол, я писал и асм код и на JIT языках сидел и сейчас сижу на С++, и просто имея этот весь опыт, у меня сложилось понимание что и как можно сделать. Но время которое надо затратить чтоб придумать весь этот язык, отталкивает чтоб начать этим заниматься.

Иначе... Если есть вопрос, я могу сообразить ответ, а тут как раз статья...

Мое мнение, Вы пытаетесь изобрести ООП, и хотите сделать статический полиформиз для поддержки разных архитектур, дак уже всё придумано С++ и шаблоны. вот, например, конфигурация Pin хоть в что, на любой платформе.

Pin<Config>::Set();

хотите сделать конфигурацию пина в во вход на любой платформе:

using PinToInput = Pin<ConfigToInput>:
PinToInput::Set();

останется только определить Configи для разных платформ и реализации Set(), ну или Set() тоже может быть одинаковыми, но тогда реализация должна быть в Configах

Как то баловался таким.

https://habr.com/ru/post/473612/

https://disk.yandex.ru/i/ajCQtg1GEPPdRQ

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

Мне кажется надо несколько по иному решать эту проблему. Имея большой опыт разработки программ на Ассемблере (программировал на ассемблер IBM, DEC, Intel) могу сказать, что основная сложность при программировании на Ассемблере не в написании команд МОV, ADD и т.п., а в написании инструкций по управлению самой программы. Если программист занимается программированием МК, то вряд ли он программирует несколько разных МК одновременно. То есть он эти команды для конкретного МК запоминает в течении 2-3 недель. А вот отсутствие возможности иметь операторы if, while, do (простом цикл), until является основной трудностью. Мною в дипломной работе были реализованы эти инструками для ассемблера ЕС ЭВМ. Для чего использовал ся макрогенератор ассемблера. Программа получалась со сложной логикой управления гораздо меньше по размерам, намного читабельной и более надежной. Минусом было увеличение времени трансляции.

может быть присоединитесь к моей группе телеграмм ? ( https://t.me/ArmAsmEditor )

мне нужен опыт (и желательно разный) от людей пишущих на асме...

в своем первом редакторе попытался некоторые задумки реализовать (заодно можете оценить, правда он для arm cortex ассемблера)..

может быть смогли бы предложить еще какие то идеи по функциональности....

Может быть вопрос не ко мне. но могу мысль свою уточнить. Реализация структурного программирования для ассемблер была реализована в 1978 г. сейчас я осваиваю ассемблер AVR. Хочу освоить и научить внука. Так вот, основная идея - не создавать новый язык, а оставаясь в рамках ассемблера получить значительный рост производительности, читабельности и надежности, как я уже отмечал. Операторы if, do, while, until генерируют текст на ассемблере, реализующий эти операторы. Условные выражения в них имели вложенную скобочную структуру. Например:

if ((оп1.AND.оп2).OR.(оп2.OR.оп3))

где оп -- операнд

Анализ логического выражения выполнялся средствами макрогенератора самого ассемблера - по сути это нулевой проход при трансляции программы. Реализован с помощью рекурсии. Для каждого МК конечно надо будет реализовывать свою реализацию, но если реализовать анализ лог.выражения, то генерация кода ассемблера для конкрентного МК не самая сложная задача. На основе этого подхода был создан пакет программ: разузлование и вхождение. Это классические задачи того времени. Разузлование: из скольких деталей и в каком количестве состоит тот или иной узел, вхождение: в какие узлы и в каком количестве входит деталь. Этот пакет позволил ускорить выполнение этих задач для крупного изделия (например авто) раз в 20. Не трое суток, что было невозможно для ЭВМ того времени из-за их ненадежности, а 2-3 часа

для ассемблера AVR как то тоже не нашел удобного редактора.. писал в WinAVR в свое время.. чуть удобнее блокнота конечно, но все равно не то...

сам реализовывал в первую очередь те функции которых не хватало лично мне...

получилось примерно так:

https://youtu.be/UTGufdw_D4Y

Что-то у меня не открывается. Мне кажется надо упростить. Сделать препроцессор, который на основе текста на ассемблере конкретного МК с логикой на основе структурных операторов генерирует текст на ассемблере. Этот сгенерированный текст можно использовать в ATM Studio. Пример исходного текста:

add op1,op2

inc R1

if (R1.GT.op1)

mov r2, op3

mov r3, op2

while ((r1.EQ.r3).OR. (op3.LT.r2))

mov ...

add ...

inc ...

endwhile

endif

и т.д.

Замечание: смысла в приведенных операторах нет. Это как пример оформления.

EQ - =

GT - >

LT - <

А делать новый язык -- смысла нет. Мне кажется для ассемблировщиков этого достаточно. И логика программы видна и каждый оператор и написанный и сгенерированный на виду, доступен в отладке. Затем уже если есть желание можно реализовать и препроцессор, и транслятор в одной среде.

не открывается ссылка на ютуб ? гм...

или я что-то не так делаюЖ

И? открывайте плейлист ! GNU ARM ASM EDITOR

можно просто в ютубе в поиске набрать ArmAsmEdit и там найти любое видео, и там в подсказках будет ссылка на весь плейлист и на следующее видео

еще одно замечание и предложение.

Мне как программисту на ассемблере нетрудно написать MOV R1, 5 ,более того это естественнее, чем R1 = 5 . В отладчике я увижу MOV , зачем мне еще помнить, что он относится к R1 = 5. Но если вы создаете IDE для ассемблера, было бы лучше реализовать след.возможность: при наведении курсора на команду всплывает окно с информацией об этой конкретной команде - сколько байт она занимает, количество тактов, шестнадцатеричный формат. Когда я программировал на стене висел для i86 плакат, где для каждой команды была эта информации. Это помогало. И при программировании систем реального времени кол-то тактов очень значимо для оптимизации работы программы. при обработке текущего прерывания, происходит еще прерывание. Необходимо и обработать текущее и не потерять новое. Вот здесь и важен анализ скорости выполнения команд. Весьма возможно, что это уже реализовано.

Я как-то делал плагин для вижуал студии, где можно было ещё и привязать комментарий к регистру, типа
mov ecx,0;=индекс
и ниже по тексту при наведении мышкой этот комментарий появлялся во всплывающей подсказке.


Ну и фолдинг (сворачивание кусков кода в одну строчку) тоже полезная вещь для асма.

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

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

то есть от асма я отходить не хочу...

Ну так у меня это уже сделано… А у вас?

у меня пока идет проработка языка..

ну это пока вы программируете в рамках одной архитектуры.. и ваши инструкции не слишком сложны (посмотрите арм-ассемблер, а потом risc-v ассемблер - они как антиподы :-) у одного много различных сложных инструкций, а у второго - вроде все инструкции простые - но тоже свой синктаксис и мнемоники....)

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

ну и насколько возможно сделать суррогатный микрокод для эмуляции тех инструкций которых нет на одной из архитектур..

про размер инструкции - в арме это зачастую так просто не работает (есть тумб2 формат - а это 16 бит вместо 32ух.. и есть еще выравнивание.)...

тоже самое и про число тактов - для этого есть DWT и там все бывает очень интересно в зависимости от того какое выравнивание у инструкции, и проще по DWT определять реальные цифры чем пытаться высчитать..

да и сейчас наверное все новые архитектуры умеют работать с вложенными приоритетными прерываниями ..

"смысл в том чтобы создать одинаковые мнемоники плюс минус для разных архитектур... "

Есть "Искусство программирования"(автор Кнут по моему). в ней представлен некий ассемблер. По сути уровень абстракции, но в пределах ассемблера. Если для RISC процессоров один оператор этого ассемблера требует генерации нескольких команд, то для классических (Intel, Motorola и т.п.) - один в один. Но в случае скажем так предельных MIPS архитектур (DEC), в команде которого может "содержаться" несколько команд процессора например Intel -- cделать на основе псевдокода генерацию команд для такого процессора -- непростая задача в рамках ассемблера, может даже невыполнимая. Для транслятора с Си это решаемо. Но мне кажется время таких процессоров ушло.

Современными процессорами я начал заниматься недавно и пока не в курсе о DWT и о вложенных приоритетных прерываниях и как их программно отрабатывать. Посмотрю.

...потом появится желание обеспечить повторное использование программ для различных ядер, чтобы по два раза не переписывать

...для этого понадобится привести архитектуры к одному общему виду

...называется это Форт

Который дергает стек при любой операции, сводя к нулю преимущества современных процессоров с кучей регистров.

да, плюс к этому программу на асме когда идет активная работа по сохранению всего подряд на стек очень тяжко отлаживать именно как асм программу...

переносимый язык позволяет кроссплатформенную отладку

я не фанат Форта, просто ваши комментарии противоречат целям заявленным в статье

Форт не такой уж и плохой язык, но он эффективен на стековых машинах, которые медленее регистровых. Это заметно даже на виртуальных машинах. Так каноническая виртуальная машина Java - 8-разрядная стековая машина. Однако виртуальная машина Dalvik для Java, используемая на смартфонах андроид, представляет собой 16-разрядную машину с виртуальным регистром - выбор сделан из соображений эффективности. Но в целом идея автора напоминает, что-то типо форта или C--.

а про С-- где посмотреть ? гугл только про си выдает результаты и си++.. :-(

https://habr.com/ru/company/kolibrios/blog/303582/

Вы абсолютно правы.

Продолжу: в статье предложено свести оптимизированные к архитектуре синтаксисы ассемблеров к некоему обобщенному.

Как вы считаете, этот подход позволит использовать "преимущества современных процессоров с кучей регистров"?

а что за преимущества в куче регистров вы выделяете ? не дергать постоянно память если данные можно хранить в регистрах ?

так вроде нет препятствий

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

1) зачем введено такое понятие, почему нельзя иметь сквозную нумерацию регистров, а компилятор сам распределит где виртуальные, а где нет?

ну просто подразумевается что виртуальный регистр это некоторая именованная ячейка в памяти.. значение которой м.б. использовано в выражениях...

для ассемблера гонять регистры на стек\со стека - реально не всегда удобно при отладке :-( да и с точки зрения быстродействия выгоды не столь очевидны (а иногда и просто нет)

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

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

А решение будет сделано на chat gpt. Причем код никто не поймет, но он будет работать для нужного процессора )))

Желание унифицировать вариации mov понятно и это легко. А что действительно сложно, так это:

1) на одних платформах есть флаги, на других нет. Как унифицировать не только циклы, но и длинную арифметику?

2) на одних платформах есть векторные инструкции, на других нет. Как унифицировать MMX, SSE, AVX и прочие? Даже ведущие программисты из Microsoft и Intel не справились с этим, размерность векторных инструкций в интринсиках задаётся всё ещё явным образом.

3) на одних платформах есть произвольный доступ к регистрам, на других — нет (FPU как пример). Даже ведущие компиляторы от ведущих уже названных компаний не умеют по максимуму использовать весь стек FPU, ограничиваясь стандартными шаблонами и верхними двумя регистрами.

4) на одних платформах двух-операндный синтаксис, на других трёх-, на третьих только и исключительно четырёх-. Вопрос тот же самый — как их унифицировать?

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

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

но на каких то алгоритмических фрагментах - си компилирует так как это сделал бы человек на асме, это действительно так...

например, неоднократно видели когда си применяет при работе с битовыми полями and\or хотя есть например BFI... возможно это из за того что на cortex-m0 просто нет bfi в системе команд... но в cortex-m3 \ cortex-m4 все равно используется and\or...

четырехоперандный синтаксис? Как такая платформа называется? И, если не затруднит, пример кода где это используется.

FMA4 например. Примеры кода наверняка найдутся в официальной документации.

ну, это расширение, а не платформа. Отдельные четырехоперандные инструкции есть и в каком-нибудь RISC-V (fmadd rd, rs1, rs2, rs3)

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

Так-то трехоперандных архитектур полно, те же ARM или RISC-V


Двухоперандные это например AVR.


1.5-операндные это например PIC (пол-операнда это один бит, с равным успехом можно добавить еще десяток мнемоник и счесть однооперандным).


Вот и интересно существуют ли в природе честные однооперандные, безоперандные и те, в которых операндов больше трех.

Вот и интересно существуют ли в природе честные однооперандные

Форт-машины, пожалуй, так как там второй операнд стек неявно.

Плюс за старание и стремление к самосовершенству.

Я тоже стал придумывать микроязык для своего релейного компьютера.

Основной фичей должна быть удобная работа с флагом переноса. Например, чтобы можно было сдвигать переменные по цепочке. Или складывать, используя дальше получившийся бит переноса для проверки условия.

Правда синтаксис ещё не доточил, потому что компилятор не готов пока что.

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

я не желаю создавать очередной си‑подобный язык высокого уровня!

А зря. Я в начале 90-х тоже предпочитал ассемблер языкам высокого уровня, поскольку между ними был существенный разрыв - стоило перейти хотя бы на C, чтобы потерять контроль над рядом аспектов размещения и выполнения кода/данных, которые могли быть важны для задачи. То, что большинство тогда писало на C, C++ и Pascal, я писал на ассемблере, и был вполне доволен. :)

А потом оказалось, что есть реализации и C, и даже Pascal, очень сильно приближенные к машинному уровню, где можно произвольно манипулировать размещением кода/данных в памяти, непосредственно использовать регистры в виде псевдопеременных, где ряд встроенных функций напрямую раскрывается в соответствующие команды процессора и т.п. Мне не приходилось писать для контроллеров ARM, но после перехода на VC++ в 90-х я совершенно потерял интерес к ассемблеру, поскольку практически все, что я привык контролировать на уровне команд и ячеек, можно было делать и в программе на C/C++, произвольно меняя уровень абстракции в любом месте. И это при том, что VC++ сильно уступал в этом тому же BC++.

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

Безумству смелых, поём мы песню. А я всё больше влезаю в HAL, хотя всё моё естество этому противится. Но так проще заработать, чем писать проги в машинных кодах, как в счастливые студенческие времена!

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

Так что спускаюсь на уровень команд процессора лишь в очень экзотических случаях.

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

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

ну если вы улучшить не можете - возможно вы просто не знаете ассемблера... вот и все... и компилятор си тут не при чем :-)

если в коде выше вы не можете ничего улучшить - то без комментариев...

потому что кто хоть немного знает - он бы из 4 инструкций оставил 2, если хорошо знает ОДНУ инструкцию !!!!

и это на каких то 4х строчках кода.... 4 байта как минимум экономии и минимум 2 такта исполнения

p.s. это из под куба

Я видел и более убогие компиляторы. Такого же результата можно добиться отключением оптимизации. Но какое отношение они имеют к программировании на ассемблере?

В тексте выше есть слово "оптимизирующие". Вам оно о чем то говорит?

я отвечал на ваш вопрос про то какой код генерит компилятор си...

и поверьте - оптимизации включены

и вопрос про ваше знание ассемблера остался - так на что заменить этот говнокод ?

Но есть же проект LLVM, в котором как раз и используется некий "высокоуровневый" ассемблер с виртуальными регистрами, а backend транслирует его в машинный код под конкретную архитектуру.

Если хочется добавить поддержку периферии МК, то можно использовать LLVM API, чтобы написать свой front-end для LLVM.

Вот пример кода (HelloWorld, сложение a + b в с, а также дергание пином/реле):

; ModuleID = 'main'
source_filename = "main"
target triple = "thumbv7m-none-none-eabi"

@__str0__ = constant [14 x i8] c"Hello, World!\00"

declare void @RELAY_TOGGLE(i32 %0)
declare void @Println(i8* %0)

define i32 @main() {
entry:
  %a = alloca i32
  store i32 10, i32* %a

  %b = alloca i32
  store i32 5, i32* %b

  %a1 = load i32, i32* %a
  %b2 = load i32, i32* %b
  %add = add i32 %a1, %b2

  %c = alloca i32
  store i32 %add, i32* %c

  %c3 = load i32, i32* %c
  tail call void @RELAY_TOGGLE(i32 %c3)

  tail call void @Println(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @__str6__, i32 0, i32 0))
  
  br label %end
end:                                              ; preds = %entry
  ret i32 0
}

Тоже хотел написать.

Есть же llvm !

Все уже придумано.

Sign up to leave a comment.

Articles