Info Guide #12
31 декабря 2017

Системки - NedoLang: Куда плыть дальше (часть 6).

     Куда плыть дальше
Alone Coder

   Компилятор уже собирает себя сам. В нём
уже можно релизить релизы.Это уже продукт. 
   Молодой сотрудник, на которого я возла─
гал  надежды, отказался портировать компи─ 
лятор  на  ARM. Хотя  раньше обещал, когда 
компилятор  был  маленький  и  нестрашный. 
Придётся самому. 
   Ускорение самосборки  пока что  зашло в
тупик. За  минуту  никак  не пересоберёшь. 
Появилось ещё только две радикальных идеи: 
 ё)токенизировать  исходники на NedoLang
(ключевые слова и двойные символы) 
 ж)генерировать obj (с патчами) прямо из
компилятора (тогда  нельзя  асмовставки  и 
асмопроцедуры - только асмомодули),сделать 
специальный линкер или лоадер. 

  15.05.2017: пытался ускорить лексер че─
рез  чтение  строки в буфер. Но проблема с
длинными  строками.  Если проверять длину,
то скорость та же. Ограничить длину строк?
Пока в исходнике есть весьма длинные стро─
ки. Их  и так  надо сократить, чтобы можно
было удобно редактировать на Speccy. Я да─
же  рисовал самый маленький на свете шрифт
4x2, написал показывалку и тестировал про─
смотр исходника с ним. Результат этого эк─
сперимента  я использовал, когда вырабаты─
вал стиль оформления исходника.



  17-18.05.2017:
  - теперь  имена  процедур в ассемблере -
без точек в конце,а автометки - с точками.
  - теперь _ в начале глобальных идентифи─
каторов  не  нужно. Локальные метки именно
временно  перекрывают  глобальные, а потом
удаляются из таблицы меток.
  - придумал, как ускорить== и != . Но не
сделал.
  - мысли:
   Как форвардить переменные: игнорировать
одинаковые - совместимо с Си. 
   Как форвардить константы? Брать послед─
нюю (можно и как метку, и как переменную). 
Это не сработает,если ассемблируем по час─ 
тям, сработает,если ассемблируем всё в ку─ 
чу. 

   Ассемблер должен склеить:
  1. модуль  неявных  математических функ─
ций (компилятору не нужно,но кодогенератор 
подклеивает  нужный? или скрипт компиляции 
меняется в зависимости от таргета?) - под─ 
ключать в конце, чтобы были только исполь─ 
зуемые процедуры 
  2. заголовочный файл  ОС (компилятору не
нужно, про  этот  файл знает только скрипт 
компиляции под данный таргет!!!) 
  3. модуль  запуска? или  два - начало  и
конец? (компилятору не нужно, ditto) 
  4. код + код + код...
  5. переменные+переменные+переменные...
  6. строки + строки + строки...

   Можно в недоасме исключить неиспользуе─
мые процедуры на втором проходе? 
   Надо какой-то хитрыйif,который прове─
ряет,  есть  ли процедура в метках первого 
прохода на втором проходе. 
   Но  тогда не получится исключить проце─
дуру, которая  используется только в неис─ 
пользованной процедуре. 
   (Пока  что  в  NedoAsm нет даже простой
условной компиляции  с проверкой существо─ 
вания метки.) 

  19.05.2017 - добавил  +sizeof(<type>) ,
структуры и константные массивы строк. Те─
перь можно писать игры типа Rusted Souls:

const struct state day1s24={
 NOSEL, IMG_STREETDAY,
 BIGSPR_PAPERBOY0, NOANIM,
 &day1m24, NOMSG, NOMSG, NOMSG
};
const struct msg day1m23={
 NOCMD,
 &day1s24,
 "
 3<О, парнишка с газетами...>n
 4Парень! Газету!"
};

  21.05.2017 - утилита nedores, конверти─
рует графические ресурсы для игр.

   Подсчёты  показали, что  если при само─
сборке  вся система  будет лежать в памяти
(а  не грузиться  из  файлов  и захламлять
диск временными файлами,как сейчас),то по─
надобится не48K и даже не 128K , а 276K -
это  даже если в памяти только один 32-ки─
лобайтный  исходник. А этих  исходников на
самом деле210K!
   Пока остаёмся на48K.

  30.05.2017 - как  делать  указатели  на
процедуры без лишнего тайпкаста? Копался в
typecode.h - свободный  бит остался только
один, тратить жалко...

  06.06.2017 - оказывается,где-то ещё ос─
тались тайпкасты через/*+*/(PCHAR) .
Исправил.

  07.06.2017 - немного сократил ассемблер
за счёт процедурыreadf(fin) с одним пара─
метром вместо кучи.

  08.06.2017:
   Теперь автометки нумеруются не с.B. ,а
с.A. Так  логичнее. А то потом, после ре─
лиза, уже не переделаешь - понапишут своих
библиотек :)

   Пытался ускорить токенизатор в компиля─
торе через таблицу меток вместоif-else. А
он от этого замедлился! Оставил так - про─
ще будет локализовать токенизатор под ARM.
И забросил дальнейшие попытки ускорения.

   Чтобы было с чем сравнить, про скорость
оригинального Си на PDP-11/70 авторами бы─
ло написано следующее:
  "In assessing the costs of using C, the
cost of the compilations themselves has to
be considered.This too we deem acceptable.
For  example, to compile and link-edit the
entire  operating system ("sys-gen") takes
somewhat  over  nine minutes of clock time
(of which seven minutes are CPU time); the
system consists of about 12,500 lines of C
code, leading  to a rate of about 22 lines
per   second  from  source  to  executable
object  on  a  PDP-11/70. The  compiler is
faster than this figure would indicate;the
system source makes heavy use of "include"
files,  so  the  actual  number  of  lines
processed  by  the  compiler is 38,000 and
the rate is 65 lines per second."
https://archive.org/stream/bstj57-6-1947/
bstj57-6-1947_djvu.txt
   65 строк в секунду на такой древней си─
стеме против наших 41.
   Правда, если  вы откроете исходник ори─
гинального  компилятора Си (ищите в интер─
нете  "Very   early   C   compilers   and
language" ), то увидите, что он весь напи─
сан  очень короткими строчками без коммен─
тариев:

init(s, t)
char s[]; {
 extern symbuf, namsiz;
 char symbuf[], sp[];
 int np[], i;

 i = namsiz;
 sp = symbuf;
 while(i--)
 if ((*sp++ = *s++)=='') --s;
 np = lookup();
 *np++ = 1;
 *np = t;
}

   И  в таком  же  стиле написан UNIX (см.
листинг в книге"Lions' commentary on UNIX
6th edition" ).
   Так что в общем мы наравне.

  09.06.2017 - сделал  инициализацию таб─
лицы  меток  в токенизаторе один раз, а не
на каждом файле.

  12.06.2017 - идея для построения проек─
та:
#include "name.h"
   должен выдавать:
include "name.dec"
incobj "name.bin","name.rel" или просто
incobj "name"
   это может быть любое место исходника (в
стартапе инклюды в конце)

  14.06.2017:
   Как  компилировать на48K большие прог─
раммы, метки которых не помещаются в ассе─
мблер за один раз? Сейчас мы уже впритык и
развивать компилятор не можем...

  а) с линкером:
   # сделать экспорт деклараций из асма (и
предусмотреть токен?) СДЕЛАНО 
   # сделать EXPORT в компиляторе
   # сделать ассемблирование цепочки фай─
лов - СДЕЛАН INCLUDE (теперь надо сделать 
#include в компиляторе) 
   # сделать экспорт объектника в асме
(патчи на месте и на будущее патчи назад) 
   # сделать линкер

  б) без линкера:
   # сделать экспорт деклараций из асма (и
предусмотреть токен?) СДЕЛАНО 
   # сделать EXPORT в компиляторе - для
процедур, функций, переменных, констант, 
константных строк/массивов/структур 
   # сделать ассемблирование цепочки фай─
лов - СДЕЛАН INCLUDE (теперь надо сделать 
#include в компиляторе) 
   # сделать подклеивание бинарников с
меткой (вместо nedodefb и для подключения 
модулей) СДЕЛАНО 
   # сделать экспорт таблицы релокации
(или обжа?) 
   # сделать подклеивание бинарников с
релокацией (или обжей?) 
  - после этого можно развивать компилятор
и асм 

   Как отличать в команде, где асм,где би─
нарник? или  реализовать incbin (он невло─ 
женный)? тогда сделать USEUNIT (#include), 
который  переводится  в  incbin?  или  все 
incbin разместить в стартапе? 

  Таблица  релокации - для  всех адресов,
т.е. чисел, которые  вычисляются  из адре─
сов? но $-label должно иметь размерность 
числа! аlabel/256(в компиляторе нет)? 

нужен флаг "адрес" в метке:"метка=число"
делает число,"метка"делает адрес, 
"метка=метка+1"(просто по факту чтения
метки типа "адрес" или$в выражении) 
делает адрес?
при всех арифметических операциях отслежи─
вать тип адрес/число?
как проще? или помечать выражения типа
"число"знаком#?
или помечать только выражения типа
$-label?
(в обычных программах не используются)
или разрешить$-labelтолько в специальной 
команде определения метки?

  Релоцируем не только переходы и вызовы,
но и вычисления адресаswitchи таблицыdw
  Обнулять_islabelимеет смысл только в
командах,которые генерятся с записью слова
или пишут метку(label,=,dw,jp,call, ld)
  Пока сделал так, что нельзя$-label
(можно1*($-label)) 

  Как релоцировать обращения к другим мо─
дулям?  Если как и внутри, то нельзя будет
распихать программу в память по частям...

  26.06.2017:
   Как  передавать  нумерацию  модулей для
обращений в объектнике? 
   Можно  ли относительный номер перенуме─
ровать в глобальный? (один и тот же модуль 
может быть включен в разные!!!) 
   Номер можно назначать по порядку компи─
ляции (даже если перекомпилировать неизме─ 
нённый не надо) 
   Надо   перекомпилировать   неизменённый
модуль, если  он использует изменённый мо─ 
дуль!!! (это потому что он привязывается к 
смещениям  в декларациях используемого мо─ 
дуля) 
   Даже если привязываться не к смещениям,
а  к номерам  символов, то вставка функции 
потребует  перекомпилировать  все  модули, 
которые используют его. 
   Можно от первого изменившегося переком─
пилировать все последующие модули. 
   Ещё  надо перекомпилировать всё при из─
менении структуры связей модулей. 
   Если  это не сделать, то в линкере надо
работать  с  символьными  метками, то есть 
линкер  не может стать лоадером (нужна па─ 
мять под метки) 

   Какой символ сделать для деклараций ти─
паmetka=<symbol><номермодуля>+<смещение>?
   или другой формат деклараций?
   Ассемблерный файл должен знать свой но─
мер модуля, чтобы правильно выгружать дек─ 
ларации! 
   Не страшно, если у ассемблера будет тот
же список файлов, что у компилятора? 
   Или список файлов компилятора ни на что
не влияет? 

  27.06.2017: добавил #include . До этого
все  используемые  внешние метки надо было
перечислять в начале исходника.

  28.06.2017: добавил #define (только для
констант).

  29.06.2017: разделил стандартную библи─
отеку   на  три -lib  (умножения-деления,
сдвиги и т.п.),str (строки) и io (файлы).
Так  можно сократить размеры утилит, кото─
рые не используют какую-то из частей.

  30.06.2017: разбил исходник компилятора
на кодогенератор и парсер, они компилирую─
тся и ассемблируются отдельно (кодогенера─
тор  под  адрес 0x6003, парсер  под адрес
0x6000  и  включает бинарник кодогенерато─
ра).  Для  этого  пришлось сделать экспорт
меток  из  ассемблера и директивыinclude,
incbin . Зато  теперь  появилась свободная
память  под  метки. Потом хотелось бы сде─
лать  ещё  и incbin с релокацией - данные
для релокации ассемблер уже выгружает.

   Зарелизил эту версию официально.

       Путь к многоплатформенности

  03.07.2017: добавил типизированные кон─
станты:
  #define <costname> (<type>)(<expr>)

  04.07.2017: добавил #ifdef/ifndef (пока
невложенный).
Начал писать кодогенератор под ARM Thumb.

  06.07.2017: добавил #undef .

  07.07.2017:
   Как делать макросы в ассемблере?
   Вместоusemacro лучше # ?
   Если поле метки=поле команды, то вообще
убрать нельзя, т.к. с точки зрения токени─
затора  строка "macro1" - это  объявление
метки,а строка"macro1 par1,par2" - ошибка
   Или  можно без#, если ловить макросы в
tokcalllbl  вместо  ошибки,  но  при  этом
вставлять невидимый токенusemacro.

  08.07.2017: добавил typedef. Кроме удо─
бства для пользователя, теперь можно будет
расширять  систему типов и в самом языке -
сейчас-то код типа всегда лежит в перемен─
ных и параметрах типаBYTE. А будет лежать
в  переменных  и параметрах типаTYPE. Это
будет, например,UINT, примерно как в дре─
внем  компиляторе  Си  (число  звёздочек в
указателях  при этом явно ограничено). Или
указатель  на структуру, как в компиляторе
Оберона.

  10.07.2017:
   Класть  макросы в буфер в памяти (отде─
льная  ветка в чтении файла?  дублирование
главного цикла? выделитьswitch в процеду─
ру? всё  это  медленно!), в отдельный файл
(сколько же  будет  открыто файлов?), патч
вызоваreadfin? (как это на языке высокого
уровня?) или делать отматывание файла? От─
матыванием  можно ещё сделатьdup-edup. Но
пока  нужных функцийseek/pos нет в файло─
вой  библиотеке, даже нетflush без закры─
тия файла.
   Переделал  все  скрипты.bat так, чтобы
они выглядели более-менее кроссплатформен─
но:  состояли  из  строчек
<имяпрограммы> <параметры>

  11.07.2017: добавил  спрайтовую библио─
текуsprite.

   Нужен нативный командный процессор.
   Желательно, чтобы формат батника совпа─
дал с MS-DOS и UNIX. 
   Т.е. вызовы без расширений + имена фай─
лов без ключей, и больше ничего. 
   При  работе командного процессора можно
хранить  только  резидент  и открытый файл 
батника, остальное каждый раз подгружать. 
   В .bat уже нельзя будет call comp.bat -
надо делать отдельные экзешники comp, tok, 
asm. 
   C++ Builder не позволяет назвать проект
asm,  поэтому   команды   будут  nedolang, 
nedotok, nedoasm. 

   Как компилировать во временной папке? и
даже  чтобы  исходники  были разбросаны по 
каталогам? 
   В MS-DOS и UNIX разные слеши, тогда ба─
тники  с  ними будут несовместимы. Поэтому 
везде  будет  прямой слеш, он по стандарту 
поддерживается  в  #include,  а в утилитах 
для MS-DOS я его перекодирую. 
   Можно сделать утилиту очистки временных
файлов - для всех трёх осей разную. 

  12.07.2017: ускорил вывод спрайта и до─
бавил   ещё   функции.  Исправлял  утилиту
nedores. 

  13.07.2017: разделил  компилятор на два
проекта: nedolang и nedolarm, уже выдаётся
какой-то код под ARM Thumb.

  14.07.2017: поддержал  типы  указателей
со звёздочками.

  17.07.2017: тестировал  спрайтовую биб─
лиотеку. Начал добавлять поддержку тайлов.

  18.07.2017: по просьбе Hippiman'а доба─
вил  в спрайтовую  библиотеку вертикальную
прокрутку окна.

  26.07.2017: для совместимости  с Си все
обращения к структурным типам предваряются
словомstruct .

  31.07.2017:
   Мысли,  как  сдвигать по вертикали весь
активный экран:
   - линейный экранный буфер? (на нём удо─
бнее  линии  и  полигоны) 0x6000: startup, 
ISR,  music,  data(?), scrbuf, gfx engine, 
logic  engine, gfx/logic/data (pageable) + 
INT vector 
   - todo  отрисовка  элементов панельки и
диалогов 
   - todo возможность выводить спрайты по─
верх панельки??? фреймово прямо на экране, 
как стрелка в ЧВ? 
   - todo клипировать спрайты внутри акти─
вного  экрана?  ?  только с переброской? ? 
(128K  экран  вряд  ли будет эффективным - 
мало места под графику в нижней памяти) 

  03.08.2017: вместо  196  файлов  в кучу
разложил  по разным каталогам сам компиля─
тор  с  библиотеками  (SDK)  и  проекты на
NedoLang  (у  каждого  свой  каталог). Для 
этого  поддержал  пути  везде, где надо (в
MS-DOS - перекодирование  из прямых слэшей
в  обрантые, а на Speccy под TR-DOS - про─
пуск до последнего слеша).
   Оптимизировал==  и  != , как задумывал
раньше.

  04.08.2017:  написал  нативную  утилиту
batch,  которая  исполняет те самые кросс─ 
платформенные  батники компиляции. Лежит с
адреса64000, так что если раньше было те─
сно,  то теперь очень тесно (реально я без
остановки  занимался оптимизацией компиля─
тора  по  размеру  и меткам, чтобы в конце
концов втиснуть batch ).Зато теперь не ну─
жно  писать  хитрые  бейсики, в которых не
хватает  места  (их  однажды даже пришлось
разрезать  пополам), можно сделать сложную
автосборку. Утилита batch имеет свою копию
файловой  библиотеки, общие с компилятором
только  дисковые  буфера  (они на экране -
одновременно открыто до8 файлов). Вот ес─
ли бы была ОС, то файловая система была бы
только в одном экземпляре.

  07.08.2017: добавил библиотекуprint, а
с её помощью утилиту diff, которая показы─
вает различие файлов на экране. Теперь мо─
жно тестировать систему автоматически, без
ручного копирования-сравнения.

  08.08.2017:  добавил  утилиты   nedodel
(удаление  файла)  и  movedisk (уплотнение
диска), потому  что  проект компилятора не
помещался на дискете.

  10-15.08.2017: переводил библиотеку  io
с NedoAsm на NedoLang, чтобы можно было её
использовать  на ARM. Строковую библиотеку
нарезал из процедур, которые уже давно бы─
ли   сделаны  для  компиляции  из-под  C++
Builder. В это времяHippiman смог вывести 
на  экран карту, редактируемую в DizzyAGE,
и подвигать по ней Диззи :)

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

  18.08.2017:  фиксил  кодогенератор  под
ARM Thumb. Оказалось, что  там  и метки, и 
всяческие defb'ы  принято писать в другом
формате,   причём   в  разных  ассемблерах
по-разному.  Я  выбрал  Keil,  потому  что
Phyton  не ест числа вида0xff. А компиля─ 
тор пока не умеет перекодировать константы
- передаёт как есть.

  19.08.2017: багфикс  импорта  атрибутов
тайлов в nedores. Было заметно только, ес─
ли  самому  рисовать в атрибутах или выво─
дить спрайты поверх тайлов.

  21.08.2017: мой выдаваемый ассемблерный
код под ARM Thumb наконец стал ассемблиро─
ваться.

  22.08.2017: токенизатор скомпилировался
под ARM Thumb. Но пока не определены неко─
торые функции.

  23.08.2017: добавил  недостающие  функ─
ции.Токенизатор слинковался под ARM Thumb.
Начал  отладку  в Phyton. Пришлось хакнуть
описание микроконтроллера 1986ВЕ1Т в комп─
лекте  Phyton, чтобы с адреса0 было боль─
шое-большое ОЗУ.

  24.08.2017:  добавил  утилиту   nedopad
(урезание или расширение файла до заданно─
го размера) для удобства загрузки програм─
мы и образа диска в симулятор Phyton.

  25.08.2017: токенизатор, скомпилирован─
ный  под ARM Thumb, работает под симулято─
ром! Результат токенизации файла на образе
диска соответствует образцу.
   Начал  писать  свой  ассемблер  под ARM
Thumb вместо Keil 'овского (точнее, делать 
ветку  NedoAsm  с  изменениями  в  главном
switch и некоторых процедурах, а остальные
части общие).

  27.08.2017:  багфикс  атрибутов  пустых
знакомест  в  nedores.  Добавил библиотеку
звуковых  эффектов ayfxplay  из игры Ball
Quest и Evo SDK. 

  28.08.2017:  начал  параллельно  писать
токенизатор  под  ARM Thumb (точнее, опять
делать ветку с общими частями).

  29.08.2017: токенизатор и ассемблер под
ARM Thumb работают! Была некоторая пробле─ 
ма с генерацией меток процедур со смещени─
ем+1 . Не смог сделать так же, как в Keil
(как он узнаёт, что метка относится к про─
цедуре, а не к переменной?). Сделал несов─
местимо. Но он мне больше не нужен. Я про─
сто сравнил результат побайтно.
   Ещё добавил рантайм библиотеку для128K
(прерывания, странички, бордер).

   Зарелизил эту версию.

         Гладко было на бумаге...

   Я взял  фирменную отладочную плату мик─
роконтроллера  1986ВЕ1Т фирмы "Миландр". С
кучей перемычек от прошлого хозяина, кото─
рые были выставлены явно не так, как нужно
было  мне. После некоторых копаний я нашёл
нужное положение перемычек и одну програм─
му, которая скомпилировалась в Phyton.
   Оказалось, что реальная железка  неско─
лько отличается по поведению от отладчика.
Речь  не только  о том, что с адреса0 нет
ОЗУ, там  вообще только48K ОЗУ (причём не
подряд),из которых под код можно использо─
вать только16K. Поэтому  вместо токениза─
тора я отлаживал просто копировщик файла.
   Более того, при попытке загрузить код в
ОЗУ  Phyton  сбрасывал  систему, так что я
терял все многочисленные настройки регист─
ров  процессора, которые  для  меня делала
программа-образец. Так  что  я сделал свой
загрузчик по Ethernet (сервер в ПЗУ и кли─
ент  отдельно). Он поддерживает только две
команды  по UDP:  записать байты в память
туда-то, запустить с заданного адреса.

   В некоторых случаях библиотека io обра─
щалась  к  невыровненным  данным. Я наивно
использовал   структуру   дескриптора   из
TR-DOS  прямо в сыром виде. Но на реальной
железке, в отличие от симулятора, невыров─
ненный  доступ вызывал прерывание, которое
было   довольно  сложно  отследить.  Файла
трассировки, опять-таки, в  отличие от си─
мулятора, уже не было, поэтому  я медленно
проходил  код процедура за процедурой. То─
чек останова в ОЗУ тоже не было, поэтому я
вручную ставилB {PC} (аналог jr $ ),а по─
том его убирал.

   В конце концов12.09.2017 всё заработа─
ло. Я  ещё  поэкспериментировал  с внешним
ОЗУ  (оказалось, были  перепутаны  провода
выборки байтов,но в общем работать можно),
лампочками  и  кнопочками,  потом  отложил
плату.

   Следующий этап - микроконтроллер "Муль─
тикор" фирмы Элвис. 
   А  также - как  поддержать банкинг, как
ещё  приблизить  к Си и как прикрутить тот
самый  3D движок. И написать специализиро─
ванную  среду  разработки.  И операционную
систему под неё :)

  07.09.2017  ещё  добавил  в  спрайтовый
движок  работу  с  пикселями на экране и в
экранном  буфере, 09.09.2017  по  просьбе
Hippiman'а  переделал спрайтовый движок на
постоянную  ширину тайлсета (28 знакомест,
чтобы уместились атрибуты),13.09.2017 со─
кратил архив на 259 файлов (добавил утили─
ту  clean), а15.09.2017 описал в красках,
как делатьHello world. Проверка на соседе
показала, что инструкция работает :)

                  * * *

   За год  в рамках проекта написано20000
строк кода (550килобайт) и под200кило─ 
байт текстов, не  считая  этой статьи (а в 
этой статье ещё80, приятного аппетита!). 
В среднем60отлаженных строк кода в сутки 
(с некоторыми отвлечениями на другие рабо─ 
ты), что чуть выше индустриального станда─ 
рта :) 




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Вступление - От авторов.
Игра - О уровнях игры: SUPER LASER SQUAD.
Обращение - Обращение к Синклиристам Алтая.

В этот день...   19 ноября