Написание цикла while в сборке

Я пытаюсь написать цикл while в сборке с процессором 6502, и я не могу понять, как написать шестнадцатеричный код. Я видел примеры, написанные с использованием сокращения, где есть метка для того, где цикл должен начинаться и заканчиваться, но я ничего не вижу для фактического шестнадцатеричного кода.

Два кода, которые я считаю полезными:

  1. Сравнение байта в памяти с X reg (сокращение: CPX, hex: EC). Это устанавливает Z флаг на ноль, если равен и
  2. Байты ветви X, если Z flag = 0 (сокращение: BNE, hex: D0)

4 ответа

Вот место для начала: http://www.obelisk.demon.co.uk/6502/. На странице представлен кросс-ассемблер, который вы можете запустить на своем ПК. Это может быть хорошей платформой для вас.

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

- подготовка так называемых "исходных файлов" символических инструкций, которые вы называете "стенография"
- используя ассемблер, переводя этот исходный файл в машинные инструкции, которые понимает 6502
- загрузка перевода в 6502
- сказать 6502 выполнить переведенные машинные инструкции

Ваша программа-пример пытается скопировать LEN байты памяти из SRC в DST,

Вы форматируете это так:

      LDX #0    ; Start with the first byte 
_LOOP LDA SRC,X ; load a byte from SRC into the A register 
      STA DST,X ; store that byte into DST
      INX       ; bump the index register to point to the next SRC and DST locations 
      CPX #LEN  ; have we moved LEN characters?  
      BNE _LOOP ; if not, go move the next one

После того, как вы добавили больше строк выписки (например, END, например); и после того, как вы определили SRC, DST, а также LEN, вы сохраняете все это в файле, скажем, cploop.txt,

Затем вы говорите ассемблеру перевести его. Ассемблер выпускает файл двоичного машинного кода 6502, который можно представить в виде шестнадцатеричных байтов, о которых вы говорите.

Вы передаете этот файл машинного кода в имитированный 6502. Затем вы как-то предписываете 6502 выполнить операции, которые воплощает машинный код.

Вот пример, показывающий соответствие между сборкой (то, что вы называете "сокращением") и машинным кодом. Во-первых, вот код ассемблера для алгоритма с некоторыми абстрагированными параметрами:

* = 4000          ; This is the address where our program will be stored

      LDX #len
loop  LDA src,X 
      STA dest,X 
      DEX       
      BNE loop

Конечно, вы не можете превратить это непосредственно в машинный код. Вам также необходимо заполнить значения len, src а также dest:

src = $1234
dest = $5678
len = 10

Что нужно знать о loop имя это так же, как src присваивается значение $1234, loop после этого будет назначен адрес инструкции. Так что в этом случае, так как LDX #len занимает 2 байта (как я покажу вам в ближайшее время), loop установлен в $4000 + 2 = $4002, Это делается автоматически ассемблером, но, конечно, вы можете сделать все это и на бумаге.

Итак, каков машинный код 6502 для вышеуказанной программы сборки?

A2 0A
BD 34 12
9D 78 56
CA
D0 F7

Откуда я это знаю? Ну, я только что вставил вышеупомянутую программу в онлайн-ассемблер 6502 по адресу http://www.masswerk.at/6502/assembler.html. Он даже показывает подробное отображение между сборкой и машинным кодом:

4000        LDX #LEN        A2 0A
4002 LOOP   LDA SRC,X       BD 34 12
4005        STA DEST,X      9D 78 56
4008        DEX             CA
4009        BNE LOOP        D0 F7
400B

Обратите внимание, как фактическая стоимость LOOP даже не используется для вычисления машинного кода для BNE LOOPтолько его относительный адрес по сравнению с BNE сама инструкция: F7 равно -9, а разница между $400B а также $4002 это -9!

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

Команды ветвления принимают однобайтовый операнд относительного адреса со знаком, который добавляется к адресу следующей инструкции для получения цели ветвления. Поскольку инструкция ветвления всегда занимает 2 байта, целевой адрес является адресом инструкции ветвления плюс операнд (с расширенным знаком) минус 2.

Примеры:
$D0 $00: no-op: ветка переходит к следующей инструкции независимо от условия
$D0 $FE: Branch указывает на себя, создавая бесконечный цикл, если Z=0,

while утверждение действительно означает:

  1. проверить условие
  2. если условие ложно, перейдите к 5
  3. сделай что-нибудь
  4. вернуться к 1 (простой JMP или ветка)
  5. остальная часть программы

С 6502 все это будет чрезвычайно просто, если вы не сделаете много предположений. Если условие, которое вы тестируете, всегда будет регистром, инструкции сравнения (cmp, cpx, cpy) и ветвления, очевидно, то, что вам нужно для 1.

Если это будет один байт, хранящийся в памяти, вам нужно загрузить этот байт, а затем сравнить его.

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

Имеете дело с поплавками? Если вы написали или имеете доступ к пакету с плавающей запятой (например, подпрограммам с плавающей запятой Commodore 64 ROM BASIC), вам нужно будет их использовать.

Вы можете понять, почему языки высокого уровня имеют типы данных.

На самом деле, это зависит от типа данных, с которыми вы имеете дело, но любая реализация while в 6502 следует в значительной степени следовать вышеизложенному.

Конкретный случай, который вы определили в своем вопросе, - это нормально, если вы знаете, что сравниваемые данные всегда будут в X и что ваш пункт назначения всегда будет на расстоянии +127/-128 байт (предел диапазона команд Bxx).

Другие вопросы по тегам