Blitzmax
Пятница, 03.05.2024, 02:08
Приветствую Вас Гость | RSS
 
Главная СтатьиРегистрацияВход
Меню сайта
Категории каталога
Разное [2]
BlitzMax [5]
Доки/Уроки [8]
Игровое программирование [1]
Наш опрос
Оцените скорость работы с сайтом
Всего ответов: 112
Главная » Статьи » Доки/Уроки

Интеграция Blitzmax с ассемблером.
Делать ассемблерные вставки в код 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

Категория: Доки/Уроки | Добавил: oxid (08.01.2009)
Просмотров: 3002 | Комментарии: 10 | Рейтинг: 0.0/0 |

Всего комментариев: 9
08.01.2009
1. Platon
БМакс может кушать c\c++\"at&t"asm файлы посредством компилятора gcc, так что тем у кого он есть можно так не париться ;-)

08.01.2009
2. oxid
Эт я знаю. И согласен вполне. Еще можно на С/С++ асм функции писать.
Но лично я gcc не пользую. Фасм меньше места занимает и даже в поставку БМ входит - можно вообще ничего не докачивать, кроме редактора асм-кода. А тру кодер васче кодит в блокноте и компилит в консоли командной строкой :-з

08.01.2009
3. SBJoker
Хорошая статья!

09.01.2009
4. oxid
Спс.

10.01.2009
5. dimanche13
Жаль я не силен в АСМ-е для х86, но *опой чую, статья отличная! А вот насчет асм-вставок в С/С++ код это надо проверить. Спасибо.

12.01.2009
6. Diablo
Тру.
Статья - класс!
+1

12.01.2009
7. oxid
сенки

07.02.2010
8. Andrew
Мда... Умудряются же писать такие статьи, и при этом совсем не знать ассемблера...

Что ты посчитал тут:
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 ? Куда сохраняется результат?
Вообщем статья стремная.. Большинство не объясняется, а просто пишется "так надо!"..
Ну а за старания конечно огромный респект !!! Если немного поправить предложения "так надо" то статья получится отличная!


22.02.2010
9. oxid
Мдэ... Умудряются же некоторые писать ответы, совершенно не понимая о чем статья. Так типа вякнуть какой я умный.
Во-первых эта статья не про изучение АСМА, и даже не про изучение Фасма, а про то как в БМ писать на асме. Так что сколько в ФПУ регистров и через что они возврачаются читай сам.
Во-вторых, там где написано "так надо" объясняется что это, а надо так потому что таково правило. Формат - знаешь такое слово? Это претензии из разряда а почему надо писать IF, а не ЫФЬ?
В-третьих, если ты даже не понял, что я сделал в коде - иди учись, пока не поймешь, а потом будешь предьявлять что-то.
В-четвертых, советую проверять работоспособность кода перед тем как что-то коментить с умным видом. Я вот проверяю, перед тем как его публикую. Код здесь 100% рабочий.
В-пятых, я тебе не препод в школе, который делает все по книге и вместо одной операции три, но так чтоб было всем понятно.
В итоге: твой коментарий - шлак кроме того, что хорошо бы ФПУ проинициализировать finit. Причем написал ты и это с ошибкой - так, будто команду надо ставить в конце "не очистил за собой стек", а не в начале. И команда эта не для фасма а для ФПУ вообще. И она инициализирует работу (не понимаешь разницу - учись), выставляя флаги внутренних регистров ФПУ.
зы: Тебе спасибо, что доставил удовольствие моему ЧСВ разгромить твой неграмотный комент.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Поиск
Ссылки
Статистика
Copyright Oxid © 2024
Сайт создан в системе uCoz