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

4 новых команды:

  • CPX (ComPare X-REG)
  • CPY (ComPare Y-REG)
  • BEQ (Branch if Equal)
  • BNE (Branch if Not Equal)

Подробно эти команды мы рассмотрим позже, сейчас мы должны обратить внимание на так называемые флаги. Флаги находятся в регистре статуса, каждый флаг может быть установлен или сброшен, то есть равняться 1 или 0. Флаги:

  • N = NEGATIVE
  • V = OVERFLOW
  • —  = НЕ ИСПОЛЬЗУЕТСЯ
  • B = BREAK
  • D = DECIMAL (Используется весьма редко)
  • I  = IRQ
  • Z = ZERO
  • C = CARRY

В большинстве случаев мы будем использовать флаги  Z и C. Флаг Z может быть установлен следующими способами:

  1. Значения регистров A, X или Y будет равно нулю.
  2. Условие сравнения будет выполнено.

Примеры:

Сравнить содержимое Y с $10. Содержимое Y было сравнено с $10,  и так как равно, поэтому Z=1.

Здесь мы хотели узнать, действительно ли в Y число  $11?  Ответ на этот вопрос нет, и поэтому  Z=0.

Попробуйте выполнить следующую небольшую программу:

 

$23 = $ 33?  НЕТ! Т. e. Z=0. Компьютер знает, что нужно переходить к «YES», если Z=1. Это условие не выполняется, поэтому  компьютер переходит на следующую команду. Теперь если Z=0, надо перейти к ‘ NO’, и так как это условие выполняется, происходит «условный переход». Результатом этого будет то, что цвет бордюра станет черным и компьютер вернется  в Basic. По сути, первый RTS не нужен, поскольку Z-флаг равен 1 или 0. То есть компьютер обязан выполнить либо BEQ или BNE и поэтому никогда не перейдет к первой RTS.

Мы теперь знаем, что:

  • BEQ — срабатывает  если  условие выполняется.
  • BNE — срабатывает если условие не выполнено.

Существуют также другие условные переходы, например, BCC и BCS, что означает «BRANCH ON CARRY CLEAR’ (переход, если C-флаг — ноль) и «BRANCH ON  CARRY SET’ (переход, если С-флаг — единица). Флаг Переноса (С-флаг) используется для сложения и вычитания (плюс и минус), но об этом позже.

Теперь мы знаем команды INX, CPX и BNE и  можем сделать следующую небольшую программу:

 Программа перемещает содержимое адресов $ 2000- $2008 вниз в адреса $1000- $1008.

ОБЗОР ПРОГРАММЫ:

Во-первых,  сбрасываем регистр X в ноль. Затем загружаем содержимое адреса $2000+X в регистр А и сохраняем по адресу $1000+X.  Затем увеличиваем X на 1. Команда CPX #$08 проверяет, достиг ли  X значения 8. Если это не так, то переход на LOOP.  Теперь X=1, поэтому значение по адресу $2001 извлекается и сохранятся в адрес $1001. Вновь X+1 и сравнение с #$08. Это позволит перейти к LOOP до тех пор, пока X-регистр не будет содержать значение $08. Теперь условие не выполнено, так что компьютер перейдет на следующую команду и выполнит RTSLOOP — это так называемая  метка, которая используются в ассемблере. Когда наша программа будет скомпилирована, то вместо нее будет адрес в памяти, куда надо совершить переход. В Мониторе мы бы увидели нашу программу так:

ПРИМЕЧАНИЕ:

Во-первых, ‘SMONEX‘ (и некоторые другие мониторы) удаляет знак $. Другими словами он предполагает, что все цифры и адреса в HEX. Наша программа начинается с адреса $6400, таким образом длина программы $640D — $6000=$0D=13 байт. Мы видим, что  ‘LDX #$00’ занимает 2 байта (1 байт для кода  команды «LDX» и 1 байт для числа).  Таким же образом LDA $2000,X занимает 3 байта (1 для кода команды, и 2 для адреса). Пожалуйста, примите к сведению что  BD 00 20, а не BD 20 00 как может вам показаться. Это связано с тем что адреса в память компьютера записываются в LOW/HIGH-BYTE формате, 00 — это младший байт адреса, а 20 старший.

Во-вторых, наш BNE LOOP был переведен в то, что машины могут понимать, а именно в BNE 6402 (не забывайте, что в SMONEX считает, что адрес в HEX). Код  BNE 6402 должен бы быть таким: D0 02 64 (LOW/HIGH-BYTE формат), но это не так! Почему вместо этого стоит D0 F5??? Дело в том, что после кода D0 указывается, насколько байт вперед или назад компьютер должен прыгнуть. Например  D0F5  означает что необходимо перейти на 10 байт назад. Десятичные 256 равны шестнадцатеричным $0100. Другими словами: $0100- $F5 =$0A (10 DEC). Команда  BNE может «прыгать» на 128 байт назад и 127 байт вперед (128 +127= 255).  По этой причине следующая программа не возможна.

В 1 байт мы пытаемся заставить компьютер перейти $6404 — $5000=$1404= 5124 байт. Невозможно!

Обратите внимание на то, что эти правила распространяются на все b-инструкции (‘BRANCH‘ -инструкции).  Если вы хотите перейти без каких-либо ограничений, используйте инструкцию JMP (JUMP).  Например:

Здесь используется 2 байта для указания адреса. По-прежнему в LOW/HIGH-BYTE формате, где ’10’ является старшим байтом  и ’12’ младшим. Этой командой можно перейти по любому адресу в памяти ($0000- $FFFF). Команда JMP переходит, независимо от того, выполняется условие или нет, и не затрагивает ни каких флагов.

Упражнение 3

В следующей программе могут быть 2 разных варианта выполнения, в зависимости от содержимого ячейки памяти $3CDF. Какие они?

Скрытый текст
  • CPY #$XX‘ — сравнение XX с содержимым регистра Y.

Инструкция CMP(‘COMPARE’) работает в точности так же, как CPX и CPY. Она применяется для регистра A(аккумулятора), так что если вы поняли как работают CPX и CPY нет никаких оснований объяснять вам как работает CMP.

INC или DEC означают соответственно,  ‘INCREASE’  и ‘DECREASE’. Работает так же, как  INX, INY, а также DEX, DEY за исключением того, что они увеличивают/уменьшают на 1 значение по указанному адресу а не значение регистра A. Пример:

Увеличивает  содержимое адреса $1200  на 1. Интересно, что делает DEC $1200? Надеюсь это вы можете выяснить сами!

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