649 подписчиков

Ассемблер для чайников (Z80)

1,9K прочитали

Основы

Это краткое описание, целью которого является понимание основ.

Ассемблер - это очень простой язык, цель которого - упростить создание программы на машинном языке. Таким образом, операторы в основном транскрибируют операции CPU, а также несколько других, чтобы упростить разработку программы.
Машинные операторы называются кодами операций. Другие обычно являются функциями, которые варьируются от одного ассемблера к другому.

Основы
Это краткое описание, целью которого является понимание основ.
Ассемблер - это очень простой язык, цель которого - упростить создание программы на машинном языке.

Регистры

Важно понять, что такое регистр, прежде чем идти дальше.

Регистр является специализированной внутренней памятью 8 бит. Регистры всегда образуют пару, которая называется парой регистров. Во время программирования регистры могут использоваться по отдельности (8 бит) или как пара регистров (16 бит) в зависимости от того, какая команда используется. Независимо от метода они указывают на одну и ту же физическую память. Меняется т.е. регистр D повлияет на пару регистров DE и наоборот. Обратите внимание - когда пары регистров загружаются или сохраняются в памяти, более поздний член пары всегда будет сохраняться по указанному адресу, а первый член будет сохраняться по адресу +1. Это означает, что регистры DE сохранится E, D в оперативной памяти.

Регистры нельзя рассматривать как общую память, поскольку не все команды Z80 могут принимать все регистры в качестве параметров. Каждая пара регистров в любом случае имеет свои особенности того, для чего они хороши. Здесь я не пытаюсь описать все, что вы можете с ними сделать, поскольку есть руководства для этого, разве только некоторые типичные характеристики.

Наиболее важные пары регистров, которые нужно знать:

А и F, образующие регистровую пару AF. A также называется аккумулятором в некоторых документах. Этот регистр является наиболее важным регистром, поскольку все 8-битные вычисления выполняются для этого регистра. По этой же причине его практически невозможно использовать для хранения информации, поскольку в результате вы очень часто загружаете и сохраняете этот регистр. F также очень важный регистр, но его нельзя использовать напрямую. Он делится на отдельные биты состояния, называемые флагами, которые меняются каждый раз, когда ЦП выполняет команду, которая должна вернуть статус. Отдельные биты этого регистра имеют разные имена, такие как флаг переноса (C), флаг нуля (Z) и так далее. Пожалуйста, прочтите про флаги ниже, для получения дополнительной информации. AF в качестве пары регистров не может использоваться вместе, кроме как для сохранения аккумулятора вместе с флагами состояния в памяти или его восстановления.

B и C, образующие регистровую пару BC. Эти регистры можно использовать как временное внутреннее хранилище ЦП. Обычно это хороший выбор в качестве 8-битного счетчика цикла. Используется, когда вам нужно указать порт ввода / вывода. Вместе регистровая пара BC обычно используется для хранения 16-битной «длины» или другого 16-битного значения, необходимого для расчета.

D и E, образующие регистровую пару DE. В качестве отдельных регистров у них нет никаких «особых даров», кроме того, что они пригодны для внутреннего временного хранения ЦП, но, когда они используются вместе как пара - используются для указания «места назначения» в памяти. DE также является хорошим выбором, когда для расчета необходимо 16-битное значение.

H и L, образующие регистровую пару HL. Как отдельные регистры, они также не имеют никаких «особых даров», но, когда они используются вместе, они образуют наиболее важную 16-битную пару, как правило, все 16-битные вычисления выполняются с HL. Он часто используется также как «источник» при наведении памяти.

Пара SP. Это 16-битный указатель, который определяет, где такие команды, как CALL или PUSH, хранят свою информацию. Начинающему программисту очень редко приходится напрямую манипулировать этим регистром, но это полезно знать. Также важно знать, что это указывает на конец хранилища, поэтому любые новые значения сохраняются до адреса, на который он указывает, и содержимое SP уменьшается на 2. 8-битные значения, которые образуют пару регистров, никогда не используются по отдельности, поэтому у них даже нет 8-битных имен.

Если вы уже много читали о регистрах, вы можете пропустить оставшуюся часть этой главы и вернуться позже, чтобы узнать больше. С этими уже упомянутыми регистрами вы уже можете делать практически все, что может делать MSX. Естественно, знание остальных регистров также важно, когда вы набираете код, но я предлагаю придерживаться этого в ваших первых программах.

Остальные регистры:

Пара PC, также известный как счетчик программ (Program Counter). Это всегда указывает на то, откуда Z80 читает программу, и, хотя это очень важно, программисту очень редко приходится думать об этом как о паре регистров. 8-битные значения, которые образуют пару регистров, никогда не используются по отдельности, поэтому у них даже нет 8-битных имен. PC также никогда не указывается напрямую, но им манипулируют с помощью команд, таких как JP xxxx (прыжок), которые можно представить как LD PC, xxxx или RET, которые можно представить как POP PC.

IXh и IXl, которые образуют регистровую пару IX. Как отдельные регистры они довольно хороши как временное хранилище. Они медленнее, чем ранее упомянутые альтернативы, но все же быстрее, чем использование внешней оперативной памяти ЦП. Использование их в качестве отдельных регистров в любом случае официально не документировано. Практически они безопасны в использовании, но вы можете найти ассемблер, который не компилирует код, если вы используете такие имена, как IXl или IXh. Как пара они ведут себя очень похоже на HL, только медленнее. Особенностью является то, что во многих случаях вы можете использовать дополнительное значение смещения, когда вы используете IX в качестве указателя.

IYh и IYl, которые образуют пару регистров IY. Эти регистры работают как индивидуально, так и в паре. Во всех случаях работают точно так же, как IX.

I и R, которые образуют регистр пары IR. Это очень специфические регистры, которые редко имеют какое-либо практическое применение. I связан с обработкой прерываний, но имеет очень мало случаев использования в среде MSX. Часть R используется как внутренний счетчик Z80, который иногда используется как источник случайного начального числа. Они более новые, используемые в качестве пары регистров, хотя в некоторых документах может появляться IR.

BC ', DE', HL 'и AF'. Они называются «теневыми регистрами» и представляют собой просто альтернативные внутренние хранилища для пар регистров BC, DE, HL и AF. Вы можете поменять место хранения с помощью команд EXX и EX AF, AF ', но это все, что вы можете сделать.

Флаги

Флаги - это то, что живет в F-регистре. Они позволяют вам действовать на основе сравнений то есть - условные решения. Если вы начинающий программист, обратите особое внимание на работу CF и ZF, так как эти двое являются самыми важными флагами. Почти все обычно делается с использованием только этих двух.

Как правило, все, что связано с вычислением чего-либо, влияет и на флаги. 16-битные команды INC и DEC являются исключением из этого правила. Обычно на флаги НЕ влияют команды перехода, команды управления ЦП или прерывания или инструкции загрузки. Загрузка из регистра I или R является исключением из этого второго правила.

Вот список флагов в F-регистре:

бит 7, SF, знак флага. Это копия результатов наиболее значимого бита. Если бит установлен (= 1 = "M") "Minus", значение из 2-х дополнений является отрицательным, в противном случае результат будет положительным (= 0 = "P") "Plus". Обратите внимание, что этот флаг можно использовать только с условной инструкцией JP.

бит 6, ZF, нулевой флаг. Если результат математической операции равен нулю, бит устанавливается (= 1 = "Z"), другими словами, бит сбрасывается (= 0 = "NZ") "Not zero"

Бит 5, YF, копия результатов 5-го бита.

Бит 4, HF, «Half-carry» от бита 3 до 4. Z80 использует это внутренне для коррекции BCD.

Бит 3, XF, копия результатов, 3-й бит.

Бит 2, PF / VF, флаг четности. Это копия младшего значащего бита результатов. Если бит установлен (= 1 = «PO»), четность нечетна, в противном случае результат будет четным. (= 0 = "PE") в некоторых случаях этот бит может использоваться для указания переполнения со знаком с 2 комплиментами. (VF) Обратите внимание, что этот флаг может использоваться только с условной инструкцией JP.

Бит 1, NF, этот бит используется внутренним Z80 для указания, была ли последняя операция сложением или вычитанием (необходимо для коррекции BCD)

Бит 0, CF, флаг переноса = бит переполнения. Этот бит - самый старший бит, который не соответствует результату. В дополнение к крупным вычислениям и переносам битов он в основном используется в сравнениях, чтобы увидеть, был ли результат вычитания меньше или больше нуля. Если установлен флаг переноса (= 1 = "C"), результат переполнен. Другие способы сброса флага (= 0 = "NC") "No carry". Обратите внимание, что 8-битные команды INC / DEC не обновляют этот флаг.

В дополнение к этим флагам есть еще два внутренних флага Z80, о которых пользователь редко должен знать, но они указаны для полноты:

IFF1 используется внутри Z80, чтобы указать, есть ли ожидающее прерывание
IFF2, это резервная копия IFF1, так что состояние может быть восстановлено.

Стек

Стек - это область памяти, указанная регистром SP, который используется для хранения обратных адресов подпрограмм, вызываемых CALL или RST. Оператор CALL или RST сохраняет в стеке адрес позади него, а затем оператор RET извлекает этот адрес, чтобы узнать, где возобновить выполнение программы после выполнения процедуры.

Вы также можете сохранить или извлечь адрес в стек с помощью PUSH и POP, но будьте осторожны, чтобы не помешать выполнению программы.
Будьте осторожны, чтобы не перезаписать данные или подпрограмму из-за чрезмерного сохранения адресов.

Заявления для кодов операций

Есть несколько типов утверждений, которые мы можем классифицировать на девять групп.

Примечание: использование регистров или значений не может свободно использоваться со всеми утверждениями. Обратитесь к документации, чтобы узнать ограничения.

Обычно в ассемблере Z80 строки отформатированы следующим образом:

[<label>[:]]<space/tab><statement>[[<space/tab><argument1>],<argument2>]

Первый параметр оператора - это место назначения, где значение будет сохранено после выполнения. В случае расчета это также первое значение расчета. Второй параметр - это источник или 2-й параметр в формуле расчета. В некоторых случаях первый параметр должен быть пропущен (AND, OR, XOR, NEG, CPL, SUB, CP). В этих случаях первый параметр всегда логически «А», хотя он не записан. В быстрых версиях операций сдвига битов регистр A может быть записан как часть самой команды. (т.е. RLC A = медленный, RLCA = быстрый)

Круглые скобки «()» используются для обозначения того, что 16-битный аргумент или регистровая пара внутри не используются напрямую, но они используются в качестве указателя памяти для извлечения / сохранения 8- или 16-битного значения. Исключением из этого правила является JP-команда, в которой скобки следует игнорировать в логическом смысле, то есть «JP (HL)» логически работает как «JP HL»

Продолжение следует.