Делать ассемблерные вставки в код 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 mov ebp,esp cmp dword[_finit],0 je _init mov eax,0 mov esp,ebp pop ebp ret
_init: mov dword[_finit],1 call ___bb_blitz_blitz mov eax,0 mov esp,ebp pop ebp ret
Кратко
что он делает: мы проверяем флаг инициализации _finit. И если
инициализации еще не было, то мы ее делаем (код после метки _init). Это
нужно для внутренних переменных модуля или глобальных переменных.
Конкретно здесь их нет, поэтому просто ставиться флаг что инициализация
уже была и вызывается ___bb_blitz_blitz. Для чего не знаю. Возможно для
какой-то дополнительной внутренней регистрации модулей. Как уже писал
без ее вызова все работает, но лучше его делать, т.к. на больших
проектах не тестировалось. Теперь пишем основной код нашей функции:
_DegToRad: push ebp mov ebp,esp
push 1016003125 fld dword[ebp+8] fmul dword[esp] fwait add esp,4
mov esp,ebp pop ebp ret
Описание: Сначала перебрасываем стек на ebp для
более удобной работы с аргументами функции. Пихаем в стек число
1016003125. Это представление в формате float числа
0.0174532925199432957692369076848861, которое является коэффициетном
преобразования градусов в радианы. Загружаем в ФПУ аргумент функции и
перемножаем его с коэффициентом. И все. Дальше просто ждем результата
от ФПУ, восстанавливаем стек и возвращаемся. Результирующее значение
будет там где ему положено быть. По идее в eax, не помню ни куда ФПУ от
этой команды результат возвращает, ни как принимает результаты Blitzmax
(или через eax или через стек). Этож больше полугода назад было. Теперь остается самая малость манипуляций с кодом - описать нашу переменную флага инициализации: section "data" data writeable align 4 _finit: dd 0 Вот и все с кодом. Полный текст программы:
format MS COFF
extrn ___bb_blitz_blitz
public ___bb_degtorad_degtorad
public _DegToRad
section "code" code
___bb_degtorad_degtorad: push ebp mov ebp,esp cmp dword[_finit],0 je _init mov eax,0 mov esp,ebp pop ebp ret
_init: mov dword[_finit],1 call ___bb_blitz_blitz mov eax,0 mov esp,ebp pop ebp ret
_DegToRad: push ebp mov ebp,esp
push 1016003125 fld dword[ebp+8] fmul dword[esp] fwait add esp,4
mov esp,ebp pop ebp ret
section "data" data writeable align 4 _finit: dd 0
Таперь
можно идти двумя путями: или писать батник или компильнуть в самом
Фасме. Главное - получить скомпиленый файл программы, 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.
Что это за формат - не спрашивайте, я не знаю. Да и вряд ли это надо
знать для получения конечного результата. Итак, после выполнения
батника или этих команд из консоли, если все настроено, мы получим два
файла: degtorad.release.win32.x86.a и degtorad.debug.win32.x86.a.
Которые идентичны и их разное название нужно только для компиляции
Blitzmax-ом в разных режимах. Как я говорил выше, с тонкостями
написания дебаг-модулей в асме я не разбирался. И это уже почти все. Но
надо еще написать интерфейсные файлы (с расширением *.i) для парсера. В
которых надо описать нашу функцию. Примеры их написания можно
почерпнуть, посмотрев как это делается у других модулей. Итак создаем два файла degtorad.release.win32.x86.i и degtorad.debug.win32.x86.i и заполняем их примерно таким содержимым: ModuleInfo "Version: 1.0" ModuleInfo "Copyright: Oxid" import brl.blitz DegToRad:float(AngleDeg#)="DegToRad" Параметры
ModuleInfo совсем не обязательны. Отдельно хочу обратить внимание, что
здесь имя функции пишется без подчеркивания впереди. Сначала идет
описание (DegToRad:float(AngleDeg#)) и потом соответствие с функцией в
асм-коде (="DegToRad"). Вот import brl.blitz вполне возможно тоже не
обязательный параметр - без него все работает на несложных примерах.
Может это как-то поможет парсеру, но в эти тонкости я не вникал пока. И вот теперь почти все. Теперь
надо только создать папку для модуля в папке для библиотек, которая в
папке модулей Blitzmax и скопировать туда 4 файла:
degtorad.debug.win32.x86.a, degtorad.release.win32.x86.a,
degtorad.release.win32.x86.i и degtorad.debug.win32.x86.i Название
для папки можете придумать любое, а у меня уже есть свои модули в папке
либ oxi.mod, поэтому я просто создал там папку с правильным именем
DegToRad.mod в ней. Теперь можно подгрузить модуль из программы на БМ простой командой Import oxi.degtorad. Вот пример программы на Blitzmax, его использующей: Strict
Framework brl.basic
Import oxi.degtorad
Print degtorad(0) + "|" +0*Pi/180
Print degtorad(1) + "|" +1*Pi/180 + "|" +Float(1*Pi/180)
Print degtorad(90) + "|" +90*Pi/180
Print degtorad(180) + "|" +180*Pi/180
Print degtorad(270) + "|" +270*Pi/180
Print degtorad(360) + "|" +360*Pi/180
Print degtorad(500) + "|" +500*Pi/180
Print degtorad(100) + "|" +Float(100*Pi/180) Как можно увидеть из результатов работы программы, функция дает определенную погрешность из-за приведения к float.
Тут можно скачать исходники: http://blitzmax.3dn.ru/load/0-0-0-14-20
Эт я знаю. И согласен вполне. Еще можно на С/С++ асм функции писать. Но лично я gcc не пользую. Фасм меньше места занимает и даже в поставку БМ входит - можно вообще ничего не докачивать, кроме редактора асм-кода. А тру кодер васче кодит в блокноте и компилит в консоли командной строкой :-з
Мда... Умудряются же писать такие статьи, и при этом совсем не знать ассемблера...
Что ты посчитал тут: fld dword[ebp+8] fmul dword[esp] fwait add esp,4
mov esp,ebp pop ebp ret
Значения из ФПУ возвращаются из регистров st(0) st(1). Вообще их 8. Не очистил за собой стек ФПУ, так твои значения там и остались. Делается это в ФАСМе командой finit. Где команда возвращения подсчитанного значения? Т.е. fstp или fst ? Куда сохраняется результат? Вообщем статья стремная.. Большинство не объясняется, а просто пишется "так надо!".. Ну а за старания конечно огромный респект !!! Если немного поправить предложения "так надо" то статья получится отличная!
Мдэ... Умудряются же некоторые писать ответы, совершенно не понимая о чем статья. Так типа вякнуть какой я умный. Во-первых эта статья не про изучение АСМА, и даже не про изучение Фасма, а про то как в БМ писать на асме. Так что сколько в ФПУ регистров и через что они возврачаются читай сам. Во-вторых, там где написано "так надо" объясняется что это, а надо так потому что таково правило. Формат - знаешь такое слово? Это претензии из разряда а почему надо писать IF, а не ЫФЬ? В-третьих, если ты даже не понял, что я сделал в коде - иди учись, пока не поймешь, а потом будешь предьявлять что-то. В-четвертых, советую проверять работоспособность кода перед тем как что-то коментить с умным видом. Я вот проверяю, перед тем как его публикую. Код здесь 100% рабочий. В-пятых, я тебе не препод в школе, который делает все по книге и вместо одной операции три, но так чтоб было всем понятно. В итоге: твой коментарий - шлак кроме того, что хорошо бы ФПУ проинициализировать finit. Причем написал ты и это с ошибкой - так, будто команду надо ставить в конце "не очистил за собой стек", а не в начале. И команда эта не для фасма а для ФПУ вообще. И она инициализирует работу (не понимаешь разницу - учись), выставляя флаги внутренних регистров ФПУ. зы: Тебе спасибо, что доставил удовольствие моему ЧСВ разгромить твой неграмотный комент.
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]