Курс программирования на ассемблере для C64(Ghouls/Mechanix). Урок 1

Сейчас мы зашли так далеко, что можем постепенно начать писать собственные программы на ассемблере. Но где в памяти мы должны их располагать? Некоторые адреса  имеют определенные значения(звук, графика, цвета и т. д.), в то же время есть адреса для общего использования. Например $D020 является адресом, который выполняет определенную функцию. Он содержит значение цвета бордюра, и может быть изменен. Когда Вы находитесь в Basic напишите:

это соответствует:
Вот описание памяти  (в общих чертах):

$0000-$00FF  ZERO PAGE
$0100-$01FF PROCESSOR STACK
$0200-$03FF рабочее пространство
$0400-$07E8 экранная память
$07E9-$07FF RAM
$0800-$9FFF область BASIC (RAM)
$A000-$BFFF ROM: BASIC (ИЛИ RAM)
$C000-$CFFF RAM
$D000-$D02E VIDEOCHIP
$D400-$D41C SIDCHIP
$D800-$DBFF COLOR RAM
$DC00-$DD0F ПРОЧЕЕ (JOYSTICK и т.д.)
$D000-$DFFF CHARACTER-ROM
$E000-$FFFF ROM: OPERATIVSYSTEM
$E000-$FFFF ELLER RAM

И так, что же все это означает? Конечно, ‘RAM’ означает ‘RANDOM ACCESS MEMORY’, а значит,  эта область памяти предназначена для размещения программ и данных. ‘ROM’ означает »READ ONLY MEMORY’, т.е. Вы можете прочитать данные из этих адресов, но не можете изменить их содержимое. В некоторых областях ($A000-$BFFF, а также $E000-$FFFF) можно, переключаться между ПЗУ и ОЗУ.

‘ZERO PAGE’ ($0000 — $00FF) является «нулевой страницей» в памяти компьютера. «Страница» состоит из 256 байт. Таким образом, $0400-$04FF страница №4, но понятие «страница» обычно используется не как область памяти. На нулевой странице есть много важных адресов для компьютера, когда он работает в BASIC. Это, например, позиция курсора, различные переменные, какая клавиша была нажата и многое другое. Когда мы работаем в машинном коде, мы можем их игнорировать и свободно использовать память от $0002 — $00FF.  $0000 и $0001 являются критическими адресами, к которым я вернусь позже.

Адреса $0002-$00FF хорошо использовать для хранения временных данных. Преимущество использования нулевой страницы лучше всего проиллюстрировать на примере:

Значение из адреса $33 загружается в регистр A и сохраняется в ячейке памяти $56. Обратите внимание, что STA 56 занимает всего 2 байта. Сравните со следующим примером:

Для команды STA 0056 используется 3 байта.  Использование первого примера экономит 1  байт. Также обратите внимание, что STA в верхнем примере имеет код $56, а  в нижнем —  $8d.

  • $0100-$01FF — область СТЕКА процессора. Здесь процессор хранит адреса возврата из подпрограмм. Лучше не трогать эту область памяти без необходимости.
  • $0200 — $03FF — рабочая область компьютера, можно использовать для хранения данных.
  • $0400 — $07E8 — это видео память. Вы можете изменять значения непосредственно командами LDA & STA. Постоянно обновляется, так что нельзя располагать свои программы.
  • $07E9-$07FF —  Маленький оперативной памяти. Никакого специального применения.
  • $0800 — $9FFF —  Здесь есть много места, но нельзя размещать программы, если Вы работаете с BASIC. Однако если программа BASIC небольшая, вы можете заставить ее работать вместе с программой в машинных кодах. Желательно чтобы программа располагалась выше адреса  $7000.
  • $A000-$BFFF — При выполнении BASIC программы компьютер должен перевести ее в машинный код. Это происходит в процессе выполнения программы и поэтому (относительно) медленно. Интерпретатор BASIC расположен в этой области памяти, а также команды, который он понимает. Это ROM и поэтому не может быть изменен. Однако Вы можете переключить его в RAM, таким образом BASIC будет выключен. Подробнее об этом позже!
  • $C000-$CFFF — RAM для свободного использования.
  • $D000-$DFFF — Содержит адреса связанные с графикой, спрайтами, цветом, звуком, джойстиками. Подробнее в следующих уроках!
  • $E000-$ FFFF —  Операционная система. Здесь находятся подпрограммы прерываний, чтения клавиатуры, загрузки и выгрузки и т.д. Также называется «Kernel». Ее можно отключить и использовать как обычный RAM.

Где мы должны размещать наши программы?  Очевидно что $0800-$9FFF наиболее  подходящее пространство. Однако мы должны ограничить его до $0800-$8FFF, потому что Турбо-Ассемблер располагается с адреса $9000.  Когда мы пишем программу в Ассемблере, он отслеживает количество свободной памяти. В статусной строке Ассемблера есть указатель «BOT:XXXX«, где XXXX — число. Ассемблер располагает данные от $8FFF и ниже. Чем длиннее наша программа, тем ниже XXXX. Если мы хотим сделать очень длинную программу, мы можем безопасно использовать для программного кода диапазон от $0800 до приблизительно  $8000. Мы можем сэкономить немного памяти в ассемблере, используя короткие имена меток. Я обычно использую такие метки:

Что делает программа, в данном случае не имеет значения. «REP», сокращенно «REPEAT» (повторить), и я использую такую метку для того чтобы помнить что  это рекурсия. Нормально использовать 3-4 буквы как аббревиатуру для обозначения действия подпрограммы. Раньше я использовал разные названия меток для подпрограмм. Через неделю, когда я смотрел на программу снова, я не мог вспомнить что делают различные подпрограммы в программе. Таким образом, следует использовать метки которые несут какой-то смысл.

Обычно я располагаю программы по адресу от $1000 и выше. Согласитесь, $1000 это такое приятное круглое число. Попробуйте запустить следующую программу:

 

Было много мусора на экране, не так ли?  Это потому, что мы копируем данные из основной памяти  в экранную. Если вместо этого мы бы решили читать из другой области (например, $6000-$6400), мы могли бы получить наш собственный текст на экране.

Обратите внимание, что мы используем в программе 4 LDA и 4 STA. Это потому, что мы читаем 256 символов за один цикл. 4 * 256=1024 байта, а экранная память имеет 40 * 25=1000 байт. Мы читаем 1024-1000=24 байта лишних, но это нам не мешает. Обратите внимание, что нет никаких CPX. Есть только ‘BNE’, потому, что «CPX» подразумевается. Рассмотрим, как работает программа.

Сначала сбрасываем  X в 0. Затем читаем из $A000 и сохраняем в $0400, из $A100 сохраняем в $0500, из $A200 сохраняем  в $0600 и из $A300 сохраняем в $0700. затем X увеличиваем на 1. Теперь вспоминаем изученное ранее —  условие имеет значение TRUE,  если, по крайней мере, один из 3 РЕГИСТРОВ (A, X и Y) содержит ноль, а затем выставляет Z-флаг. Компьютер рассматривает регистр, который изменился.  В нашем случае X и так как он только что был увеличен на 1,  значение его не равно нулю. Флаг Z = 0 и выполняется команда «BNE». Прыжок в «GETTXT». Когда X достигает 255 ($FF) инструкция «INX» увеличит его на 1 и таким образом он становится равен 0. Теперь Z-флаг = 1, и «BNE» не выполняется.  Программа продолжается и выполняет  ‘RTS’, то есть «конец». После этого обзора вы надеюсь, поняли принцип работы. В противном случае вы должны прочитать это еще раз.

4 новых инструкции:

  • TAX  — TRANSFER ACCUMULATOR TO X
  • TXA  — TRANSFER X TO ACCUMULATOR
  • TAY  — TRANSFOR ACCUMULATOR TO Y
  • TYA  — TRANSFER Y TO ACCUMULATOR


TAX означает, что содержимое аккумулятора передается в X. Противоположная команда  TXA. TAY и TYA работают таким же образом с регистром Y.

Упражнение 4

Что делает следующая программа?

Скрытый текст

Эти инструкции являются очень практичными. Например, если вы хотите чтобы 3 записи содержали одинаковое значение, вместо:

практичней написать:

Попробуйте следующую программу:


Программа выведет 256 символов на экран, так как они располагаются в памяти. Можно конечно сделать свой собственный набор символов, но об этом во втором уроке…

Еще одна инструкция, которая особенно полезна — инструкция «JSR», что означает ‘JUMP TO SUBROUTINE’ (прыжок в подпрограмму).

Пример:

Сначала заполняем первые 256 позиций на экране  256 символами. Затем прыгаем на COLR (цвет), где цифра $00 сохраняется в ячейках памяти $D020 и $D021(цвет бордюра и фона будет черным). Затем выполняется RTS, но теперь мы возвращаемся не как обычно обратно в BASIC, а вместо этого возвращаемся к «LOOP2». Когда компьютер выполняет JSR  он сохраняет 2 числа в стеке. Эти 2 числа являются адресом  откуда он пришел после выполнения JSR. Как только он доходит до RTS, то загружает эти 2 числа из СТЕКА и компьютер продолжает работу с того места откуда он совершил переход. JSR COLR был просто небольшим крюком для подпрограммы, которая выставляет цвет экрана черным. Это конечно не полноценная подпрограмма, а пример использования JSR. Возвращается  компьютер обратно в «LOOP2». Мы видим, что «LOOP2» работает почти так же, как «LOOP1». Отсутствует только «LDY #$00». Это излишне, потому что Y уже содержит значение $00. Посмотрите внимательно на программу, и думаю, вы поймете почему.

Две полезных подпрограммы KERNEL: $E544 и $FF81. JSR $E544 делает то же самое, что и вы, когда нажимаете «SHIFT+CLR/HOME» —  очищает экран.  JSR $FF81 также очищает экран, но также выставляет цвет экрана обратно в «нормальный» режим – светло-синий бордюр и синий цвет фона. Он также делает некоторые другие вещи, но мы не будем вдаваться в них здесь. Обычно я использую его в начале всех моих программ, например, так:

JSR $FF81 является своего рода «RESET» для экрана.

COLOR RAM тесно связана с экранной памятью и она начинает с $D800. Например:

Цвет букв на экране будет зеленым.

Добавить комментарий