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_PAPERBOYO, NOANIM, &day1m24, NOMSG, NOMSG, NOMSG }; const struct msg day1m23={ NOCMD, &day1s24, " 3<О, парнишка с газетами...>n ЧПарень! Газету!" }; 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/bstjS7-6-1947/ bstjS7-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 бth 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 не ест числа видаOxff. А компиля─ тор пока не умеет перекодировать константы - передаёт как есть. 19.08.2017: багфикс импорта атрибутов тайлов в nedores. Было заметно только, ес─ ли самому рисовать в атрибутах или выво─ дить спрайты поверх тайлов. 21.08.2017: мой выдаваемый ассемблерный код под ARM Thumb наконец стал ассемблиро─ ваться. 22.08.2017: токенизатор скомпилировался под ARM Thumb. Но пока не определены неко─ торые функции. 23.08.2017: добавил недостающие функ─ ции.Токенизатор слинковался под ARM Thumb. Начал отладку в Phyton. Пришлось хакнуть описание микроконтроллера 198бВЕ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 (прерывания, странички, бордер). Зарелизил эту версию. Гладко было на бумаге... Я взял фирменную отладочную плату мик─ роконтроллера 198бВЕ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отлаженных строк кода в сутки (с некоторыми отвлечениями на другие рабо─ ты), что чуть выше индустриального станда─ рта :)
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября