BlitzMax + fasmМатериал из Blitz Et CeteraДелать ассемблерные вставки в код Blitzmax не позволяет. Но это еще не значит, что нельзя написать код на ассемблере для Blitzmax. Дело в том, что сам Blitzmax использует для компиляции Fasm. А это значит что нам надо просто определенным образом скомпилировать модуль для Blitzmax на ассемблере и просто подключить его для использования в программе. Но это еще не все. Дело в том, что модули компилируются в формате COFF, поэтому мы теоретически можем использовать для написания модулей под Blitzmax ЛЮБОЙ язык, который компилирует в COFF. Просто нужно соблюдать некоторые правила при написании модулей. Я например, подумываю про язык D. Но неизвестно чем это подумывание закончится. И сразу про недостаток: теряется мультиплатформенность, т.к. для MacOS используется другой компилятор, хотя теоретически возможно что для интеловских версий MacOS-а и подойдет. Но этот вопрос я не исследовал вообще. Ну нету у меня Мака. Итак, я предполагаю, что и Fasm и Blitzmax уже установлены и настроены и даже работают с полпинка. Для примера сделаем простую программку, которая переводит градусы в радианы. Не думаю что это очень актуально, но кто знает. И оговорочка: делать будем только релизную версию, дебаг посложнее да и я в ней не разбирался. Начинаем оформлять код: format MS COFF ; - задаем формат компиляции. Fasm такой проказник - много форматов знает и умеет.
extrn ___bb_blitz_blitz ;- так надо! а вообще это объявление внешней функции Blitzmax для инициализации модуля. Я пробовал ее и не вызывать - все работает. Но надо конечно проверить на крупной программе, а не на примерчиках. Теперь пришла пора придумать название модуля. Долго думать я не стал и решил назвать его совсем неоригинально, но понятно - degtorad. По этому поводу надо объявить процедуру инициализации модуля: public ___bb_degtorad_degtorad
Как видно, название внутри асм-кода имеет свой строгий формат, который, думаю, ясен из строки. public _DegToRad ; а это объявление нашей функции. Перед именем обязательно надо поставить подчеркивание!
На этом оформление закончено, пора писать сам код. Для начала надо проинициализировать модуль, написав функцию инициализации: ___bb_degtorad_degtorad. Ставим директиву начала кода:
section "code" code. И пишем код инициализации. ___bb_degtorad_degtorad:
push ebp Кратко что он делает: мы проверяем флаг инициализации _finit. И если инициализации еще не было, то мы ее делаем (код после метки _init). Это нужно для внутренних переменных модуля или глобальных переменных. Конкретно здесь их нет, поэтому просто ставиться флаг что инициализация уже была и вызывается ___bb_blitz_blitz. Для чего - не знаю. Возможно, для какой-то дополнительной внутренней регистрации модулей. Как уже писал, без ее вызова все работает, но лучше его делать, т.к. на больших проектах не тестировалось. Теперь пишем основной код нашей функции: _DegToRad:
push ebp Описание: сначала перебрасываем стек на ebp для более удобной работы с аргументами функции. Пихаем в стек число 1016003125. Это представление в формате float числа 0.0174532925199432957692369076848861, которое является коэффициетном преобразования градусов в радианы. Загружаем в ФПУ аргумент функции и перемножаем его с коэффициентом. И все. Дальше просто ждем результата от ФПУ, восстанавливаем стек и возвращаемся. Результирующее значение будет там где ему положено быть. По идее в eax, не помню ни куда ФПУ от этой команды результат возвращает, ни как принимает результаты Blitzmax (или через eax или через стек). Этож больше полугода назад было. Теперь остается самая малость манипуляций с кодом - описать нашу переменную флага инициализации: section "data" data writeable align 4
_finit: Вот и все с кодом. Полный текст программы: format MS COFF
extrn ___bb_blitz_blitz Теперь можно идти двумя путями: или писать батник или компильнуть в самом Фасме. Главное - получить скомпиленый файл программы, degtorad.OBJ с которым нам надо работать дальше. Для батника все просто. Вот командная строка для компиляции и записи лога: fasm degtorad.ASM >fasm.log Для Фасма еще проще - надо нажать Ctrl+F9, что приведет к компиляции нашей программы. Можно еще и через меню это сделать: Run/Compile. В общем способов и подспособов получить скомпиленый модуль у нас хватает. Но это далеко не все. Теперь нам надо использовать командную строку или батник по-любому, если вы конечно не напишете оконную ГУЙ оболочку или не знаете аналогичной программы в визуальном исполнении. А использовать мы будем программу ar.ехе, которая находится в папочке bin Блицмакса. Надеюсь пути к bin прописаны. И для краткости изложения я приведу сразу батник: del *.a ar rc degtorad.release.win32.x86.a degtorad.OBJ ar rc degtorad.debug.win32.x86.a degtorad.OBJ Эта прога упакует наш объектный код в свой формат, используемый Blitzmax. Что это за формат - не спрашивайте, я не знаю. Да и вряд ли это надо знать для получения конечного результата. Итак, после выполнения батника или этих команд из консоли, если все настроено, мы получим два файла:
Которые идентичны, а их разное название нужно только для компиляции Blitzmax-ом в разных режимах. Как я говорил выше, с тонкостями написания дебаг-модулей в асме я не разбирался. И это уже почти все. Но надо еще написать интерфейсные файлы (с расширением *.i) для парсера. В которых надо описать нашу функцию. Примеры их написания можно почерпнуть, посмотрев как это делается у других модулей. Итак создаем два файла degtorad.release.win32.x86.i и degtorad.debug.win32.x86.i и заполняем их примерно таким содержимым: ModuleInfo "Version: 1.0"
ModuleInfo "Copyright: Oxid" Параметры ModuleInfo совсем не обязательны. Отдельно хочу обратить внимание, что здесь имя функции пишется без подчеркивания впереди. Сначала идет описание (DegToRad:float(AngleDeg#)) и потом соответствие с функцией в асм-коде (="DegToRad"). Вот import brl.blitz вполне возможно тоже не обязательный параметр - без него все работает на несложных примерах. Может это как-то поможет парсеру, но в эти тонкости я не вникал пока. И вот теперь почти все. Теперь надо только создать папку для модуля в папке для библиотек, которая в папке модулей Blitzmax и скопировать туда 4 файла:
Название для папки можете придумать любое, а у меня уже есть свои модули в папке либ oxi.mod, поэтому я просто создал там папку с правильным именем DegToRad.mod в ней. Теперь можно подгрузить модуль из программы на БМ простой командой Import oxi.degtorad. Вот пример программы на Blitzmax, его использующей: Strict
Framework brl.basic Как можно увидеть из результатов работы программы, функция дает определенную погрешность из-за приведения к float. Автор: Oxid |

