Translation: DtZ'2014 User Guide In this archive: TCP.EXE - "С" optimizing compiler V 5.20, TCLN.EXE - linker, TCLIB.EXE - librarian. CLIB.REL - standart library *.H - standart headers. *.C, *.MAC - library source *.BAT - batch files for creating library. The files with relocating code are .REL files. Yes, really .REL files known from CP/M used by Microsoft tools. So you can use Microsoft's M80/L80/LIB80, as well as RMAC and LINK by Digital Research. Because of this you face the limit of external naming: linker can recognise only first 7 case-insencitive symbols. 1. Current limitations While you can use all the types (char..float) while declearing variables, arithmetical operations and initialisation in the declarations are only allowed for char, int and long types (only assignment, using as the parameter, using as function return value, + , -, && , || , & , | , ~ , ^ ) and addresses. As for long, additionally, you can initialise in declaration, but the initialisation value must be valid signed or unsigned int. You cannot pass struct and unions by the value, nor assign them. You cannot use backslash for multilines in macros and string constants, but you can use "string1" "string2" to get "string1string2" Warning! Do not mix string constants with initialisation of char arrays - in the case of char arrays, you cannot use this method to get a multilines. Macros with parameters are not supported. Initialisation in declarations of automatic objects is not supported,too. 2. Compiler switches The common format of calling compiler is: TCP switches files Switches may have a parameters, or may not. You can combine several switches in the string without spaces, but if you have parameter, you must separateit with a space. Minus sign must precede every switch or group of switches. All the file names which does not start with minus sign can be separated with any number of spaces. You may omit .C in file names, but if the file has another extension, it must be passed with a full name. For each of the source file you will get .REL file. If you call compiler with several source file you just call a complier for each of this files one-by-one. Linker is not called automatically. So you must call it directly. In case of errors compiler terminated with some value different from 0 as ERRORLEVEL,and you can stop compilation process. This can be used in makefiles or in batch files. So, the switches: -dname == #define name 1 -q Use program calls instead of macros while doing 16-bit math. Use this for compact code. -z Generate Z80/U880 code. Uses IX and 16 bit substraction. The second set of registers, IY, JR and other Z80 stuff is not used. Much faster, but sometimes generates a longer code because of preserving IX. -k Sets char to be signed by default. By default, it is unsigned. -m Use this key to compile libraries. Ключ, используемый при компиляции библиотек. При его использовании после завершения компиляции очередной функции с классом 'extern' завершается формирование очередного модуля в об'ектном коде, классы всех ранее определенных об'ектов заменяются на 'extern' и с нового об'екта начинается генерация очередного модуля. Об особенностях генерации и использования библиотек - в разделе описания программы TCLIB.EXE. -O Ключ для запрещения оптимизации - в основном используется при тестах на скорость и отладке. При обычной работе не рекомендуется его применять, так как об'ем генерируемого кода увеличивается почти в два раза. -E# На месте символа '#' должно стоять число - оно определяет максимальное количество поименованых об'ектов (переменных, функций, типов, констант, аргументов у функций), используемых в программе. Некоторые количества используемых об'ектов: int test (int a, int b); - 3 имени. int cmp (char *, char *); - 3 имени enum colors { RED, GREEN, WHITE, BLACK } TCL; - 6 имен. -l# Этот ключ придется применять, есль общий об'ем строковых костант в одной функции превыхает 400 байт. Текст этих констант помещается за функцией, но до закрывающей скобки он хранится в буфере. -g# После указаного '#' количества предупреждений компиляция прекращается. -j# После указаного '#' количества ошибок компиляция прекращается. 4. Распределение памяти. Скомпилированная программа состоит из двух сегментов: данные и код. В сегмент кода, модификация содержимого которого в случае размещения готовой программы в ПЗУ невозможна, помещаются все исполняемые части программы (тела всех функций), строковые константы, инициализированные об'екты (переменные, массивы, и т.д.). В сегмент данных, располагаемый в области ОЗУ, попадают все неинициализированные об'екты. Соглашение об умалчиваемой инициализации об'ектов, не имеющих явной инициализации, для встраиваемых систем автоматически не выполняется. Решается эта проблема (при необходимости) заполнением кодом 0х00 всей области ОЗУ из стартового модуля. При получении обычной .СОМ программы для исполнения под СР/М все неинициализированные об'екты заполняются байтом 0х00 на этапе редактирования связей. 5. Подготовка стартового модуля для целевой компиляции. Поставляемая библиотека CLIB.REL содержит в своем составе стартовый модуль (по имени CROOT), выполняющий начальные установки для выполнения программы под управлением СР/М. При необходимости получения программы, работающей в другом окружении, рекомендуется придерживаться следующих рекомендаций к аппаратным и програмным средствам: о ПЗУ располагайте с адреса 0х0000. о После сброса управление сразу передается на метку '?START'. о ОЗУ может располагаться в любом месте, но желательно 'без дыр'. о Программа не должна завершаться. о Не инициализировать периферийные микросхемы в стартовом модуле. о Ассмеблерные функции использовать только там, где иначе нельзя. Пример текста стартового модуля для системы со следующим распределением памяти: 0x0000..0x1fff ПЗУ об'емом 8 КБ. 0x3800..0x47ff ОЗУ об'емом 4 КБ. ; ; crom.mac ; public $memry, EDATA_, BDATA_ public ?start extrn rroot ; ?start: lxi sp,4800h lxi h,0 BDATA_ equ $ - 2 $memry equ $ - 2 shld EDATA_ call rroot jmp ?start ; Loop forewer. ; dseg EDATA_: dw 0 cseg ; end ?start Комментарии: Главная функция Вашей программы должна быть описана так: void pascal rroot(void); Атрибут 'pascal' обознает, в данном случае, что внешнее имя этого об'екта передается всегда буквами верхнего регистра и усеченным до 6 символов - т.е. приведенным к соглашениям о внешних именах ассемблера м80.сом фирмы Microsoft. Остальные особенности ниже, в разделе о передаче параметров функциям. Именем '$MEMRY' помечены 2 байта в коде, в которые после связывания целевой программы помещается адрес первого свободного байта в сегменте данных. Копирование этого значения в другие переменные нужно для правильной работы функций распределения памяти brk() и sbrk(). Так же к используемым функцией brk() относятся переменные 'BDATA_' и 'EDATA_'. Соглашение о имени '$MEMRY' поддерживается TCLN.EXE и L80.COM. Часть стартового модуля, заполняющая все ОЗУ кодом 0x00, нужна для выполнения упомянутого выше соглашения об инициализации переменных. 5. Использование ассемблера. При написании ассемблерных функций необходимо знать: о Переменные и функции в Вашей "С" программе, о если хотите использовать их в ассемблерной о функции, должны иметь атрибут 'pascal' o либо иметь имя длинной до 5 букв и следом o подчеркивание ( NAME_ ) при этом в С - модуле о они должны быть описаны большими буквами без о подчеркивания , при это парамтры передаются о в С стиле Пример: int pascal vara, varb; void pascal pfunc(void); int * pascal pfunc(int); int (* ppfp)(char *); int PFUN2 ( char * ); Комментарии: vara - pascal переменная. varb - cdecl переменная. pfunc - pascal функция ppfp - pascal указатель на cdecl функцию. PFUN2 - С функция Для функций, не имеющих атрибута 'pascal', аргументы вычисляются и помещаются в стек в порядке 'справа налево'. Пример: Следующий текст траслируется так: void pascal test(int, int); test(0, 100); lxi h,0 push h lxi h,100 push h call test pop d pop d Следующий текст траслируется так: void test1(int, int); test(0, 100); lxi h,100 push h lxi h,0 push h call test1 pop d pop d Всеми функциями значение результата (если необходимо) возвращается в вызывавшую программу в регистровой паре HL, но если функция описана как возвращающая значение типа char или unsigned char , то значение возвращается в регистре A . При возврате функция должна восстановить: о Содержимое регистровой пары BC. о Содержимое ргистра IX (если используется процессор Z80/U880). о Значение указателя стека SP. Регистровая пара BC используется для хранения переменных 'register'. Содержимое регистра IX используется для доступа к автоматическип переменным. В качестве примера написания ассемблерных функций, вызываемых из "С" - программ, может служить пакет работы с памятью - файлы MEM.MAC и MEM.H. В систему разработки не включен компилятор с языка ассемблера, для компиляции можно пользоваться M80.COM, запускаемыми под эмулятором операционой системы СР/М. 6. Программа TCLIB.EXE В системе поставляется программа для работы с об'ектными модулями. Для пояснения некоторых ее функций требуется небольшое отступление: Так как компилятор реализован по однопроходной схеме, полный список имен для каждого модуля становится известен к концу чтения исходного файла и, соответственно, к концу формирования выходного. Но редакторам связей (TCLN.EXE, L80.COM) эта информация необходима в начале модуля. Операцию переноса списка имен в начало модуля выполняет библиотекарь TCLIB.EXE для каждого модуля, с которым он имеет дело. Ассемблер формирует все как надо, т.к. осуществляет трансляцию за 2 прохода. Но это преобразование требуется только для модулей (библиотек), в которых осуществляется поиск необходимых глобальных имен. Для 'связывания' годятся модули непосредственно после компиляции. Информация: компилятор с языка 'BASIC' фирмы Microsoft, работающий на СР/М-80, так же выполнен однопроходным. Ключи программы TCLIB.EXE: -l Печать имен и размеров модулей, глобальных имен, определенных в каждом из обрабатываемых модулей. -q Дополнительно печать глобальнх имен, НЕопределенных в каждом из обрабатываемых модулей. За ключами следуют: Одно имя - файл преобразуется, как описано выше. Более одного имени - первое встретившееся имя обозначает выходной файл, в который копируются (с описаными преобразованиями) модули из остальных файлов. Расширение по умолчанию для каждого исходного файла - .REL, если явно не задано другое. Старая версия исходного файла уничтожается только после успешного завершения всех операций по записи нового файла. Расширение имени нового файла по умолчанию будет .REL, если явно не указано другое. 7. Редактор связей TCLN.EXE Редактор связей преобразует файлы перемещаемого формата .REL в двоичный образ программы, настроенный на конкретные адреса начала сегментов кода и данных. Результатом работы является двоичный файл, содержащий образ программы. Формируется еще один файл (с расширением .SYM и именем, совпадающим с выходным) - текстовый файл сответствий между определенными в программе символическими именами и абсолютными адресами пространства памяти той машины, на которой будет исполняться созданная программа. Ключи: -lname Имя файла 'name', в котором производится поиск модулей, к точкам входа которых есть неудовлетворенные ссылки, оставшиеся после связывания перемещаемых файлов, перечисленных в командной строке программы. -oname Имя файла 'name', в который будет записан результат работы связывающего загрузчика. Расширением имени этого файла по умолчанию становится .COM. Одновременно образуется файл со списком символических имен программы. Его расширением всегда является .SYM. -pxxxx Шестнадцатеричное число 'xxxx' указывает загрузчику, с какого адреса размещать сегмент исполняемых кодов программы. -dxxxx Шестнадцатеричное число 'xxxx' указывает загрузчитку, с какого адреса размещать сегмент неинициализированных данных программы. Инициализированные данные попадают в сегмент кода программы. Если не заданы ключи -p и -d, в начале получившегося образа программы резервируются 3 байта, в которые загрузчиком помещается машинная команда перехода к началу программы (метке '?START'). Этот режим используется для получения исполняемых программ для операционных систем СР/М и MSX-DOS. 99. Мелочи. Программа для CP/M, занимающая минимальный об'ем: #include void _setargv(void) {} void exit(int code) { _exit(code); } int main(void) { bdos(9, (unsigned) "Hello, world!\r\n$"); return (0); }  файл со списком символических имен программы. Его расши