<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом m4</title>
<link>https://blogengine.me/blogs/tags/m4/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Немного о сложностях написания ассемблера на m4</title>
<guid isPermaLink="false">135849</guid>
<link>https://bolknote.ru/all/nemnogo-o-slozhnostyah-napisaniya-assemblera-na-m4/</link>
<pubDate>Sun, 18 May 2025 17:56:58 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/nemnogo-o-slozhnostyah-napisaniya-assemblera-na-m4/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Не думаю, что я много буду использовать язык &lt;i&gt;m4&lt;/i&gt; в будущем, если вообще буду, поэтому хотел дать себе и, возможно, кому-то из читателей чуть больше контекста о том как писался на этом макропроцессоре &lt;a href="https://bolknote.ru/all/assembler-processora-i8080a-na-m4/"&gt;ассемблер процессора 8080A&lt;/a&gt;. А то со временем всё забудется.&lt;/p&gt;
&lt;p&gt;Для этого я чуть-чуть больше расскажу о &lt;i&gt;m4&lt;/i&gt; и ассемблере 8080A.&lt;/p&gt;
&lt;p&gt;Ассемблер 8080А довольно простой. Будучи школьником, я его выучил по комментариям к кускам кода, которые печатались в журнале «Радио» — другой литературы в моём доступе не было. В нём всего несколько команд, большинство из них имеют один или два параметра.&lt;/p&gt;
&lt;p&gt;Посмотрим, например, на команды &lt;tt&gt;ADD B&lt;/tt&gt; и &lt;tt&gt;ADD C&lt;/tt&gt;. Первая эквивалентна &lt;tt&gt;A += B&lt;/tt&gt; на других языках, вторая — &lt;tt&gt;A += C&lt;/tt&gt;. Буквами обозначаются регистры, для простоты можно считать их именованными переменными. Их мало, всего несколько штук и они имеют свои особенности. Например, в этих двух командах мы видим особенность регистра &lt;tt&gt;A&lt;/tt&gt; — к нему можно прибавлять значения других регистров.&lt;/p&gt;
&lt;p&gt;Команды &lt;tt&gt;ADD B&lt;/tt&gt; и &lt;tt&gt;ADD C&lt;/tt&gt; для исполнения компьютером переводятся в числа — в машинные коды. Обычно их записывают в шестандцатеричном виде, я тоже так буду делать. Данные команды сложения кодируются как числа &lt;tt&gt;80&lt;/tt&gt; и &lt;tt&gt;81&lt;/tt&gt; соответственно.&lt;/p&gt;
&lt;p&gt;Теперь немного про &lt;i&gt;m4&lt;/i&gt;. Я писал выше, что &lt;i&gt;m4&lt;/i&gt; — макропроцессор, если упрощать, язык макропроцессора позволяет указать как одни «слова» заменить на другие. «Слова» при этом должны начинаться с буквы или подчёркивания и содержать только буквы, цифры или знак подчёркивания. Это ограничение очень важное. Не будь его, я бы задал по одному правилу на каждую команду: &lt;nobr&gt;&lt;tt&gt;ADD B → 80&lt;/tt&gt;&lt;/nobr&gt;, &lt;nobr&gt;&lt;tt&gt;ADD C → 81&lt;/tt&gt;&lt;/nobr&gt; и был таков.&lt;/p&gt;
&lt;p&gt;К сожалению, так это не работает. Из-за этого ограничения, когда макропроцессор встречает &lt;tt&gt;ADD&lt;/tt&gt;, он ещё не знает что будет дальше, поэтому не может выбрать на какой код заменить это слово, а когда дальше он видит &lt;tt&gt;B&lt;/tt&gt; или &lt;tt&gt;C&lt;/tt&gt;, ему надо помнить, что было до этого, так как с этими регистрами работает много команд. Другими словами, макропроцессору нужно запоминать контекст.&lt;/p&gt;
&lt;p&gt;В руководствах по &lt;i&gt;m4&lt;/i&gt; указывается, что этот макропроцессор контекст учитывать не умеет. Так и есть, встроенных конструкций, предназначенных именно для этого нет, но можно выкрутиться менее специфичными. Дело в том, что &lt;i&gt;m4&lt;/i&gt; может проверять как выглядят его текущие правила замен одного слова на другое.&lt;/p&gt;
&lt;p&gt;Поэтому мы можем завести специальное правило, куда будем записывать какая команда нам встретилась, а позже, встретив имя регистра, будет проверять чему равно наше специальное правило и производить замену, основываясь на этом.&lt;/p&gt;
&lt;p&gt;При этом &lt;i&gt;m4&lt;/i&gt; не делает различий между, так сказать, текстом программы и обрабатываемым текстом, для него это одно и то же. То есть макропроцессор делает возможным метапрограммирование — позволяет менять программе свой собственный текст.&lt;/p&gt;
&lt;p&gt;Вот как это выглядит в коде:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="plaintext"&gt;dnl заменяем строку ADD на определение макроса, сама строка ADD при этом пропадёт
define(`ADD&amp;#039;, `define(`__cmd&amp;#039;, `__s_ADD&amp;#039;)&amp;#039;)dnl

dnl когда встречаем B, смотрим чему равно определение макроса __cmd
define(`B&amp;#039;, `
ifelse(
    defn(`__cmd&amp;#039;), `__s_ADC&amp;#039;, 88,
    defn(`__cmd&amp;#039;), `__s_ADD&amp;#039;, 80,
    …тут остальные команды…
    `&amp;#039;)
&amp;#039;)dnl

dnl когда встречаем C, смотрим чему равно определение макроса __cmd
define(`C&amp;#039;, `
ifelse(
    defn(`__cmd&amp;#039;), `__s_ADC&amp;#039;, 89,
    defn(`__cmd&amp;#039;), `__s_ADD&amp;#039;, 81,
    …тут остальные команды…
    `&amp;#039;)
&amp;#039;)dnl&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы дойти до этого трюка, пришлось поломать голову, но тем интереснее. Возможно он где-то уже описан, но искать информацию по &lt;i&gt;m4&lt;/i&gt; очень тяжело — поисковые машины охотно путают его с одноимённым процессором, а нейросети пишут какую-то пургу, не имеющую никакого отношения к реальности.&lt;/p&gt;
</description>
</item>

<item>
<title>Ассемблер процессора i8080A на m4</title>
<guid isPermaLink="false">135830</guid>
<link>https://bolknote.ru/all/assembler-processora-i8080a-na-m4/</link>
<pubDate>Fri, 16 May 2025 10:40:51 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/assembler-processora-i8080a-na-m4/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Сегодня опять сычевал почти до полуночи — вечером попался кусок кода на &lt;i&gt;m4&lt;/i&gt; и я, пробормотав вечное «когда-нибудь надо бы его выучить», вдруг подумал — а почему бы и не сейчас? Я и так всё время откладываю, а этот вечер ничем для этой цели не хуже, чем любой другой.&lt;/p&gt;
&lt;p&gt;Чтобы разбираться было веселее, придумал себе задачу — написать на &lt;i&gt;m4&lt;/i&gt; ассемблер, желательно не очень сложный, чтобы занятие на вечерок не разрослось потом до недельного проекта. Взял &lt;a href="https://web.archive.org/web/20131014125438/https://demin.ws/projects/radio86/info/kr580/i8080.html"&gt;инструкции интеловского процессора 8080A&lt;/a&gt; — это был мой первый ассемблер. Советской аналог процессора стоял на компьютере «Радио-86РК», с &lt;a href="https://bolknote.ru/all/4316/"&gt; которого я когда-то начинал&lt;/a&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.05.15@2x.webp" width="1000" height="665" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Строка «HELLO WORLD», выведенная программой, переведённой в машинный код моим ассемблером&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Несколько слов о том что такое &lt;i&gt;m4&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Это довольно простой макропроцессор, умеющий заменять одни указанные строки на другие. Описание что на что заменить делается параметрическими макросами. В языке есть собственные макросы, но можно определить и пользовательские. Поддерживаются так же условия и математика. В продвинутых версиях &lt;i&gt;m4&lt;/i&gt; есть даже циклы, но их в любой версии можно эмулировать рекурсией.&lt;/p&gt;
&lt;p&gt;Парочка примеров того как выглядит его синтаксис:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="plaintext"&gt;dnl Макрос, заменяющий одну строку на другую
define(`WORLD&amp;#039;, `KAZAN&amp;#039;)dnl

dnl Макрос, оставляющий первый свой параметр как есть, а
dnl второй складывающий со значением другого макроса,
dnl если второй параметр не указан, его значение — единица
define(`__pr&amp;#039;, `define(`__ip&amp;#039;, eval(__ip + ifelse($2, `&amp;#039;, 1, $2)))$1&amp;#039;)dnl&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы реализовать задуманное, я взял список команд процессора с кодами — их там чуть меньше 250, если брать варианты с разными регистрами, и написал на Пайтоне два генератора.&lt;/p&gt;
&lt;p&gt;Два, потому что мне нужно было как-то решить проблему расчёта адресов ссылок. Первая программа генерирует файл &lt;tt&gt;linker8080.m4&lt;/tt&gt;, который этим и занимается. Адреса он на следующем этапе передаёт в виде макросов второму файлу — &lt;tt&gt;asm8080.m4&lt;/tt&gt;, который делает основную работу — переводит ассемблер в машинные коды.&lt;/p&gt;
&lt;p&gt;Сначала у меня всё было сделано в одном файле, но я быстро выяснил, что макросы распространяются сверху вниз, то есть определённые ниже макросы не влияют на текст выше. Если ссылка, для которой я подсчитал адрес, находится ниже точки вызова, я этот вызов уже не могу заменить.&lt;/p&gt;
&lt;p&gt;Вот программа на этом ассемблере, в действии её можно посмотреть на скриншоте:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="asm"&gt;ORG(h1100)
LXI H, ADDR(TEXT)
CALL hF818
JMP hF86C

LABEL(TEXT)
BYTE(h48, h45, h4C, h4C, h4F, h20, h57, h4F, h52, h4C, h44, hD, hA, h0)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Не слишком отличается от привычного вида, но отличия всё-таки есть.&lt;/p&gt;
&lt;p&gt;Во-первых, числа должны быть только шестнадцатеричными. Часто так и бывает, но тут запись немного непривычная — &lt;tt&gt;hFF&lt;/tt&gt; вместо более привычной &lt;tt&gt;FFh&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Во-вторых, многие вещи, не генерирующие код, выглядят чуть иначе — адрес запуска задаётся конструкцией &lt;tt&gt;ORG(…)&lt;/tt&gt;, метка — через &lt;tt&gt;LABEL(…)&lt;/tt&gt;, а её адрес получается через &lt;tt&gt;ADDR(…)&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;В-третьих, произвольные цепочки байт задаются не директивой &lt;tt&gt;DB&lt;/tt&gt;, а конструкцией &lt;tt&gt;BYTE(…)&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Результат можно увидеть у меня &lt;a href="https://github.com/bolknote/M4-8080A-Asm"&gt;в репозитории&lt;/a&gt;.&lt;/p&gt;
</description>
</item>


</channel>
</rss>