GBA ASM - День 1: Постигаем ассемблер — Архив WASM.RU

Все статьи

GBA ASM - День 1: Постигаем ассемблер — Архив WASM.RU

Вы можете спросить, будем ли мы использовать тот же ассемблер, который идёт вместе с GCC. Короткий ответ: НЕТ. Развёрнутый ответ: мы будем использовать ассемблер Goldroad, который можно найти на его сайте или скачать здесь. Я использую версию 1.6F. Вам следует скачать самую последнюю версию ассемблера и распаковать её куда-нибудь, так чтобы в пути не было пробелов. Если в пути нет пробелов - это всегда существенно облегчает жизнь.

Оки, вы распаковали ассемблер туда, куда хотели. У меня есть файл, который может вам изрядно помочь. Это screen.h из туториала Pern'а, который я вручную сконвертировал в синтаксис ассемблера Goldroad. Скачайте его здесь и поместите в ту же директорию, где находится Goldroad.exe.

Теперь вы наверняка захотите проверить, как он работает. Но для начала вам нужен эмулятор. Идите и найдите VisualboyAdvance, так как я на 100% уверен, что он понимает командную строку. Чтобы проверить, как он работает, создайте файл first.asm, скопируйте в него нижеследующий исходник и поместите в ту же директорию, где находится ассемблер.

; начинайте копировать отсюда

@include screen.h
@textarea

ldr r1,=REG_DISPCNT
ldr r2,=(BG2_ENABLE|MODE_3)
str r2,[r1]
ldr r1,=0x0FF
ldr r2,=vram+2410
str r1,[r2]
label1
B label1

@pool
@endarea

; заканчивайте копировать здесь

Альтернативный код на C будет примерно следующим:

int main()
{
SetMode(MODE_3|BG2_ENABLE);
vram[2410] = 0x0FF;
while(1)
{}
}

Тем не менее, как вы вероятно знаете, скомпилированный C-код будет ОГРОМНЫМ. Только ассемблер может дать вам маленькие бинарники. Давайте проанализируем исходник строка за строкой.

@include screen.h

Эта строка делает то же самое, что и выражение #include в C.

@textarea

Эта строка просто определяет, где начинается код.

ldr r1,=REG_DISPCNT

О, вот и первая настоящее ассемблерное выражение. Здесь в дело вступаю я.

В ARM'е (процессор GBA) есть 16 регистров r0-r15. r15 - это вроде IP (Instruction Pointer) в процессорах Intel. ОСТАВЬТЕ ЕГО В ПОКОЕ! Я стараюсь работать только с первыми 10 - r0-r9. Если вы знаете Intel- или x86-ассемблер, тогда вы ПОЧТИ знаете инструкции MOV и LDR. Эти инструкции позволяют вам перемещать 32-х битные числа. Второй операнд (число/регистр) перемещается в первый (число/регистр). Инструкция MOV используется только в особых случаях. Мы пока будем использовать LDR, которая расшифровывается как LoaD Register (загрузить в регистр). Она загружает в указанный регистр значение другого регистра, либо ячейки памяти, либо заданного числа. Давай вернёмся к нашей строке кода:

ldr r1,=REG_DISPCNT

 * Это инструкция LDR.

        * Первым параметром в нашем случае является регистр r1.
 
        * REG_DISPCNT задан в screen.h и определяет местонахождение памяти 
           управления экраном.

Используйте звёздочки, чтобы определить к чему относятся комментарии.

ldr r2,=(BG2_ENABLE|MODE_3)

Здесь то же самое, что и в предыдщущей строке, только на этот раз вторым операндом являются два сORенных значения (оператор '|'). BG2_ENABLE и MODE_3 заданы в screen.h и будучи сORенными дают значение 0x0403. Это значение помещается в регистр r2.

str r2,[r1]

Вау, наша вторая инструкция, инструкция STR помещает значение первого регистра в ячейку памяти, задаваемую вторым операндом. STR расшифровывается как STore Register (сохранить регистр). В данном случае квадратные скобки [] говорят, что регистр используется как указатель. Знаете что? Эти три инструкции делают то, что в C для нас делает SetMode(MODE_3|BG2_ENABLE). Это переводит экран в битмэп-режим номер три (3).

ldr r1,=0x0FF

Сейчас вы должны это понять - это загружает в r1 0x0FF (255).

ldr r2,=vram+2410

Вы должны понять и этом, за исключением того, что я сейчас объясню. Для начала, просто чтобы вы знали, vram также задаётся в screen.h, и это память, в которую вам понадобится писать, чтобы вывести что-нибудь на экран. vram определяется как 0x06000000.

Теперь наша инструкция прибавляет 2410 к значению vram, загружая значение в r2. Почему? Чтобы поместить значение цвета вам нужно задать x и y, верно? Поэтому вот формула для 3-его режима:

	y * 240 + x

Соответственно наша инструкция задаёт позицию x=10, y=10. Более того, 0x0FF, который мы ранее поместили в r1, будет означать ярко-красный цвет, когда мы поместитм точку на экран.

str r1,[r2]

Снова инструкция str, только в этом раз мы помещаем содержимое регистра r1 в ячейку памяти, на которую указывает r2. В данном случае r2 указывает на экранную координату 10,10, а r1 - это ярко-красный цвет. Таким образом, сохранение ярко-красного цвета в экранную память в позиции 10,10... Позже я дам вам увидеть результат. Но пока ещё немного кода.

label1

Задаёт метку, к которой вы можете перейти подобно тому, как работает команда goto в BASIC.

b label1

Эквивалентно 'Goto label1' в BASIC'е. Эти две строки создают бесконечный цикл. Инструкция B работает подобно инструкции Jxxx в x86-ассемблере, она передаёт управление в зависимости от результата предыдущих операций, подробнее об этом будет написано дальше.

@pool

Даёт ассемблеру место, куда можно поместить некоторые из чисел, которые мы задавали и использовали. АБСОЛЮТНО НЕОБХОДИМО.

@endarea

Говорит ассемблеру, что секция кода закончена.

Эй, мы только что закончили с нашей первой программой под GBA на ассемблере!

Компилирование нашего исходника

Я предполагаю, что вы работаете в Windows, да и один совет - ПОСТАВЬТЕ XP! (Второй совет от переводчика - СНЕСИТЕ XP!)

Наберите 'goldroad first.asm' в директории, где находится Goldroad Assembler и нажмите ввод.

Если вы увидели какие-нибудь сообщения об ошибках, попробуйте снова, убедитесь, что задали команду верно.

Если вы увидели "Assembled successfully" или что-нибудь вроде этого, поздравляю!

Если всё прошло как надо, то в папке Goldroad'а должен появиться файл first.gba.

Теперь осталось запустить полученный файл в эмуляторе GBA (VisualBoy Advance). На экране должна появиться красная точка где-то в районе 10,10. Поздравляю! Только что закончился День 1.

2002-2013 (c) wasm.ru