Garry's Mod
Оценок: 40
Wiremod ZCPU/HL-ZASM. Перевод
От j0ez
HL-ZASM - это высокоуровневый ассемблерный компилятор и язык программирования. Он предоставляет поддержку всех базовых высокоуровневых структур языка C, пока сохраняется поддержка совместимости с ассемблером ZASM2.
   
Наградить
В избранное
В избранном
Удалить
Предисловие
Данное "руководство" - мой собственный перевод материала из Wiremod вики по ZCPU/HL-ZASM.

Официальная версия на английском языке находится по ссылке: http://wiki.wiremod.com/wiki/ZCPU/HL-ZASM
Этот перевод я сделал для личного пользования, однако оставляю его в открытом доступе для тех, кто хочет изучить что-то новое в Wiremod и устал от Е2.
Кому интересно развиваться в этом направлении и кто хорошо знает технический английский, тех прошу на http://www.wiremod.com/forum/cpu-tutorials/
Сразу оговорюсь, что этот материал довольно продвинутый и далеко не для всех. Так что если вы новичок в Wiremod или E2, то дважды подумайте, нужно ли это вам сейчас.

В тех моментах, где я пишу "в настоящий момент", имеется в виду дата последнего редактирования официальной версии (а именно 25 февраля 2012 г. на момент написания перевода).

The official English version of this "guide" is on: http://wiki.wiremod.com/wiki/ZCPU/HL-ZASM
Немного саморекламы
Посмотрите другие мои руководства, буду рад оценке и вашим комментариям:
http://steamoss.com/sharedfiles/filedetails/?id=450684522
http://steamoss.com/sharedfiles/filedetails/?id=447624385
Ключевые слова
В HL-ZASM компиляторе есть зарезервированные символы и ключевые слова, которые не могут быть использованы в качестве, к примеру, переменных. Переменной/функцией/идентификатором могут символы алфавита, нижнее подчеркивание '_', в некоторых случаях точка '.' может быть частью имени.

В языке зарезервированы следующие ключевые слова:
'''GOTO''', '''FOR''', '''IF''', '''ELSE''', '''WHILE''', '''DO''', '''SWITCH''', '''CASE''',
'''CONST''', '''RETURN''', '''BREAK''', '''CONTINUE''', '''EXPORT''', '''FORWARD''',
'''DB''', '''ALLOC''', '''SCALAR''', '''VECTOR1F''', '''VECTOR2F''', '''UV''', '''VECTOR3F''',
'''VECTOR4F''', '''COLOR''', '''VEC1F''', '''VEC2F''', '''VEC3F''', '''VEC4F''', '''MATRIX''',
'''STRING''', '''DB''', '''DEFINE''', '''CODE''', '''DATA''', '''ORG''', '''OFFSET''',
'''VOID''', '''FLOAT''', '''CHAR''', '''INT48''', '''VECTOR''', '''PRESERVE''', '''ZAP'''.

Точный смысл, значение и использование этих ключевых слов детально разобрано в следующих разделах.
Синтаксис языка ассемблера
Базовый ассемблер
HL-ZASM поддерживает следующие конструкции синтаксиса обычного ассемблера (Intel-подобного):
mov eax,123; //Копирование значения константы в регистр mov eax,ebx; //Копирование значения регистра в регистр add eax,123; //Двухоперадндая команда jmp 123; //Однооперандная команда с константой jmp eax; //Однооперандная команда с регистром

Два операнда всегда подчиняются следующему правилу: первый операнд - приемник, второй - источник.
Доступ к памяти и сегменты
Возможно использование как традиционного символа доступа к памяти '( )' или более распространенного '[ ]'. Оба работают идентично.

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

HL-ZASM поддерживает "инвертированный" синтаксис, при котором сегментный префикс следует за операндом, например 'es:eax' вместо 'eax:es'.

При использовании обычного синтаксиса для чтения значения из памятяи, сегментный префикс должен быть внутри скобок. Возможно использование знака '+' вместо двоеточия ':', но при этом нужно использовать обычный синтаксис доступа к памяти.

Также возможно использование постоянных значений (констант) в качестве сегментных префиксов для регистра через использование инвертированного синтаксиса.

В данный момент невозможно получить доступ к ячейке памяти путем использования смещения через константу (прим. переводчика На момент 25 февраля 2012 г., дату последнего редактирования официальной версии).

Поддерживается следующий синтаксис для получения доступа к памяти и сегментам:
//Чтение из памяти по типу ZASM2 mov eax,#100; mov eax,#eax; mov eax,es:#100; mov eax,es:#eax; mov eax,eax:#100; //mov eax,eax:#es; //Неправильно: невозможно использовать сегментый регистр в качестве указателя //Обычный способ чтения из памяти mov eax,[100]; mov eax,[eax]; mov eax,[es:eax]; mov eax,[es+eax]; //mov eax,[eax:es]; //Неправильно: невозможно использовать сегментый регистр в качестве указателя //mov eax,[eax+es]; //Неправильно: невозможно использовать сегментый регистр в качестве указателя //Использование констант с сегментами mov eax,es:100; mov eax,eax:100; mov eax,100:es; mov eax,100:eax; //mov eax,100:200; //Неправильно //Использование регистров с сегментами mov eax,ebx:ecx; mov eax,es:ebx; mov eax,ebx:es; //Неправильно, но преобразуется в конструкцию 'es:ebx' //mov eax,fs:es; //Неправильно, так как нет соответствующего верного синтаксиса
Константы
В HL-ZASM возможно использование константных выражений, шестнадцатеричных значений и меток:
//Константный целые числа mov eax,255; //EAX = 255 mov eax,0255; //EAX = 255 mov eax,0x1FF; //EAX = 511 //Отрицательные целые числа mov eax,-255; //EAX = -255 mov eax,-0x1FF; //EAX = -511 //Числа с плавающей точкой и выражения mov eax,1e4; //EAX = 10000 mov eax,1.53e-3; //EAX = 0.00153 mov eax,1.284; //EAX = 1.248 mov eax,2.592+3.583; //EAX = 6.175 mov eax,1e2+15; //EAX = 115 //mov eax,1e-5+0.034;//Does not parse (bug) mov eax,0xFF+100; //EAX = 355 //Сложные выражения define labelname,512; mov eax,10+15; //EAX = 25 mov eax,10*(15+17*24); //EAX = 4230 mov eax,10+labelname*53-10*(17-labelname); //EAX = 32096
Метки и переменные
Метки используются, чтобы структурировать части кода. Каждая метка есть число с прикрепленным к нему именем. Это значит, что имена переменных и имена меток имеют свое константное значение и могут быть использованы в выражениях в качестве параметров для различных команд:
labelname: jmp labelname; mov eax,labelname+3; labelName: //чувствительна к регистру jmp labelName;

Команда "define" позволяет прикрепить константное значение к метке:
define defVar1,120; define defVar2,50+defVar1; //define defVar3,labelname2*10; //Не срабатывает, возможно баг labelname2: mov eax,defVar1; //120 mov eax,defVar2; //170 //mov eax,defVar3; //170

Команда "db" используется для того, чтобы записать определенные значения в память, обходя любую предварительную обработку (препроцессинг). Они будут записаны в сегмент кода:
db 100; //Выводит 100 db 0xFF; //Выводит 255 db labelname2+10; db 'This is a string',0; db 15,28,595,'string',35,29;

Команда "alloc" выделяет место и позволяет обращаться к нему по имени, если оно ему было дано. Выделенное место будет находиться в текущей позиции в памяти (если данные или код находятся в том же сегменте) или в отдельном сегменте данных в зависимости от предпочтений компилятора:
alloc var1,100,72; //Назначить имя метки, размер и значение, идентично 'var1: db 72,72,72,...' alloc var2,100; //Назначить имя метки и значение 'var2: db 100' alloc var3; //Назначить имя метки 'var3: db 0' alloc 120; //Назначить размер 'db 0,0,0,0,0....' define allocsize,120; alloc 0+allocsize; //Не должно начинаться с имени индекса опознавания

Также существуют специальные команды для определения векторных и строковых переменных. Базовый синтаксис: "ТИП_ВЕКТОРА ИМЯ, ЗНАЧЕНИЕ_ПО_УМОЛЧАНИЮ". В качестве примера приведены все типы векторов:
scalar name,...; //К примеру, "scalar x,10" vector1f name,...; vector2f name,...; vector3f name,...; vector4f name,...; vec1f name,...; vec2f name,...; vec3f name,...; vec4f name,...; uv name,...; color name,...; matrix name; //Инициализатор по умолчанию отсутствует

Возможно получение указателя на каждый из компонент векторной переменной:
vector3f vec1; mov #vec1.x,10; mov #vec1.y,20; *(vec1.z) = 30; uv texcoord1; mov #texcoord1.u,10; mov #texcoord1.v,20; color col1; mov #col1.r,10; mov #col1.g,20; mov #col1.b,30; mov #col1.a,40;

Матрица и вектор могут быть использованы вместе с векторными выражениями ZCPU:
matrix m1; matrix m2; vector4f rot,0,0,1,45; mident m1; //Загрузить единичную матрицу mrotate m2,rot; //Загрузить матрицу вращения mmul m1,m2; //Перемножить две матрицы

Также присутствует дополнительная команда, которая не связана напрямую с созданием переменных, но она позволяет изменить текущее место в памяти, в которое записана программа через записывающий(?) указатель. Команда называется ORG:
//Записывающий указатель равен 0 alloc 64; //Записывающий указатель теперь равен 64 alloc 1; //Записывающий указатель теперь равен 65 ORG 1000; //Указатель теперь равен 1000

Эта команд может быть использована для более продвинутого управления генерации кода. Есть также две специальных доступных нам команды-помощника, которые могут быть использованы для упрощения объявления переменных в простой программе: DATA и CODE. Они используются так:
DATA; //Область данных alloc var1; alloc var2; ...... subroutine1: .... ret .... CODE; //Область кода call subroutine1; call subroutine2; ......

Эти команды разворачиваются в следующую конструкцию:
//DATA jmp _code; //CODE _code:
Генератор выражений
В HL-ZASM имеется встроенный генератор выражений. Присутствует возможность генерировать сложные выражения, которые могут участвовать в вызовах функций, регистрах, переменных в том же виде, в котором они генерируются в коде языка C.

Вот несколько примеров различных выражений:
EAX = 0 //То же самое, что и "mov eax,0" EAX += EBX //То же самое, что и "add EAX,EBX" main() print("text",999) R17 = solve("sol1",50,R5) R2 = R0 + R1*128 c = *ptr++; R0 = (noise(x-1, y) + noise(x+1, y) + noise(x, y-1) + noise(x, y+1)) / 8 Offset = 65536+32+MAX_DEVICES+udhBusOffset[busIndex*2]

Необходимо проявлять особую осторожность при использовании генератора выражений, так как он использует 6 регистров общего назначения ('EAX' ... 'EDI') в качестве временных хранилищ для расчета выражений.

В компиляторе присутствует поддержка постоянных выражений, которые сокращаются до одного константного значения во время компиляции. Возможно использование данных свойств нижеприведенного синтаксиса в анализаторе выражений:
Синтаксис
Описание
-X, +X
Определить знак или инвертировать значение
&globalvar, +X
Указатель на глобальную переменную (всегда константа)
&stackvar
Указатель на переменную стека (всегда динамический)
&globalvar[..]
Указатель на элемент глобального массива
&stackvar[..]
Указатель на элемент массива основанного на базе стека
1234
Константное значение
"string"
Указатель на константную строку, может быть использован только внутри функций
'c'
Одиночный символ
#var
Константный указатель или метка
EAX
Регистр
func(...)
Вызов функции
var[...]
Доступ к массиву
*var
Чтение переменной через указатель
expr + expr
Сложение
expr - expr
Вычитание
expr * expr
Умножение
expr / expr
Деление
expr ^ expr
Возведение в степень
BAND expr, expr
Двоичное И
BOR expr, expr
Двоичное ИЛИ
XOR expr, expr
Логическое Исключающее ИЛИ
AND expr, expr
Логическое И
OR expr, expr
Логическое ИЛИ
expr = expr
Присвоить (возвращает значение с левой стороны после присвоения)
expr > expr
Больше, чем
expr >= expr
Больше или равно, чем
expr == expr
Равно
expr < expr
Меньше, чем
expr++
Инкремент (возвращает значение ДО инкремента)
expr--
Декремент (возвращает значение ДО декремента)
++expr
Инкремент (возвращает значение ПОСЛЕ инкремента)
--expr
Декремент (возвращает значение ПОСЛЕ декремента)

Генератор выражений также поддерживает выражения внутри операционных кодов (опкодов).
Объявление переменных
В HL_ZASM возможно объявить переменные тем же образом, что и в языке C. К слову, есть разница между переменными, объявленными таким образом и через команды ZASM2. К этому мы вернемся чуть позже.

Переменные могут быть объявлены либо в глобальном пространстве (сегменте данных), либо в локальном пространстве (сегменте стека/стековом кадре). Переменные, объявлены в глобальном пространстве создаются во время компиляции, в то время, как переменные стека существуют только в течение работы программы.

Имейте в виду, что объявление и определение переменных - это две разные вещи. Переменные объявляются, как показано ниже, но они могут быть определены с помощью команд ZASM2.
float x; mov x,10; //Устанавливает значение переменной X в 10 mov #x,10; //То же самое, что и '*(x) = 10' scalar y; mov y,10; //Ничего не делает, то же самое, что и 'mov 123,10' mov #y,10; //Устанавливает значение переменной Y в 10

В настоящее время компилятор поддерживает три типа: "float" (64-битная переменная с плавающей точкой), "char" (64-битный код символа с плавающей точкой), "void" (необъявленный/пустой тип либо неопределенной состояние). В отличие от обычных компиляторов, все эти три типа работают идентичным образом, грубо говоря, они все - одна и та же вещь:
float x; float y,z; char* w; char** u; //Указатель на указатель //Во всех трех примерах 'a' - это указатель на символ char * a; char* a; char *a; char b,*a;

Чтобы создать указатель на переменную следует использовать спецсимвол '*'. Нет разницы, есть ли какие-либо промежутки между звездочкой и именем переменной (в любом случае звездочка принадлежит к имени переменной).

Массивы фиксированного размера могут быть объявлены в качестве переменных. Если массив расположен в глобальном пространства, все его элементы по умолчанию будут равны нулю, хотя может случиться иначе, если программа была динамически запущена операционной системой. Если массив объявлен в локальном пространстве, его элементы могут быть необъявлены:
float arr[256]; arr[100] = 123; R0 = arr[R1];

На данный момент нет поддержки двумерных массивов, но в будущем эта возможность будет добавлена (прим. переводчика На момент 25 февраля 2012 г., даты последнего редактирования официальной версии).

Возможно использование инициализаторов для массивов и переменных. Константные выражения в качестве инициализаторов могут быть использованы только в случае глобальных переменных и массивов (в режиме стека таких ограничений нет):
//Глобальное пространство float x = 10; float garr1[4] = { 0, 5, 7, 2 }; float garr2[8] = { 1, 2 }; //Недостающие элементы будут равны нулю float garr3[8] = { 1, 2, 0, 0, 0, 0, 0, 0 }; //Аналогично предыдущей строке //Локальное пространства void func(float x,y) { float z = x + y * 128; float larr1[4] = { x, y, 0, 0 }; float larr2[16] = { x, 0, y }; //Недостающие элементы будут равны нулю }

Также присутствует поддержка создания переменных, которые хранятся в регистрах препроцессора. Чтобы это сделать, перед объявлением типа должно стоять ключевое слово "register". Локальные регистровые переменные работают гораздо быстрее, чем в локальных стековых переменных.
void strfunc(char *str) { register char *ptr = str; *ptr++ = 'A'; }

Количество локальных регистровых переменных, которые можно создать. ограничено.
Объявление функций
Возможно объявление функций наподобие языка C, однако в данный момент поддерживается только один стиль такого объявления:
return_type function_name(param_type1 name1, name2, param_type2 name3) { .... code .... }

Параметры определяются тем же образом, каким объявляются переменные. Можно использовать массивы постоянного размера в качестве переменных в функциях, но невозможно их занести в функцию напрямую. Также возможно использовать безразмерные массивы в качестве параметров (см. примеры).

Примеры объявления функций:
void main() { .. } float func1() { .. } float func2(float x, y, float z) { .. } char strcmp(char* str1, char* str2) { .. } float strlen(char str[]) { .. } //'char str[]' - это то же самое, что и 'char* str' //Невозможно использовать массив таким образом void dowork(char str[256]) { .. }

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

Преждевременные объявления функций позволяют строго определить аргументы функций, а также они позволяют перегрузить функцию другими параметрами при сохранении такого же имени. Функция может быть объявлена заранее, если перед ее типом написать ключевое слово 'FORWARD":
//Преждевременное объявление перед использованием forward void func(); //Первая функция forward void func(float x); //Вторая функция forward void func(float x, *y); func(); //Вызов первой функции func(10); //Вызов второй функции func2(); //Ошибка компилятора: функция 'func2' не объявлена //Фактические "тела" функций forward void func() { //Первая функция ... } forward void func(float x) { //Вторая функция ... } forward void func(float x, *y) { ... } forward void func2() { ...

В отличие от заранее объявленных функций, нормально объявленные функции могут использованы из любого места в коде, но они не предоставляют строгую проверку типов принимаемых аргументов:
void func1() { .. } func1(); func2(); //Работает, даже если не объявлена void func2() { .. }

Также есть дополнительное ключевое слово, которое может быть использовано при определении функций - "EXPORT". Если использовать это ключевое слово, то будет использоваться функция из внешней сгенерированной библиотеки. Компилятор также автоматически добавит объявление для этой функции в файле сгенерированной библиотеки:
export void func1() { .. } void func2() { .. } //В итоговом файле имя функции будет искажено
Вызов функций
Соглашение о вызове
HL-ZASM использует соглашение о вызове "cdecl". Результат выполнения функции проходит через регистр EAX. Если функция не была преждевременно объявлена или если она имеет некоторое количество аргументов, то в регистр ECX должно быть записано количество аргументов:
R0 = func(a,b,c); //То же самое, что и: push c; push b; push a; mov ecx,3; //Необязательно, если функция объявлена заранее call func; add esp,3; //Необходимо привести в порядок стек mov r0,eax; //Возвращение результата main(); //Аналогично: mov ecx,0; call main;

Функция будет изменять регистры EAX, ECX, EBP (наряду с регистром ESP), а также может изменять другие регистры, если они не помечены, как закрепленные.
Стековый фрейм
HL-ZASM использует инструкции управление стековым фреймом из ZCPU ("ENTER", "LEAVE") для создания стекового фрейма для функции. Они просмотрят количество локальных переменных в инструкции "ENTER", и далее будет создан стековый фрейм с заранее выделенным пространством для локальных переменных.

Функция сгенерирует следующий код:
void func(float x,y) { float z,w; ... } //Генерирует: func: enter 2; .... leave; ret

Доступ к переменным в стеке осуществляется через инструкции "RSTACK", "SSTACK". Компилятор будет использовать "EBP:X" в качестве смещения стека, где "EBP" - это регистр базы стекового фрейма, а "X" - это смещение целевого значения в стеке. Пример:
void func(float x,y) { float z,w; } //Эти значения будут храниться в стеке //[ 3] Y //[ 2] X //[ 1] Возвращает адрес //[ 0] Сохраненное значение EBP (при вызове функции) //[-1] Z //[-1] Z //Поэтому такая конструкция будет работать: rstack R0,EBP:2 //R0 = X rstack R1,EBP:3 //R1 = Y rstack R2,EBP:-1 //R2 = Z rstack R3,EBP:-2 //R3 = W

Таким образом у нас есть возможность сгенерировать стектрейс, используя нижеприведенный код:
void stack_trace() { char* returnAddress,savedEBP; R0 = EBP; //'Current' EBP while ((R0 > 0) && (R0 < 65535)) { rstack returnAddress,R0:1; rstack savedEBP,R0:0; add_to_trace(returnAddress); R0 = savedEBP; } }
Закрепленные регистры
Если текущая программа использует какой-либо из регистров ZCPU, она должна их пометить как закрепленные, чтобы генератор выражение не использовал эти регистры для вычисления выражений.

Компилятор будет выдавать предупреждение, если будут использоваться незакрепленные регистры. В настоящий момент регистры EAX-EDI должны быть помечены как закрепленные (так как только они используются генератором выражений):
void func(float x,y) { preserve EAX, EBX; //Генератор выражений никогда не изменит значения регистров EAX И EBX EAX = 123; EBX = x*10 + y; }
Условные операторы и циклы
HL-ZASM компилятор поддерживает стандартные условные операторы, однако их поддержка несколько ограничена. Условное ветвление может быть организовано с помощью конструкции IF_THEN_ELSE. Также поддерживается оператор ELSE IF. После проверки условия может быть выполнена либо одна команда, либо целый блок кода:
//Может использовать блоки if (expression) { .... } else if (expression) { .... } else { .... } //Может избегать использование блоков: if (expression) expression; if (expression) expression1 else expression2;

HL-ZASM поддерживает циклы "FOR":
for (initializer; condition; step) { ... }

Initializer - это выражение, которое будет запускать цикл, condition - состояние, которое будет проверяться при каждом проходе цикла, а step - это выражение, которое будет выполняться после выполнения каждого прохода. Например:
float x; for (x = 0; x < 128; x++) { .. } //Цикл от 0 до 127 for (x = 128; x > 0; x--) { .. } //Цикл от 128 до 1 for (;;) { .. } //Бесконечный цикл

Также возможно использование цикла while. Цикл DO-WHILE пока что не поддерживается:
while (expression) { ... } while ((x < y) && (x > 0)) { ... } while (1) { ... } //IБесконечный цикл

Ключевое слово "BREAK" используется для того, чтобы преждевременно прервать цикл:
while(1) { if (condition) { break; } .... }

Ключевое слово "CONTINUE" позволяет мгновенно перейти на следующий шаг цикла:
float x; for (x = 0; x < 128; x++) { if (x == 50) { //Пропустить 50-ый шаг continue; } }

Можно также определять метки, а потом перемещаться к ним ("прыгать") путем определения их тем же способом, что и в ZASM2, и используя "GOTO":
.... goto label1; //Прыжок на метку label1 .... label1:

При использовании "GOTO" также можно подставить туда сложное выражение:
goto function_entrypoints[10];
Препроцессор
Препроцессор HL-ZASM поддерживает C-подобные директивы препроцессора. Директивы всегда действуют в текущей строке (невозможно записать две директивы в одной строке).
Директивы библиотек времени выполнения (Runtime) языка C
По умолчанию программы, откомпилированные с помощью HL-ZASM не имеют прикрепленную Runtime библиотеку, и поэтому может понадобится переписать базовые сопрограммы. Можно прикрепить Runtime библиотеку по выбору. Библиотека по умолчанию называется ZCRT и позволяет загрузить ZCPU без какого-либо дополнительного ПО.

CRT (Common Runtime Library) может быть подключена с помощью соответствующей директивы препроцессора. Она должна располагаться в первой строке кода до написания какого-либо другого кода, иначе она не будет корректно работать (директива нечувствительна к регистру):
#pragma CRT ZCRT

Эта директива обозначит CRT папку в качестве одного из поисковых путей и подключит основной CRT файл:
#pragma SearchPath lib #include <zcrt/main.txt>

Эта последовательность директив позволит использовать библиотеки по умолчанию, которые принадлежат данной Runtime библиотеке.
Определение и условные директивы
В языке возможно использовать С-подобные определения директив препроцессора (хотя пока что невозможно определять функции препроцессора):
#define DEF1 #define DEF2 1234 #ifdef DEF1 func(DEF2) //same as func(1234) ... #elseif DEF2 .... #else ... #endif #undef DEF1
Директивы подключения файлов
Препроцессор позволяет подключать внешние файлы, используя директивы:
#include "filename" #include <filename>

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

Препроцессор также поддерживает ZASM2 "include" синтаксис:
##include## filename same as #include <filename>
Особые команды компилятора
Здесь представлено несколько особых команд компилятора, доступных через директивы препроцессора. Директива "SET" позволяет пользователю модифицировать настройки компилятора. Пример синтаксиса (все чувствительно к регистру):
#pragma set OutputResolveListing true

Возможно манипулировать следующими опциями:
Имя
По умолчанию
Описание
CurrentLanguage
HLZASM
Текущий язык компилятора. Может быть HLZASM или ZASM2
CurrentPlatform
CPU
Целевая платформа. Определяет набор свойств, не может быть изменено
MagicValue
-700500
Магическое число. Используется в качестве ошибочного константного значения
OptimizeLevel
0
Уровень оптимизатора. 0 - нет, 1 - низкий, 2 - высокий. На данный момент не поддерживается
OutputCodeTree
false
Выводить дерево кода?
OutputResolveListing
false
Выводить листинг на этапе принятия решения?
OutputFinalListing
false
Выводить листинг в конце?
OutputTokenListing
false
Выводить токенизированный(?) исходный код?
OutputBinaryListing
false
Выводить итоговый двоичный дамп в листинг?
OutputDebugListing
false
Выводить данные отладки в листинг?
OutputToFile
false
Выводить листинги в файл вместо консоли?
Output OffsetsInListing
true
Выводить двоичные смещения в листинг?
(прим. переводчика пробел нужно убрать, я поставил его, чтобы стим не ругался)
OutputLabelsInListing
true
Выводить имена меток в итоговом листинге?
GenerateComments
true
Сгенерировать дополнительные комментарии в листинге?
FixedSizeOutput
false
Выводить инструкции фиксированного размера (может быть изменено в любое время)?
SeparateDataSegment
false
Занести каждую переменную в отдельный сегмент даных? На данный момент не поддерживается.
GenerateLibrary
false
Сгенерировать прекомпилированную библиотеку?
AlwaysEnterLeave
false
Всегда генерировать ENTER/LEAVE блоки в функциях?
NoUnreferencedLeaves
true
Не компилировать функции и переменные, которые не используются программой?

Директива "LANGUAGE" может быть использована в месте задания языка путем изменения переменных компилятора:
#pragma language zasm #pragma set CurrentLanguage ZASM2

Директива "CRT" может быть использована, чтобы прикрепить Runtime библиотеку языка C. Директива "CPUNAME" используется, чтобы присвоить особое имя целевому процессору:
#pragma CPUName ACPI Power Controller
Дополнительные директивы
Здесь приведено несколько директив препроцессора и особых меток, доступных программисту:
Директива
Описание
__PTR__
Текущий записывающий указатель
__LINE__
Номер текущей строки
__FILE__
Текущее имя файла (строка)
__DATE_YEAR__
Текущий год (во время компиляции)
__DATE_MONTH__
Текущий месяц (во время компиляции)
__DATE_DAY__
Текущий день (во время компиляции)
__DATE_HOUR__
Текущий час (во время компиляции)
__DATE_MINUTE__
Текущая минута (во время компиляции)
__DATE_SECOND__
Текущая секунда (во время компиляции)
__PROGRAMSIZE__
Общий размер программы в байтах
programsize
Аналогично предыдущему (ZASM2-совместимая директива)
Список ошибок
Основные ошибки компилятора

Undefined label
Вызов неизвестной метки, переменной или функции, ранее не объявленных в текущем пространстве.

Variable redefined
Переменная или функция с таким именем уже были определена в этом пространстве.

Identifier expected
Генератор выражений ожидает последующий идентификатор (переменную/функцию и т.п.)

Expression expected, got ...
В данном месте кода ожидался другой объекта. Также может обозначать некорректный синтаксис выражения.

Ident ... is not a variable/pointer/array
Невозможно получить указатель на данный идентификатор.

Invalid instruction operand
ZPCU не поддерживает данный операнд. Может обозначать, что сегментный префикс используется для доступа к регистру или к порту.

Undefined opcode
Данный опкод не поддерживается текущей архитектурой.

Array size must be constant
Возможно определять только массивы фиксированного размера. Динамические массивы не поддерживаются.

Cannot have expressions in global initializers
Поддержка сложных выражение в качестве инициализаторов переменных на данных момент не поддерживается.

Can only zap/preserve registers inside functions/local blocks
На данный момент компилятор не поддерживает закрепленные регистры в глобальном пространстве.

... must be constant
Ожидалось константное значение, и оно не должно опираться на значения неизвестных переменных или меток.

Expected ... got ... instead
Для языковой конструкции был использован некорректный синтаксис.

Out of free registers
Ошибка обозначает одну из трех проблем:
  • Больше нет свободных регистров, которые можно использовать из-за большого количества выделенных локальных регистровых переменных;
  • Сгенерированное выражение было слишком сложным (there are not enough unallocated registers);
  • Внутренняя ошибка компилятора.

Unable to include CRT library
Некорректное имя Runtime библиотеки или не была найдена библиотека.

Cannot open file
Не найден файл в указанной папке и ни в одном из поисковых путей.

Internal error ...
Внутренняя ошибка компилятора (ошибка, которую невозможно исправить).

TRANSLATED BY: STEAM_0:0:44995452
http://steamoss.com/profiles/76561198050256632
Комментариев: 18
j0ez  [создатель] 28 апр. 2022 г. в 23:32 
🔥🔥🔥
Strand 18 апр. 2022 г. в 14:45 
Ну вот, снова я, пишу через 2 с половиной года о том, что я уже более менее освоил ZCPU))
https://youtu.be/p2E2m-bdEh0
https://youtu.be/TzLAqxZzl5c
https://youtu.be/gdprSDUkZW4
j0ez  [создатель] 22 ноя. 2019 г. в 3:54 
Тут, к сожалению, не могу подсказать(
j0ez  [создатель] 21 ноя. 2019 г. в 13:05 
SolidSlav, нормас, но насколько я помню, у синуса и косинуса немного другой диапазон значений, нежели 0..512 :)
j0ez  [создатель] 20 ноя. 2019 г. в 9:21 
SolidSlav, неплохо 👍. Продолжай в том же духе)
j0ez  [создатель] 8 сен. 2019 г. в 8:16 
👍
CornerPin 8 сен. 2019 г. в 5:57 
Туториалы со старого форума Wiremod:
https://www.reddit.com/r/wiremod/comments/5qusxk/gpu_and_cpu_tutorials_at_wiremod_now_not_avaiable/

Официальная документация, охватывает CPU, GPU и немного SPU (Ctrl+F для быстрого поиска по странице):
https://wiremod.github.io/Miscellaneous/zcpudoc.html
https://wiremod.github.io/Miscellaneous/zcpudoc_ru.html
Strand 7 сен. 2019 г. в 21:34 
Просто я играю на минго-серверах и творю там дичь, а мне не хватает лимита гейтов решил подучить CPU, а после и GPU. А возможно и изучу все полностью. Правда вот есть проблема что я не могу найти документацию с GPU. Можешь кинуть ссылку если знаешь?
j0ez  [создатель] 7 сен. 2019 г. в 14:57 
Спасибо за отзыв) Не думал, что людей это до сих пор интересует)