Глава 4: Учебное пособие по языку ассемблера микропроцессора 6502

Glava 4 Ucebnoe Posobie Po Azyku Assemblera Mikroprocessora 6502



Глава 4: Учебное пособие по языку ассемблера микропроцессора 6502

4.1 Введение

Микропроцессор 6502 был выпущен в 1975 году. В то время он использовался в качестве микропроцессора для некоторых персональных компьютеров, таких как Apple II, Commodore 64 и BBC Micro.







Микропроцессор 6502 до сих пор производится в больших количествах. Это уже не центральный процессор, который сегодня используется в персональных компьютерах (ноутбуках), но он по-прежнему производится в больших количествах и сегодня используется в электронных и электроприборах. Чтобы понять более современные компьютерные архитектуры, очень полезно изучить старый, но довольно успешный микропроцессор, такой как 6502.



Поскольку его легко понять и программировать, это один из лучших (если не лучший) микропроцессор для обучения языку ассемблера. Язык ассемблера — это язык низкого уровня, который можно использовать для программирования компьютера. Обратите внимание, что язык ассемблера одного микропроцессора отличается от языка ассемблера другого микропроцессора. В этой главе изучается язык ассемблера микропроцессора 6502. Точнее, обучают именно 65C02, но называют его просто 6502.



Известный в прошлом компьютер назывался Commodore_64. 6502 — микропроцессор семейства 6500. Компьютер Commodore_64 использует микропроцессор 6510. Микропроцессор 6510 имеет 6500 мкП. Набор команд 6502 µP почти полностью содержит инструкции 6510 µP. Знания в этой и следующей главах основаны на компьютере Commodore_64. Эти знания используются в качестве основы для объяснения современных компьютерных архитектур и современных операционных систем в этой части онлайн-курса карьеры.





Компьютерная архитектура относится к компонентам материнской платы компьютера и объяснению того, как данные передаются внутри каждого компонента, особенно микропроцессора, как данные передаются между компонентами, а также как данные взаимодействуют. Единственное число данных — это датум. Эффективный способ изучения компьютерной архитектуры компьютера — изучение языка ассемблера материнской платы.

Компьютер Commodore_64 называется компьютером с 8-битным компьютерным словом. Это означает, что информация хранится, передается и обрабатывается в форме восьмибитных двоичных кодов.



Блок-схема материнской платы Commodore 64
Блок-схема материнской платы Commodore 64:


Рис. 4.1 Блок-схема системного блока Commodore_64

Представьте себе микропроцессор 6510 как микропроцессор 6502. Общая память представляет собой серию байтов (8 бит на байт). Существует оперативная память (чтение/запись), в которую можно записывать или стирать байты. При отключении питания компьютера вся информация в оперативной памяти (ОЗУ) стирается. Также имеется постоянное запоминающее устройство (ПЗУ). При отключении питания компьютера информация в ПЗУ сохраняется (не стирается).

Существует порт ввода/вывода (схема), который на схеме называется устройствами ввода/вывода. Этот порт не следует путать с портами, которые видны на левой и правой или передней и задней вертикальных поверхностях системного блока компьютера. Это две разные вещи. Соединения этого внутреннего порта с периферийными устройствами, такими как жесткий диск (или дискета), клавиатура и монитор, на схеме не показаны.

На схеме изображены три шины (группы электрических очень маленьких жил-проводников). Каждый провод может передавать бит 1 или бит 0. Шина данных для передачи восьмибитных байтов за раз (один тактовый импульс) в ОЗУ и порт ввода-вывода (устройства ввода-вывода) является двунаправленной. Шина данных имеет ширину восемь бит.

Все компоненты подключены к адресной шине. Адресная шина является однонаправленной от микропроцессора. Адресная шина имеет шестнадцать проводников, каждый из которых несет один бит (1 или 0). Шестнадцать бит передаются за один тактовый импульс.

Есть управляющая шина. Некоторые проводники шины управления будут передавать по одному биту от микропроцессора к другим компонентам. Несколько линий управления передают биты от порта ввода/вывода (IO) к микропроцессору.

Компьютерная память
ОЗУ и ПЗУ считаются одним блоком памяти. Схематически эта сборка представлена ​​следующим образом, где шестнадцатеричные числа имеют префикс «$»:


Рис. 4.11. Структура памяти компьютера Commodore 64.

Оперативная память от 0000 16 в ДФФФ 16 который записывается от $0000 до $DFFF. В языке ассемблера 6502 µP шестнадцатеричное число начинается с префикса «$» и не имеет суффикса (индекса) 16, H или шестнадцатеричного числа. Любая информация в оперативной памяти исчезает при выключении компьютера. ПЗУ начинается с $E000 до $FFFF. В нем есть подпрограммы, которые не отключаются при выключении компьютера. Эти подпрограммы являются широко используемыми процедурами, которые помогают в программировании. Пользовательская программа вызывает их (см. следующую главу).

Пространство (байты) от $0200 до $D000 предназначено для пользовательских программ. Пространство от $D000 до $DFFF предназначено для информации, непосредственно связанной с периферийными устройствами (устройствами ввода/вывода). Это часть операционной системы. Итак, операционная система компьютера Commodore-64 состоит из двух основных частей: части в ПЗУ, которая никогда не выключается, и части от $D000 до $DFFF, которая выключается при отключении питания. Эти данные ввода/вывода должны загружаться с диска каждый раз при включении компьютера. Сегодня такие данные называются драйверами периферии. Периферийные устройства начинаются от порта устройства ввода/вывода через соединения на материнской плате до идентифицируемых портов на вертикальных поверхностях компьютера, к которым подключены монитор, клавиатура и т. д., а также к самим периферийным устройствам (монитору, клавиатуре и т. д.). .).

Память состоит из 2 16 = 65 536 байтовых ячеек. В шестнадцатеричной форме это 10000. 16 = 10000 ЧАС = 10000 шестигранник = локации стоимостью 10 000 долларов. В вычислениях счет по двум, десятым, шестнадцатым и т. д. начинается с 0, а не с 1. Таким образом, первая позиция на самом деле является номером ячейки 0000000000000000. 2 = 0 10 = 0000 16 = 0000 долларов США. На языке ассемблера 6502 µP идентификатор адреса начинается с префикса $ и не имеет суффикса или нижнего индекса. Последнее местоположение — это номер местоположения 1111111111111111. 2 = 65 535 10 = ФФФФ 16 = $FFFF, а не 10000000000000000 2 , или 65 536 10 , или 10000 16 или 10 000 долларов. 10000000000000000 2 , 65 536 10 , 10000 16 , или $10000 дает общее количество байтовых ячеек.

Здесь, 2 16 = 65 536 = 64 х 1024 = 64 х 2 10 = 64 Кбайт (Килобайт). Суффикс 64 в названии Commodore-64 означает 64 КБ общей памяти (ОЗУ и ПЗУ). Байт состоит из 8 бит, и 8 бит помещаются в одну байтовую ячейку памяти.

64 Кбайт памяти разделены на страницы. На каждой странице есть 0100 16 = 256 10 байтовые местоположения. Первые 256 10 = первый 0100 16 Locations — это страница 0. Вторая — страница 1, третья — страница 2 и так далее.

Для адресации 65 536 ячеек необходимо 16 бит для каждой ячейки (адреса). Итак, адресная шина от микропроцессора к памяти состоит из 16 линий; одна строка для одного бита. Бит — это либо 1, либо 0.

Регистры 6502 мкП
Регистр подобен байтовым ячейкам для байтовой ячейки памяти. 6502 µP имеет шесть регистров: пять 8-битных регистров и один 16-битный регистр. 16-битный регистр называется счетчиком программ и сокращенно PC. Он содержит адрес памяти для следующей инструкции. Программа на ассемблере состоит из инструкций, которые размещаются в памяти. Шестнадцать (16) различных битов необходимы для адресации определенного байта в памяти. В определенный тактовый импульс эти биты отправляются в 16-битные адресные линии адресной шины для чтения инструкции. Все регистры 6502 мкП изображены следующим образом:


Рис. 4.12 Регистры 6502 мкП

Счетчик программ или ПК можно рассматривать на схеме как 16-битный регистр. Младшие восемь битов обозначены как PCL для низкого уровня счетчика программ. Старшие восемь битов обозначены как PCH для высокого уровня счетчика программ. Инструкция в памяти Commodore-64 может состоять из одного, двух или трех байтов. 16 бит в ПК указывают на следующую команду, которая должна быть выполнена в памяти. Среди схем микропроцессора две из них называются арифметико-логическим блоком и декодером инструкций. Если текущая инструкция, обрабатываемая в микропроцессоре, имеет длину один байт, эти две схемы увеличивают PC для следующей инструкции на 1 единицу. Если текущая инструкция, обрабатываемая в микропроцессоре, имеет длину два байта, то есть она занимает два последовательных байта в памяти, эти две схемы увеличивают PC для следующей инструкции на 2 единицы. Если текущая инструкция, обрабатываемая в микропроцессоре, имеет длину три байта, то есть она занимает три последовательных байта в памяти, эти две схемы увеличивают PC для следующей инструкции на 3 единицы.

Аккумулятор «А» представляет собой восьмибитный регистр общего назначения, в котором хранятся результаты большинства арифметических и логических операций.

Регистры «X» и «Y» используются для подсчета шагов программы. Счет в программировании начинается с 0. Поэтому они называются индексными регистрами. У них несколько другие цели.

Хотя регистр указателя стека «S» имеет 9 бит, который считается восьмибитным регистром. Его содержимое указывает на местоположение байта на странице 1 оперативной памяти (ОЗУ). Страница 1 начинается с байта $0100 (256 10 ) в байт $01FF (511 10 ). Когда программа выполняется, она переходит от одной инструкции к следующей последовательной инструкции в памяти. Тем не менее, это не всегда так. Бывают случаи, когда он переходит из одной области памяти в другую, чтобы продолжить последовательное выполнение там инструкций. Страница 1 в оперативной памяти используется в качестве стека. Стек — это большая область оперативной памяти, имеющая очередные адреса продолжения кода, откуда происходит переход. Коды с инструкциями по переходу не находятся в стеке; они находятся в другом месте памяти. Однако после выполнения инструкций перехода адреса продолжения (а не сегменты кода) остаются в стеке. Они были перемещены туда в результате инструкций перехода или ветвления.

Восьмибитный регистр состояния процессора P — это регистр особого типа. Отдельные биты не связаны друг с другом. Каждый бит там называется флагом и оценивается независимо от остальных. Значения флагов приводятся ниже по мере необходимости.

Первый и последний битовый индекс для каждого регистра указаны над каждым регистром на предыдущей диаграмме. Отсчет битового индекса (позиции) в регистре начинается с 0 справа.

Страницы памяти в двоичном, шестнадцатеричном и десятичном формате
В следующей таблице показано начало страниц памяти в двоичном, шестнадцатеричном и десятичном формате:

На каждой странице 1 0000 0000 2 количество байтов, равное 100 ЧАС количество байтов, равное 256 10 количество байтов. На предыдущей диаграмме памяти страницы указаны вверх от страницы 0, а не вниз, как указано в таблице.

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

В оставшейся части этой главы объясняется язык ассемблера 6502 µP с использованием всей предыдущей информации. Чтобы быстро понять язык, читатель должен складывать и вычитать по шестнадцатеричной системе счисления вместо десятичной. На самом деле предполагается, что это число по второму основанию, но вычисления по второму основанию затруднительны. Помните, что при сложении двух чисел по основанию два перенос по-прежнему равен 1, как и в десятичной системе. Но при вычитании двух чисел по основанию два заимствование равно двум, а не десяти, как в десятичной системе счисления. При сложении двух чисел по шестнадцатеричной системе перенос по-прежнему равен 1, как и в десятичной системе. Но при вычитании двух чисел по шестнадцатеричной системе заимствование равно шестнадцати, а не десяти, как по десятичной системе.

4.2 Инструкции по передаче данных

Рассмотрим следующую таблицу инструкций передачи данных на языке ассемблера для 6502 µP:

Когда байт (8 бит) копируется из байтовой ячейки памяти в регистр аккумулятора, регистр X или регистр Y, который загружается. Когда байт копируется из любого из этих регистров в байтовую ячейку памяти, это называется передачей. Когда байт копируется из одного регистра в другой, он все равно передается. Во втором столбце таблицы стрелкой показано направление копирования байта. Остальные четыре столбца показывают различные режимы адресации.

Запись в столбце режима адресации представляет собой фактический байт-код соответствующей мнемонической части инструкции в шестнадцатеричном формате. Например, AE — это фактический байт-код для LDX, который предназначен для загрузки байта из памяти в регистр X в режиме абсолютной адресации, например AE. 16 = 10101110 2 . Итак, биты для LDX в ячейке байта памяти равны 10101110.

Обратите внимание, что для мнемонической части инструкции LDX существует три возможных байта: A2, AE и A6, и каждый из них предназначен для определенного режима адресации. Если байт, загружаемый в регистр X, не нужно копировать из байтовой ячейки памяти, значение необходимо ввести с (сразу после) мнемоникой LDX в инструкции в шестнадцатеричном или десятичном формате. В этой главе такие значения вводятся в шестнадцатеричном формате. Это немедленная адресация, поэтому фактический байт в памяти, представляющий LDX, равен A2. 16 = 10100010 2 и не АЕ 16 что равно 10101110 2 .

В таблице все байты под заголовками режима адресации называются кодами операций, что сокращенно обозначается как коды операций. Для одной мнемоники может быть более одного кода операции, в зависимости от режима адресации.

Примечание: Слово «загрузка» в системном блоке компьютера может иметь два значения: оно может относиться к загрузке файла с диска в память компьютера или может относиться к передаче байта из байтовой ячейки памяти в регистр микропроцессора. .

Для 6502 мкП имеется больше режимов адресации, чем четыре в таблице.

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

Память M и аккумулятор A

Память в аккумулятор

Немедленная адресация
Следующая инструкция сохраняет число FF 16 = 255 10 в аккумулятор:

LDA #$FF

«$» используется не только для идентификации адреса памяти. Обычно он используется для обозначения того, что следующее за ним число является шестнадцатеричным. В этом случае $FF не является адресом какого-либо байта памяти. Это число 255 10 в шестнадцатеричном формате. Основание 16 или любые другие его эквивалентные индексы не должны записываться в инструкции языка ассемблера. Символ «#» указывает, что все, что следует за следующим, является значением, которое должно быть помещено в регистр аккумулятора. Значение также можно записать в десятичной системе счисления, но в этой главе это не делается. «#» означает немедленную адресацию.

Мнемоника имеет некоторое сходство с соответствующей английской фразой. «LDA #$FF» означает загрузку номера 255. 10 в аккумулятор A. Поскольку это непосредственная адресация из предыдущей таблицы, LDA — это A9, а не AD или A5. A9 в двоичном формате равен 101010001. Таким образом, если A9 для LDA находится по адресу $0200 в памяти, $FF находится по адресу $0301 = 0300 + 1. #$FF — это именно операнд для мнемоники LDA.

Абсолютная адресация
Если значение $FF находится в ячейке $0333 памяти, предыдущая инструкция будет такой:

LDA $0333

Обратите внимание на отсутствие #. В этом случае отсутствие # означает, что далее идет адрес памяти, а не интересующее значение (не значение, которое нужно поместить в аккумулятор). Итак, на этот раз код операции для LDA — AD, а не A9 или A5. Операндом для LDA здесь является адрес $0333, а не значение $FF. $FF находится в локации $0333, что довольно далеко. Инструкция «LDA $0333» занимает в памяти три последовательные ячейки, а не две, как на предыдущей иллюстрации. «AD» для LDA находится в позиции $0200. Младший байт 0333, равный 33, находится в позиции $0301. Старший байт $0333, равный 03, находится в позиции $0302. Это метод с прямым порядком байтов, который используется языком ассемблера 6502. Языки ассемблера разных микропроцессоров различны.

Это пример абсолютной адресации. $0333 — это адрес местоположения, в котором есть $FF. Инструкция состоит из трех последовательных байтов и не включает $FF или его фактическое расположение в байте.

Нулевая страница адресации

Предположим, что значение $FF находится в ячейке памяти $0050 на нулевой странице. Расположение байтов нулевой страницы начинается с $0000 и заканчивается на $00FF. Это 256 10 локации в целом. Каждая страница памяти Commodore-64 — 256. 10 длинный. Обратите внимание, что старший байт равен нулю для всех возможных мест нулевой страницы памяти. Режим нулевой адресации аналогичен режиму абсолютной адресации, но старший байт 00 не вводится в команду. Итак, чтобы загрузить $FF из ячейки $0050 в аккумулятор, инструкция режима адресации с нулевой страницей выглядит следующим образом:

LDA 50 долларов США

Поскольку LDA — это A5, а не A9 или AD, A5 16 = 10100101 2 . Помните, что каждый байт в памяти состоит из 8 ячеек, и в каждой ячейке находится бит. Инструкция здесь состоит из двух последовательных байтов. A5 для LDA находится в ячейке памяти $0200, а адрес $50 без старшего байта 00 находится в ячейке $0301. Отсутствие 00, которое заняло бы байт в общей памяти объемом 64 КБ, экономит пространство памяти.

Аккумулятор в память

Абсолютная адресация
Следующая инструкция копирует значение байта, каким бы оно ни было, из аккумулятора в ячейку памяти размером $1444:

ОНИ СТОЯТ $1444

Говорят, что это передача из аккумулятора в память. Он не загружается. Загрузка обратная. Байт кода операции для STA — 8D. 16 = 10001101 2 . Эта инструкция состоит из трёх последовательных байтов в памяти. 8D 16 находится в позиции $0200. 44 16 адреса $1444 находится в позиции $0201. И 14 16 находится в позиции $0202 – небольшой порядок байтов. Фактически копируемый байт не является частью инструкции. Здесь для STA используется 8D, а не 85 для адресации нулевой страницы (в таблице).

Адресация нулевой страницы
Следующая инструкция копирует значение байта, каким бы оно ни было, из аккумулятора в ячейку памяти $0050 на нулевой странице:

СТА $0050

Байт кода операции для STA здесь равен 85. 16 = 10000101 2 . Эта инструкция состоит из двух последовательных байтов в памяти. 85 16 находится в позиции $0200. 50 16 адреса $0050 находится в позиции $0201. Проблема порядка байтов здесь не возникает, поскольку адрес имеет только один байт — младший. Фактически копируемый байт не является частью инструкции. Здесь для STA используются 85, а не 8D для адресации нулевой страницы.

Не имеет смысла использовать непосредственную адресацию для передачи байта из аккумулятора в ячейку памяти. Это связано с тем, что фактическое значение, например $FF, должно быть указано в инструкции при непосредственной адресации. Таким образом, немедленная адресация невозможна для передачи значения байта из регистра микропроцессора в любую ячейку памяти.

Мнемоники LDX, STX, LDY и STY
LDX и STX аналогичны LDA и STA соответственно. Но здесь используется регистр X, а не регистр A (аккумулятор). LDY и STY аналогичны LDA и STA соответственно. Но здесь используется регистр Y, а не регистр A. Обратитесь к Таблице 4.21 для каждого кода операции в шестнадцатеричном виде, который соответствует определенной мнемонике и конкретному режиму адресации.

Переводы между регистрами
Предыдущие два набора инструкций в Таблице 4.21 касаются копирования памяти/регистров микропроцессора (передачи) и копирования регистров/регистров (передачи). Инструкции TAX, TXA, TAY, TYA, TSX и TXS осуществляют копирование (перенос) из регистра микропроцессора в другой регистр того же микропроцессора.

Чтобы скопировать байт из A в X, инструкция следующая:

НАЛОГ

Чтобы скопировать байт из X в A, инструкция следующая:

Техас

Чтобы скопировать байт из A в Y, инструкция следующая:

РУКА

Чтобы скопировать байт из Y в A, инструкция следующая:

ТИА

Для компьютера Commodore 64 стек находится в памяти на странице 1 сразу после страницы 0. Как и любая другая страница, она состоит из 25610 10 байтовые местоположения: от $0100 до $01FF. Обычно программа выполняется от одной инструкции к следующей последовательной инструкции в памяти. Время от времени происходит переход на другой сегмент кода памяти (набора инструкций). Область стека в памяти (ОЗУ) содержит адреса следующих инструкций, с которых были прекращены переходы (или ветвления) для продолжения программы.

Указатель стека «S» представляет собой 9-битный регистр в 6502 мкП. Первый бит (крайний левый) всегда равен 1. Все адреса расположения байтов на первой странице начинаются с 1, за которым следуют 8 разных битов для 256. 10 локации. Указатель стека имеет адрес места на странице 1, где находится адрес следующей инструкции, которую программа должна вернуть и продолжить после выполнения текущего сегмента кода (перешедшего к нему). Поскольку первый бит всех адресов стека (первая страница) начинается с 1, регистр указателя стека должен содержать только оставшиеся восемь битов. В конце концов, его первый бит, самый левый бит (девятый бит, считая справа), всегда равен 1.

Чтобы скопировать байт из S в X, инструкция следующая:

ТСХ

Чтобы скопировать байт из X в S, инструкция следующая:

ТЕКСТ

Инструкции регистр-регистр не принимают никаких операндов. Они состоят только из мнемоники. Каждая мнемоника имеет свой код операции в шестнадцатеричном формате. Это режим подразумеваемой адресации, поскольку здесь нет операнда (нет адреса памяти, нет значения).

Примечание: Передачи (копирования) X в Y или Y в X нет.

4.3 Арифметические операции

Схема арифметико-логического устройства в микропроцессоре 6502 может складывать только два восьмибитных числа за раз. Оно не вычитает, не умножает и не делит. В следующей таблице показаны коды операций и режимы адресации для арифметических операций:

Примечание: Все мнемоники арифметических операций и других типов операций (т.е. все мнемоники 6502) занимают один байт кода операции (ОП). Если для мнемоники существует более одного режима адресации, для одной и той же мнемоники будут разные коды операций: по одному на каждый режим адресации. C, D и V в таблице являются флагами регистра состояния. Их значения будут даны позже по мере необходимости.

Добавление беззнаковых чисел
В 6502 µP числа со знаком представляют собой числа, дополняемые до двух. Беззнаковые числа — это обычные положительные числа, начинающиеся с нуля. Итак, для байта из восьми бит наименьшее беззнаковое число — 00000000. 2 = 0 10 = 00 16 и самое большое беззнаковое число — 11111111. 2 = 255 10 = ФФ 16 . Для двух беззнаковых чисел сложение:

А+М+С→А

Это означает, что 8-битное содержимое аккумулятора добавляется арифметико-логическим устройством к байту (8 бит) из памяти. После сложения A и M перенос девятого бита переходит в ячейку флага переноса в регистре состояния. Любой предыдущий бит переноса из предыдущего сложения, который все еще находится в ячейке флага переноса в регистре состояния, также добавляется к сумме A и M, образуя A+M+C→A. Результат возвращается в аккумулятор.

Если добавление процентов составляет:

А + М

И нет необходимости добавлять какой-либо предыдущий перенос, необходимо сбросить флаг переноса, который равен 0, чтобы добавление было:

A+M+0→A то же, что A+M→A

Примечание: Если M добавляется к A и происходит перенос 1, поскольку результат больше 255 10 = 11111111 2 = ФФ 16 , это новый керри. Этот новый перенос 1 автоматически отправляется в ячейку флага переноса на случай, если он понадобится для суммирования следующей пары восьми битов (еще один A + M).

Код для добавления двух беззнаковых восьмибитов
00111111 2 +00010101 2 то же самое, что и 3F 16 + 15 16 это то же самое, что 63 10 +21 10 . Результат: 010101002. 2 это то же самое, что 54 16 и 84 10 . Результат не выходит за пределы максимального числа для восьми бит, равного 255. 10 = 11111111 2 = ФФ 16 . Таким образом, результирующего переноса 1 нет. Другими словами, результирующий перенос равен 0. До сложения не существует предыдущего переноса 1. Другими словами, предыдущий перенос равен 0. Код для выполнения этого сложения возможно:

ЦЛК
LDA#$3F
АЦП №$15

Примечание: При наборе языка ассемблера в конце каждой инструкции нажимается клавиша «Enter» клавиатуры. В этом коде три инструкции. Первая инструкция (CLC) очищает флаг переноса, если предыдущее сложение имеет 1. CLC можно выполнить только в режиме подразумеваемой адресации. Мнемоника режима подразумеваемой адресации не принимает операндов. Это очищает ячейку переноса регистра состояния P. Очистка означает передачу бита 0 в ячейку флага переноса. Следующие две инструкции в коде используют режим непосредственной адресации. При непосредственной адресации для мнемоники имеется только один операнд, который является числом (а не адресом памяти или регистра). Итак, номеру должен предшествовать «#». Знак «$» означает, что следующее за ним число шестнадцатеричное.

Вторая инструкция загружает число 3F. 16 в аккумулятор. Для третьей команды схема арифметико-логического устройства микропроцессора принимает предыдущий (очищенный) перенос 0 (принудительно установленный в 0) ячейки флага переноса регистра состояния и добавляет его к 15. 16 а также к значению, которое уже есть в 3F 16 аккумулятор и помещает полный результат обратно в аккумулятор. В этом случае происходит перенос 0. АЛУ (арифметико-логическое устройство) отправляет (вводит) 0 в ячейку флага переноса регистра состояния. Регистр состояния процессора и регистр состояния означают одно и то же. Если в результате произошел перенос 1, АЛУ отправляет 1 во флаг переноса регистра состояния.

Три строки предыдущего кода должны находиться в памяти, прежде чем они будут выполнены. Код операции 1816 для CLC (неявная адресация) находится в позиции $0200 байт. Код операции A9 16 для LDA (непосредственная адресация) находится в позиции $0201 байт. Число 3F 10 находится в байтовой позиции $0202. Код операции 69 16 для LDA (непосредственная адресация) находится в байтовой позиции $0203. Число 15 10 находится в байтовой позиции $0204.

Примечание: LDA — это инструкция передачи (загрузки), а не арифметическая инструкция (мнемоника).

Код для добавления двух беззнаковых шестнадцатибитов
Все регистры в 6502 µP по существу являются восьмибитными, за исключением регистра PC (счетчик программ), который является 16-битным. Даже регистр состояния имеет ширину 8 бит, хотя его восемь бит не работают вместе. В этом разделе рассматривается сложение двух 16 беззнаковых битов с переносом из первой пары восьми бит во вторую пару восьми бит. Здесь нас интересует перенос из восьмой битовой позиции в девятую битовую позицию.

Пусть числа будут 0010101010111111. 2 = 2ABF16 16 = 10 943 10 и 0010101010010101 2 = 2А95 16 = 10 901 10 . Сумма 0101010101010100. 2 = 5554 16 = 21 844 10 .

Сложение этих двух беззнаковых чисел по основанию два происходит следующим образом:

В следующей таблице показано то же самое сложение с переносом 1 из восьмого бита в девятую битовую позицию, начиная справа:

При этом кодировании сначала добавляются два младших байта. Затем АЛУ (арифметико-логическое устройство) отправляет перенос 1 из позиции восьмого бита в позицию девятого бита в ячейку флага переноса в регистре состояния. Результат 0 1 0 1 0 1 0 0 без переноса поступает в аккумулятор. Затем добавляется вторая пара байтов с переносом. Мнемоника ADC означает автоматическое сложение с предыдущим переносом. В этом случае предыдущий перенос, равный 1, не должен меняться до второго сложения. Для первого сложения, поскольку любой предыдущий перенос не является частью этого полного сложения, его необходимо очистить (сделать равным 0).

Для полного сложения двух пар байтов первое сложение выглядит так:

А + М + 0 -> А

Второе дополнение:

А + М + 1 -> А

Таким образом, флаг переноса должен быть очищен (присвоено значение 0) непосредственно перед первым сложением. Следующая программа, объяснение которой читатель должен прочитать ниже, использует для суммирования режим абсолютной адресации:

ЦЛК
ЛДА $0213
АЦП $0215
; нет очистки, поскольку необходимо значение флага переноса
СТА $0217
ЛДА $0214
АЦП $0216
СТА $0218

Обратите внимание, что в языке ассемблера 6502 комментарий начинается с точки с запятой. Это означает, что при выполнении программы точка с запятой и все, что находится справа от нее, игнорируется. Написанная ранее программа находится в текстовом файле и сохраняется с именем по выбору программиста и с расширением «.asm». Предыдущая программа — это не та программа, которая отправляется в память для выполнения. Соответствующая программа в памяти называется транслированной программой, в которой мнемоника заменяется кодами операций (байтами). Любой комментарий остается в текстовом файле на языке ассемблера и удаляется до того, как переведенная программа достигнет памяти. Фактически, сегодня на диске сохранено два файла: файл «.asm» и файл «.exe». Файл «.asm» показан на предыдущем рисунке. Файл «.exe» — это файл «.asm», в котором все комментарии удалены, а все мнемоники заменены их кодами операций. При открытии в текстовом редакторе файл «.exe» не распознается. Если не указано иное, для целей данной главы файл «.exe» копируется в память, начиная с адреса $0200. Это еще один смысл загрузки.

Два добавляемых 16-битных числа занимают в памяти четыре байта для абсолютной адресации: по два байта на число (память представляет собой последовательность байтов). При абсолютной адресации операнд опкода находится в памяти. Результат суммирования имеет ширину два байта и также должен быть помещен в память. Это дает в общей сложности 6 10 = 6 16 байты для ввода и вывода. Ввод осуществляется не с клавиатуры, а вывод — не с монитора или принтера. В этой ситуации входные данные находятся в памяти (ОЗУ), а выходные данные (результат суммирования) возвращаются в память (ОЗУ).

Прежде чем программа будет выполнена, переведенная версия должна сначала находиться в памяти. Глядя на предыдущий код программы, видно, что инструкции без комментария составляют 19 10 = 13 16 байты. Итак, программа берет из байтовой ячейки $0200 в памяти до $0200 + $13 – $1 = $0212 байтовой ячейки (начиная с $0200, а не $0201, что подразумевает – $1). Добавление 6 байтов для входных и выходных чисел приводит к завершению всей программы на $0212 + $6 = $0218. Общая продолжительность программы – 19 16 = 25 10 .

Младший байт дополнения должен находиться в адресе $0213, а старший байт того же дополнения должен находиться в адресе $0214 – небольшой порядок байтов. Аналогично, младший байт сложения должен находиться в адресе $0215, а старший байт того же сложения должен находиться в адресе $0216 – небольшой порядок байтов. Младший байт результата (суммы) должен находиться в адресе $0217, а старший байт того же результата должен находиться в адресе $0218 — небольшой порядок байтов.

Код операции 18 16 для CLC (подразумеваемая адресация) находится в байтовой позиции $0200. Код операции для «LDA $0213», т. е. AD. 16 для LDA (абсолютная адресация) находится в байтовой позиции $0201. Младший байт дополнения (10111111) находится в ячейке памяти $0213. Помните, что каждый код операции занимает один байт. Адрес «$0213» «LDA $0213» находится в байтовых ячейках $0202 и $0203. Инструкция «LDA $0213» загружает младший байт дополнения в аккумулятор.

Код операции для «ADC $0215», т.е. 6D. 16 для АЦП (абсолютная адресация) находится в байтовой позиции $0204. Младший байт сложения, равный 10010101, находится в байтовой позиции $0215. Адрес «$0215» «ADC $0215» находится в байтовых ячейках $0205 и $0206. Команда «ADC $0215» добавляет младший байт слагаемого к младшему байту дополнения, которое уже находится в аккумуляторе. Результат помещается обратно в аккумулятор. Любой перенос после восьмого бита отправляется во флаг переноса регистра состояния. Ячейку флага переноса нельзя очищать до второго добавления старших байтов. Этот перенос автоматически добавляется к сумме старших байтов. Фактически, перенос 0 автоматически добавляется к сумме младших байтов в начале (что эквивалентно отсутствию добавления переноса) из-за CLC.

Комментарий занимает следующие 48 10 = 30 16 байты. Однако это остается только в текстовом файле «.asm». Это не доходит до памяти. Удаляется трансляцией, которую делает ассемблер (программа).

Для следующей инструкции «STA $0217» код операции STA равен 8D. 16 (абсолютная адресация) находится в байтовой позиции $0207. Адрес «$0217» для «STA $0217» находится в ячейках памяти $0208 и $0209. Инструкция «STA $0217» копирует восьмибитное содержимое аккумулятора в ячейку памяти $0217.

Старший байт дополнения (00101010) находится в ячейке памяти $0214, а старший байт сложения (00101010) находится в ячейке памяти $02. 16 . Код операции для «LDA $0214», то есть AD16 для LDA (абсолютная адресация), находится в байтовой позиции $020A. Адрес «$0214» «LDA $0214» находится в местоположениях $020B и $020C. Инструкция «LDA $0214» загружает старший байт дополнения в аккумулятор, стирая все, что находится в аккумуляторе.

Код операции для «ADC $0216» — 6D. 16 для АЦП (абсолютная адресация) находится в байтовой позиции $020D. Адрес «$0216» «ADC 0216» находится в байтовых позициях $020E и $020F. Команда «ADC $0216» добавляет старший байт слагаемого к старшему байту дополнения, которое уже находится в аккумуляторе. Результат помещается обратно в аккумулятор. Если имеется перенос 1, то для второго сложения он автоматически помещается в ячейку переноса регистра состояния. Хотя перенос за пределы шестнадцатого бита (слева) для этой проблемы не требуется, полезно проверить, произошел ли перенос 1, проверив, стал ли флаг переноса равным 1.

Для следующей и последней инструкции «STA $0218» код операции STA 8D16 (абсолютная адресация) находится в байтовой позиции $0210. Адрес «$0218» для «STA $0218» находится в ячейках памяти $0211 и $0212. Команда «STA $0218» копирует восьмибитное содержимое аккумулятора в ячейку памяти $0218. Результатом сложения двух шестнадцатибитных чисел является 0101010101010100, где младший байт 01010100 находится в ячейке памяти $0217, а старший байт 01010101 в ячейке памяти $0218 — небольшой порядок байтов.

Вычитание
В 6502 µP числа со знаком представляют собой числа, дополняемые до двух. Дополнение до двух может быть восьмибитным, шестнадцатибитным или любым, кратным восьми битам. При дополнении до двух первый бит слева является знаковым битом. Для положительного числа этот первый бит равен 0, что указывает на знак. Остальные биты формируют число обычным способом. Чтобы получить дополнение до двух отрицательного числа, инвертируйте все биты соответствующего положительного числа, а затем добавьте 1 к результату с правого конца.

Чтобы вычесть одно положительное число из другого положительного числа, вычитаемое преобразуется в отрицательное число, дополняемое до двух. Затем уменьшаемое и новое отрицательное число добавляются обычным способом. Итак, восьмибитное вычитание становится:

Где перенос предполагается равным 1. Результатом в аккумуляторе является разница в дополнении до двух. Итак, чтобы вычесть два числа, должен быть установлен флаг переноса (приведенный к 1).

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

Программирование вычитания восьмибитных или шестнадцатибитных чисел выполняется аналогично программированию сложения. Однако флаг переноса должен быть установлен в самом начале. Мнемоника для этого:

Вычитание шестнадцатибитных положительных чисел
Рассмотрим вычитание со следующими числами:

Это вычитание не требует дополнения до двух. Поскольку вычитание в 6502 мкП производится в дополнении до двух, вычитание по основанию два выполняется следующим образом:

Результат дополнения двух аналогичен результату, полученному при обычном вычитании. Однако обратите внимание, что 1, которая идет в семнадцатой битовой позиции справа, игнорируется. Исключаемое и вычитаемое разбиваются на две восьмерки каждая. Двоичное дополнение 10010110 младшего байта вычитаемого определяется независимо от его старшего байта и любого переноса. Дополнение до двух старшего байта вычитаемого 11101011 определяется независимо от его младшего байта и любого переноса.

16 бит уменьшаемого числа уже находятся в дополнении до двух, начиная с 0 слева. Таким образом, никаких корректировок в битах не требуется. В 6502 мкП младший байт уменьшаемого числа без каких-либо изменений добавляется к младшему байту дополнения до двух вычитаемого. Младший байт сокращаемого числа не преобразуется в дополнение до двух, поскольку шестнадцать бит всего уменьшаемого числа уже должны быть в дополнении до двух (с 0 в качестве первого бита слева). В этом первом добавлении добавляется обязательный перенос 1 из-за инструкции 1=0 SEC.

В текущем эффективном вычитании происходит перенос 1 (сложения) с восьмого бита на девятый бит (справа). Поскольку это фактически вычитание, любой бит, который должен находиться во флаге переноса в регистре состояния, дополняется (инвертируется). Таким образом, перенос 1 становится 0 во флаге C. Во второй операции старший байт уменьшаемого числа добавляется к старшему двоичному байту вычитаемого. Автоматически дополняемый бит флага переноса регистра состояния (в данном случае равен 0) также добавляется (к старшим байтам). Любая единица, выходящая за пределы шестнадцатого бита справа, игнорируется.

Следующее — просто закодировать всю эту схему следующим образом:

SEC
ЛДА $0213
СБК $0215
; нет очистки, поскольку требуется инвертированное значение флага переноса
СТА $0217
ЛДА $0214
СБК $0216
СТА $0218

Помните, что в языке ассемблера 6502 точка с запятой начинает комментарий, который не включается в переведенную версию программы в памяти. Два 16-битных числа для вычитания занимают четыре байта памяти с абсолютной адресацией; по два на число (память представляет собой последовательность байтов). Эти вводы осуществляются не с клавиатуры. Результат суммирования составляет два байта и тоже должен быть помещен в память в другое место. Этот вывод не поступает на монитор или принтер; оно уходит в память. Это дает в общей сложности 6 10 = 6 16 байты для ввода и вывода, которые будут помещены в память (ОЗУ).

Прежде чем программа будет выполнена, она должна сначала находиться в памяти. Глядя на код программы, видно, что инструкции без комментария составляют 19 10 = 13 16 байты. Поскольку все программы в этой главе начинаются с ячейки памяти $0200, программа переходит из байтовой ячейки $0200 в память в байтовую ячейку $0200 + $13 – $1 = $0212 (начиная с $0200, а не $0201). Этот диапазон не включает область для входных и выходных байтов. Два входных числа занимают 4 байта, а одно выходное число — 2 байта. Добавление 6 байтов для входных и выходных чисел дает диапазон для программы, который заканчивается на $0212 + $6 = $0218. Общая продолжительность программы – 19 16 = 25 10 .

Младший байт уменьшаемого числа должен находиться в адресе $0213, а старший байт того же уменьшаемого числа должен находиться в адресе $0214 — небольшой порядок байтов. Аналогично, младший байт вычитаемого должен находиться в адресе $0215, а старший байт того же вычитаемого должен находиться в адресе $0216 – небольшой порядок байтов. Младший байт результата (разница) должен находиться в адресе $0217, а старший байт того же результата должен находиться в адресе $0218 — небольшой порядок байтов.

Код операции 38 16 для SEC (подразумеваемая адресация) находится в адресе $0200. Предполагается, что все программы в этой главе запускаются с адреса $0200, аннулируя любую программу, которая могла там находиться; если не указано иное. Код операции для «LDA $0213», т. е. AD. 16 , для LDA (абсолютная адресация) находится в позиции байта $0201. Младший байт уменьшаемого числа, равный 10111111, находится в ячейке памяти $0213. Помните, что каждый код операции занимает один байт. Адрес «$0213» «LDA $0213» находится в байтовых ячейках $0202 и $0203. Инструкция «LDA $0213» загружает младший байт уменьшаемого значения в аккумулятор.

Код операции для «SBC $0215», т.е. ED 16 , для SBC (абсолютная адресация) находится в байтовой позиции $0204. Младший байт вычитаемого, который равен 01101010, находится в позиции байта $0215. Адрес «$0215» «ADC $0215» находится в байтовых ячейках $0205 и $0206. Команда «SBC $0215» вычитает младший байт вычитаемого из младшего байта уменьшаемого, который уже находится в аккумуляторе. Это вычитание дополнения до двух. Результат помещается обратно в аккумулятор. Дополнение (инверсия) любого переноса после восьмого бита отправляется во флаг переноса регистра состояния. Этот флаг переноса не должен быть очищен перед вторым вычитанием старших байтов. Этот перенос автоматически добавляется к вычитанию старших байтов.

Комментарий занимает следующие 57 10 = 3916 16 байты. Однако это остается только в текстовом файле «.asm». Это не доходит до памяти. Удаляется трансляцией, которую делает ассемблер (программа).

Для следующей инструкции «STA $0217» код операции STA, т. е. 8D. 16 (абсолютная адресация) находится в байтовой позиции $0207. Адрес «$0217» для «STA $0217» находится в ячейках памяти $0208 и $0209. Инструкция «STA $0217» копирует восьмибитное содержимое аккумулятора в ячейку памяти $0217.

Старший байт уменьшаемого числа, 00101010, находится в ячейке памяти $0214, а старший байт вычитаемого, 00010101, находится в ячейке памяти $0216. Код операции для «LDA $0214», т. е. AD. 16 для LDA (абсолютная адресация) находится в байтовой позиции $020A. Адрес «$0214» «LDA $0214» находится в местоположениях $020B и $020C. Инструкция «LDA $0214» загружает старший байт уменьшаемого значения в аккумулятор, стирая все, что находится в аккумуляторе.

Код операции для «SBC $0216», т.е. ED 16 для SBC (абсолютная адресация) находится в байтовой позиции $020D. Адрес «$0216» «SBC $0216» находится в байтовых ячейках $020E и $020F. Инструкция «SBC $0216» вычитает старший байт вычитаемого из старшего байта уменьшаемого (дополнения до двух), который уже находится в аккумуляторе. Результат помещается обратно в аккумулятор. Если для этого второго вычитания имеется перенос 1, его дополнение автоматически помещается в ячейку переноса регистра состояния. Хотя для этой проблемы перенос за пределы шестнадцатого бита (слева) не требуется, полезно проверить, происходит ли дополнительный перенос, проверив флаг переноса.

Для следующей и последней инструкции «STA $0218» код операции STA, т. е. 8D. 16 (абсолютная адресация), находится в байтовой позиции $0210. Адрес «$0218» для «STA $0218» находится в ячейках памяти $0211 и $0212. Команда «STA $0218» копирует восьмибитное содержимое аккумулятора в ячейку памяти $0218. Результатом вычитания двух шестнадцатибитных чисел является 0001010101010101 с младшим байтом 01010101 в ячейке памяти $0217 и старшим байтом 00010101 в ячейке памяти $0218 – небольшой порядок байтов.

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

4.4 Логические операции

В 6502 µP мнемосхемой для OR является ORA, а для исключающего OR — EOR. Обратите внимание, что логические операции не имеют подразумеваемой адресации. Подразумеваемая адресация не принимает операндов. Каждый из логических операторов должен принимать два операнда. Первый находится в аккумуляторе, а второй — в памяти или в инструкции. Результат (8 бит) возвращается в аккумулятор. Первый в аккумуляторе либо помещается туда по непосредственной команде, либо копируется из памяти с абсолютной адресацией. В этом разделе для иллюстрации используется только адресация нулевой страницы. Все эти логические операторы являются побитовыми операторами.

И
В следующей таблице показано побитовое И в двоичном, шестнадцатеричном и десятичном формате:

Все программы в этой главе должны начинаться с адреса $0200. Однако программы в этом разделе находятся на нулевой странице с целью проиллюстрировать использование нулевой страницы без старшего байта 00000000. 2 . Предыдущий оператор AND может быть закодирован следующим образом:

LDA #$9A ; не по памяти – немедленная адресация
И #$CD ; не по памяти – немедленная адресация
СТА 30 долларов США; хранит 88 долларов США по цене 0030 долларов США, начиная с нуля

ИЛИ
В следующей таблице показано побитовое ИЛИ в двоичном, шестнадцатеричном и десятичном формате:

LDA #$9A ; не по памяти – немедленная адресация
ОРА #$CD ; не по памяти – немедленная адресация
СТА 30 долларов США; хранит $CF по адресу $0030, начинающемуся с нуля.

БЕСПЛАТНО
В следующей таблице показано побитовое исключающее ИЛИ в двоичном, шестнадцатеричном и десятичном формате:

LDA #$9A ; не по памяти – немедленная адресация
ЭОР #$CD ; не по памяти – немедленная адресация
СТА 30 долларов США; хранит 57 долларов США по цене 0030 долларов США, отсчитываемой от нуля

4.5 Операции сдвига и поворота

Мнемоника и коды операций для операторов сдвига и вращения:

ASL: сдвиг влево на один бит аккумулятора или ячейки памяти, вставляя 0 в освободившуюся крайнюю правую ячейку.

LSR: сдвиг вправо на один бит аккумулятора или ячейки памяти, вставляя 0 в освободившуюся крайнюю левую ячейку.
ROL: поворот на один бит влево от аккумулятора или ячейки памяти, вставляя выпавший слева бит в освободившуюся крайнюю правую ячейку.
ROR: повернуть на один бит вправо от аккумулятора или ячейки памяти, вставив выпавший справа бит в освободившуюся крайнюю левую ячейку.

Чтобы выполнить сдвиг или вращение с помощью аккумулятора, инструкция выглядит примерно так:

ЛСР А

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

Чтобы выполнить сдвиг или вращение байтовой ячейки памяти, инструкция выглядит примерно так:

РОР $2BCD

Где 2BCD — это ячейка памяти.

Обратите внимание, что не существует режима немедленной или подразумеваемой адресации для смещения или ротации. Не существует режима немедленной адресации, поскольку нет смысла сдвигать или вращать число, которое остается только в инструкции. Подразумеваемого режима адресации не существует, поскольку разработчики 6502 µP хотят, чтобы смещалось или вращалось только содержимое аккумулятора (регистр A) или ячейка байта памяти.

4.6 Режим относительной адресации

Микропроцессор всегда увеличивает (на 1, 2 или 3 единицы) счетчик программ (ПК), чтобы указать на следующую команду, которая должна быть выполнена. В 6502 µP есть инструкция, мнемоника которой — BVS, что означает переход при переполнении. ПК состоит из двух байтов. Эта инструкция заставляет ПК иметь другой адрес памяти для выполнения следующей инструкции, не являющейся результатом обычного приращения. Это делается путем добавления или вычитания значения, называемого смещением, к содержимому ПК. Итак, компьютер затем указывает на другую (разветвленную) ячейку памяти, чтобы компьютер мог продолжить выполнение оттуда. Смещение представляет собой целое число от -128. 10 до +127 10 (дополнение до двух). Таким образом, смещение может ускорить переход в памяти. Если оно положительное или отстающее в памяти, или если оно отрицательное.

Инструкция BVS принимает только один операнд — смещение. BVS использует относительную адресацию. Рассмотрим следующую инструкцию:

БВС 7 франков

Во второй базе, 7F. ЧАС 01111111 2 = 127 10 . Предположим, что содержимое ПК для следующей инструкции составляет $0300. Инструкция BVS приводит к прибавлению $7F (положительное число, уже в дополнении до двух) к $0300, что дает $037F. Таким образом, вместо следующей инструкции, которая должна выполняться в ячейке памяти $0300, она находится в ячейке памяти $037F (разница примерно в половину страницы).

Существуют и другие инструкции ветвления, но BVS очень хорошо подходит для иллюстрации относительной адресации. Относительная адресация имеет дело с инструкциями перехода.

4.7 Индексированная адресация и косвенная адресация отдельно

Эти режимы адресации позволяют 6502 µP обрабатывать огромные объемы данных за короткие промежутки времени с меньшим количеством инструкций. Для всей памяти Comodore-64 имеются ячейки размером 64 КБ. Таким образом, для доступа к любой ячейке 16-битного байта необходимы два байта. Единственным исключением из необходимости двух байтов является нулевая страница, где старший байт $00 опускается для экономии места, занимаемого инструкцией в памяти. В режиме адресации без нулевой страницы как старшие, так и младшие байты 16-битного адреса памяти в основном каким-то образом обозначаются.

Базовая индексированная адресация

Абсолютная индексная адресация
Помните, что регистр X или Y называется индексным регистром. Рассмотрим следующую инструкцию:

ЛДА $C453,X

Предположим, что значение 6 ЧАС находится в регистре X. Обратите внимание, что цифра 6 нигде в инструкции не прописана. Эта инструкция добавляет значение 6H к C453. ЧАС который является частью напечатанной инструкции в текстовом файле, который еще предстоит ассемблировать – C453 ЧАС + 6 ЧАС = С459 ЧАС . LDA означает загрузку байта в аккумулятор. Байт, который нужно загрузить в аккумулятор, поступает по адресу $C459. $C459, представляющий собой сумму $C453, введенную с помощью инструкции, и 6 ЧАС который находится в регистре X, становится эффективным адресом, с которого поступает байт, подлежащий загрузке в аккумулятор. Если 6 ЧАС находился в регистре Y, в инструкции вместо X вводится Y.

В операторе типизированной инструкции $C453 известен как базовый адрес, а номер 6 — ЧАС в регистре X или Y называется счетной или индексной частью эффективного адреса. Базовый адрес может относиться к любому адресу байта в памяти, а следующие 256 10 Доступ к адресам возможен при условии, что начальный индекс (или счетчик) в регистре X или Y равен 0. Помните, что один байт может давать непрерывный диапазон до 256. 10 числа (например, 00000000 2 на номер 11111111 2 ).

Таким образом, абсолютная адресация добавляет все, что уже помещено (поставлено другой инструкцией) в регистр X или Y, к 16 адресам, которые набираются с помощью инструкции для получения эффективного адреса. В типизированной инструкции два индексных регистра различаются буквами X или Y, которые вводятся после запятой. Вводится либо X, либо Y; не оба.

После того, как вся программа набрана в текстовом редакторе и сохранена с именем файла с расширением «.asm», ассемблер, который является другой программой, должен преобразовать набранную программу в то, что (загружено) в памяти. Предыдущая инструкция «LDA $C453,X» занимает в памяти три байта, а не пять.

Помните, что мнемоника, такая как LDA, может иметь более одного кода операции (разные байты). Код операции для инструкции, использующей регистр X, отличается от кода операции, использующей регистр Y. Ассемблер знает, какой код операции использовать, на основе типизированной инструкции. Однобайтовый код операции для «LDA $C453,X» отличается от однобайтового кода операции для «LDA $C453,Y». Фактически, код операции для LDA в «LDA $C453,X» — BD, а код операции для LDA в «LDA $C453,9» — BD.

Если код операции для LDA находится в байтовой позиции $0200. Затем 16-битный адрес $C453 занимает следующие байты в памяти, а именно $0201 и $0202. Конкретный байт кода операции указывает, задействован ли регистр X или регистр Y. Итак, ассемблированная языковая инструкция «LDA $C453,X» или «LDA $C453,Y» занимает в памяти три последовательных байта, а не четыре или пять.

Индексированная адресация с нулевой страницей
Адресация индекса нулевой страницы аналогична адресации абсолютного индекса, описанной ранее, но целевой байт должен находиться только на нулевой странице (от $0000 до $00FF). Теперь, когда мы имеем дело с нулевой страницей, старший байт, который всегда равен 00, ЧАС для ячеек памяти обычно избегают. Итак, обычно упоминается, что нулевая страница начинается с $00 до FF. Итак, предыдущая инструкция «LDA $C453,X» такая:

LDA $53.X

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

Когда значение, введенное в инструкции, добавляется к значению в индексном регистре, сумма не должна давать результат выше нуля страницы (FF ЧАС ). Таким образом, не может быть и речи о наличии инструкции типа «LDA $FF, X» и значения типа FF. ЧАС в индексном регистре, потому что FF ЧАС + ФФ ЧАС = 200 ЧАС который является расположением первого байта ($0200) страницы 2 (третьей страницы) в памяти, находится на большом расстоянии от страницы 0. Таким образом, при индексированной адресации с нулевой страницей эффективный адрес должен находиться на нулевой странице.

Косвенная адресация

Перейти к абсолютной адресации
Прежде чем обсуждать абсолютную косвенную адресацию, полезно сначала взглянуть на абсолютную адресацию JMP. Предположим, что адрес, имеющий интересующее значение (целевой байт), составляет 8765 долларов. Это 16-битный формат, состоящий из двух байтов: старший байт равен 87. ЧАС и младший байт, который равен 65 ЧАС . Итак, два байта по $8765 помещаются в ПК (счетчик программ) для следующей инструкции. В программе (файле) на языке ассемблера набирается следующее:

JMP $8765

Выполняемая программа в памяти переходит с любого адреса, к которому она обращалась, на $8765. Мнемоника JMP имеет три кода операций: 4C, 6C и 7C. Код операции для этой абсолютной адресации — 4C. Код операции для абсолютной косвенной адресации JMP — 6C (см. следующие рисунки).

Абсолютная косвенная адресация
Используется только с инструкцией перехода (JMP). Предположим, что адрес, содержащий интересующий байт (целевой байт), равен $8765. Это 16-битный формат, состоящий из двух байтов: старший байт равен 87. ЧАС и младший байт, который равен 65 ЧАС . При абсолютной косвенной адресации эти два байта фактически располагаются в двух последовательных байтовых ячейках в другом месте памяти.

Предположим, что они расположены в ячейках памяти $0210 и $0211. Затем младший байт интересующего адреса, который равен 65 ЧАС находится в адресе $0210, а старший байт — 87. ЧАС находится по адресу $0211. Это означает, что интересующий младший байт памяти переходит к младшему последовательному адресу, а интересующий более высокий байт памяти переходит к более старшему последовательному адресу - небольшой порядок байтов.

16-битный адрес может относиться к двум последовательным адресам в памяти. В этом свете адрес $0210 относится к адресам $0210 и $0211. Пара адресов $0210 и $0211 содержит конечный адрес (16 бит по два байта) целевого байта с младшим байтом 65. ЧАС в $0210 и старшем байте 87 ЧАС в $0211. Итак, набранная инструкция перехода:

СПМ ($0210)

Мнемоника JMP имеет три кода операций: 4C, 6C и 7C. Код операции для абсолютной косвенной адресации — 6C. В текстовом файле набирается «JMP ($0210)». Из-за скобок ассемблер (транслятор) использует для JMP код операции 6C, а не 4C или 7C.

При абсолютной косвенной адресации фактически имеется три области памяти. Первая область может состоять из байтовых ячеек $0200, $0201 и $0202. Здесь содержатся три байта для инструкции «JMP ($0210)». Вторая область, которая не обязательно находится рядом с первой, состоит из двух последовательных байтовых ячеек $0210 и $0211. Здесь находится младший байт ($0210), который набирается в инструкции программы на языке ассемблера. Если интересующий адрес равен $8765, младший байт 65 ЧАС находится в позиции байта $0210, а старший байт 87 ЧАС находится в байтовой позиции $0211. Третий регион состоит всего из одного байта. Это адрес $8765 для целевого байта (последний интересующий байт). Пара последовательных адресов, $0210 и $0211, содержит указатель $8765, который является интересующим адресом. После компьютерной интерпретации 8765 долларов поступают в ПК (счетчик программ) для доступа к целевому байту.

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

СПМ (50 долларов США)

Старший байт указателя находится в позиции $51 байт. Действующий адрес (указанный) не обязательно должен находиться на нулевой странице.

Таким образом, при индексной адресации значение индексного регистра добавляется к базовому адресу, указанному в инструкции, чтобы получить эффективный адрес. Косвенная адресация использует указатель.

4.8 Индексированная косвенная адресация

Абсолютная индексированная косвенная адресация
Этот режим адресации используется только с инструкцией JMP.
При абсолютной косвенной адресации имеется указанное значение (байт) со своими двумя последовательными байтовыми адресами. Эти два последовательных адреса формируют указатель, который находится в области указателя двух последовательных байтов в памяти. Младший байт области указателя — это то, что набирается в инструкции в скобках. Указатель — это адрес указанного значения. В предыдущей ситуации $8765 — это адрес указанной стоимости. $0210 (за которым следует $0211) — это адрес, содержимое которого составляет $8765, что является указателем. В режиме абсолютной косвенной адресации в программе (текстовом файле) вводится ($0210), включая круглые скобки.

С другой стороны, в режиме абсолютной индексированной косвенной адресации младший байт адреса для области указателя формируется путем добавления значения в регистре X к набранному адресу. Например, если указатель находится по адресу $0210, типизированная инструкция может выглядеть примерно так:

СПМ ($020A,X)

Где регистр X имеет значение 6 ЧАС . 020А ЧАС + 6 ЧАС = 0210 ЧАС . Регистр Y не используется в этом режиме адресации.

Косвенная адресация с индексацией нулевой страницы
В этом режиме адресации используется регистр X, а не регистр Y. В этом режиме адресации указанное значение и указатель по-прежнему находятся в его двухбайтовой области указателя адреса. На нулевой странице для указателя должно быть два последовательных байта. Адрес, который набирается в инструкции, представляет собой однобайтовый адрес. Это значение добавляется к значению в регистре X, и любой перенос отбрасывается. Результат указывает на область указателя на странице 0. Например, если интересующий адрес (указанный) равен $8765 и находится в байтовых ячейках $50 и $51 на странице 0, а значение в регистре X равно $30, типизированная инструкция выглядит примерно так:

LDA (20,X долларов США)

Потому что 20 + 30 = 50 долларов.

Косвенная индексированная адресация
В этом режиме адресации используется регистр Y, а не регистр X. В этом режиме адресации по-прежнему существуют указанное значение и область указателя, но содержимое области указателя работает по-другому. В нулевой странице для области указателя должно быть два последовательных байта. В инструкции набирается нижний адрес области указателя. Это число (пара байтов), содержащееся в области указателя, добавляется к значению в регистре Y, чтобы получить реальный указатель. Например, пусть интересующий адрес (указанный) равен $8765, значение 6H находится в регистре Y, а число (два байта) находится по адресу 50. ЧАС и 51 ЧАС . Два байта вместе составляют $875F, поскольку $875F + $6 = $8765. Типизированная инструкция выглядит примерно так:

LDA (50 долларов США), да

4.9 Инструкции увеличения, уменьшения и тестовых битов

В следующей таблице показаны операции инструкций увеличения и уменьшения:

INA и DEA увеличивают и уменьшают аккумулятор соответственно. Это называется адресацией аккумулятора. INX, DEX, INY и DEY относятся к регистрам X и Y соответственно. Они не принимают никаких операндов. Таким образом, они используют подразумеваемый режим адресации. Приращение означает добавление 1 к регистру или байту памяти. Декремент означает вычитание 1 из регистра или байта памяти.

INC и DEC увеличивают и уменьшают байт памяти соответственно (а не регистр). Использование адресации нулевой страницы вместо абсолютной адресации позволяет сэкономить память для команды. Адресация нулевой страницы на один байт меньше абсолютной адресации инструкции в памяти. Однако режим адресации нулевой страницы влияет только на нулевую страницу.

Команда BIT проверяет биты байта в памяти с 8 битами в аккумуляторе, но не меняет ни одного. Установлены только некоторые флаги регистра состояния процессора «P». Биты указанной ячейки памяти логически соединяются с битами аккумулятора. Затем устанавливаются следующие биты состояния:

  • N, который представляет собой бит 7 и последний бит (слева) регистра состояния, получает бит 7 ячейки памяти перед операцией AND.
  • V, который является битом 6 регистра состояния, получает бит 6 ячейки памяти перед операцией AND.
  • Флаг Z регистра состояния устанавливается (становится равным 1), если результат операции И равен нулю (00000000 2 ). В противном случае оно очищается (становится равным 0).

4.10 Сравнение инструкций

Мнемоника команд сравнения для 6502 µP: CMP, CPX и CPY. После каждого сравнения затрагиваются флаги N, Z и C регистра состояния процессора «P». Флаг N устанавливается (становится равным 1), когда результатом является отрицательное число. Флаг Z устанавливается (становится равным 1), когда результат равен нулю (000000002). Флаг C устанавливается (становится равным 1), когда происходит перенос с восьмого на девятый бит. В следующей таблице представлена ​​подробная иллюстрация.

Означает «больше чем». При этом сравнительная таблица должна быть интуитивно понятна.

4.11 Инструкции перехода и ветвления

В следующей таблице приведены инструкции перехода и ветвления:

Инструкция JMP использует абсолютную и косвенную адресацию. Остальные инструкции в таблице являются инструкциями ветвления. Они используют только относительную адресацию с 6502 мкП. При этом таблица становится понятной, если ее читать слева направо и сверху вниз.

Обратите внимание, что ветви могут применяться только к адресам в пределах от -128 до +127 байт от данного адреса. Это относительная адресация. И для JMP, и для инструкций ветвления напрямую влияет счетчик программ (PC). 6502 µP не допускает переходов по абсолютному адресу, хотя переход может выполнять абсолютную адресацию. Инструкция JMP не является инструкцией ветвления.

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

4.12 Область стека

Подпрограмма похожа на одну из предыдущих коротких программ для сложения двух чисел или вычитания двух чисел. Область стека в памяти начинается от $0100 до $01FF включительно. Эта область называется просто стеком. Когда микропроцессор выполняет переход к инструкции подпрограммы (JSR – см. следующее обсуждение), ему необходимо знать, куда вернуться после завершения. 6502 µP хранит эту информацию (адрес возврата) в нижней памяти от $0100 до $01FF (область стека) и использует содержимое регистра указателя стека, которое в микропроцессоре имеет букву «S», в качестве указателя (9 бит) на последний возвращенный адрес. который хранится на странице 1 (от $0100 до $01FF) памяти. Стек увеличивается с $01FF и позволяет вкладывать подпрограммы глубиной до 128 уровней.

Другое использование указателя стека — обработка прерываний. У 6502 µP контакты обозначены как IRQ и NMI. На эти контакты могут быть поданы небольшие электрические сигналы, которые заставят 6502 мкП прекратить выполнение одной программы и начать выполнение другой. В этом случае первая программа прерывается. Как и подпрограммы, сегменты кода прерывания могут быть вложенными. Обработка прерываний обсуждается в следующей главе.

Примечание : Указатель стека имеет 8 бит для адреса младшего байта при адресации ячеек от $0100 до $01FF. Старший байт 00000001 2 предполагается.

В следующей таблице приведены инструкции, которые связывают указатель стека «S» с регистрами A, X, Y и P с областью стека в памяти:

4.13 Вызов и возврат подпрограммы

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

JSR: переход к подпрограмме

Инструкция для возврата из подпрограммы:

RTS: Возврат из подпрограммы

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

В отличие от JMP, JSR помещает адрес следующей за собой инструкции из ПК (счетчика программ) в стек. Позиция этого адреса в стеке помещается в указатель стека «S». Когда в подпрограмме встречается (выполняется) инструкция RTS, адрес, помещенный в стек, извлекается из стека, и программа возобновляет работу с этого извлеченного адреса, который является адресом следующей инструкции непосредственно перед вызовом подпрограммы. Последний адрес, удаленный из стека, отправляется в программный счетчик. В следующей таблице приведены технические подробности инструкций JSR и RTS:

На следующем рисунке показано использование JSR и RTS:

4.14 Пример цикла обратного отсчета

Следующая подпрограмма ведет обратный отсчет от $FF до $00 (всего 256 10 считается):

запустить LDX #$FF ; загрузить X с $FF = 255
цикл DEX ; Х = Х – 1
Петля БНЕ ; если X не ноль, то переходим к циклу
РТС; возвращаться

Каждая строка имеет комментарий. Комментарии никогда не попадают в память для выполнения. Ассемблер (транслятор), который преобразует программу в то, что она находится в памяти для выполнения (запуска), всегда удаляет комментарии. Комментарий начинается с «;» . «Начало» и «цикл» в этой программе называются метками. Метка идентифицирует (имя) адрес инструкции. Если инструкция представляет собой однобайтовую инструкцию (неявная адресация), метка является адресом этой инструкции. Если инструкция является многобайтовой, метка идентифицирует первый байт многобайтовой инструкции. Первая инструкция этой программы состоит из двух байтов. Предполагая, что он начинается с адреса $0300, адрес $0300 можно заменить в программе на «start». Вторая инструкция (DEX) представляет собой однобайтовую инструкцию и должна находиться по адресу $0302. Это означает, что адрес $0302 может быть заменен на «цикл» в программе, что на самом деле так и происходит в «цикле BNE».

«Петля BNE» означает переход по заданному адресу, когда флаг Z регистра состояния равен 0. Когда значение в регистре A, X или Y равно 00000000. 2 , из-за последней операции флаг Z равен 1 (установлен). Итак, пока он равен 0 (а не 1), вторая и третья инструкции в программе повторяются именно в таком порядке. В каждой повторяющейся последовательности значение (целое число) в регистре X уменьшается на 1. DEX означает X = X – 1. Когда значение в регистре X равно $00 = 00000000 2 , Z становится равным 1. В этот момент повторение двух инструкций больше не происходит. Последняя инструкция RTS в программе, которая представляет собой однобайтовую инструкцию (подразумеваемая адресация), возвращается из подпрограммы. Целью этой инструкции является создание адреса счетчика программ в стеке для кода, который должен быть выполнен перед вызовом подпрограммы, и возврат к счетчику программ (ПК). Этот адрес является адресом инструкции, которая должна быть выполнена перед вызовом подпрограммы.

Примечание: При написании программы на языке ассемблера для 6502 µP в начале строки должна начинаться только метка; любой другой код строки должен быть сдвинут как минимум на один пробел вправо.

Вызов подпрограммы
Игнорируя пространство памяти, занятое предыдущими метками, программа занимает 6 байт последовательных ячеек памяти (ОЗУ) от $0300 до $0305. В данном случае программа:

ЛДКС #$FF ; загрузить X с $FF = 255
ДЭКС ; Х = Х – 1
БНЕ $0302 ; если X не ноль, то переходим к циклу
РТС; возвращаться

Начиная с адреса $0200 в памяти может быть вызов подпрограммы. Инструкция по вызову:

запуск JSR; начало — это адрес $0300, т. е. JSR $0300.

Подпрограмма и ее вызов, которые правильно записаны в файле текстового редактора:

запустить LDX #$FF; загрузить X с $FF = 255
цикл DEX ; Х = Х – 1

Петля БНЕ ; если X не ноль, то переходим к циклу
РТС; возвращаться

Начало JSR: переход к программе, начиная с $0300.

Теперь в одной длинной программе может быть много подпрограмм. Все они не могут иметь название «старт». У них должны быть разные имена. На самом деле ни один из них не может иметь название «старт». «Старт» используется здесь в целях обучения.

4.15 Перевод программы

Перевод программы или ее ассемблирование означают одно и то же. Рассмотрим следующую программу:

запустить LDX #$FF : загрузить X с $FF = 255
цикл DEX: X = X – 1
Цикл BNE: если X не ноль, то перейти к циклу
РТС: возврат
Начало JSR: переход к программе, начиная с $0300.

Это программа, написанная ранее. Он состоит из подпрограммы, запуска и вызова подпрограммы. Программа отсчитывает от 255. 10 до 0 10 . Программа начинается с начального адреса пользователя $0200 (ОЗУ). Программа набирается в текстовом редакторе и сохраняется на диске. Он имеет имя типа «sample.asm», где «sample» — это имя по выбору программиста, но с именем файла должно быть связано расширение «.asm» для языка ассемблера.

Собранная программа создается другой программой, которая называется ассемблером. Ассемблер поставляется производителем 6502 µP или третьей стороной. Ассемблер воспроизводит программу таким образом, чтобы она находилась в памяти (ОЗУ) во время выполнения (запуска).

Предположим, что инструкция JSR начинается с адреса $0200, а подпрограмма начинается с адреса $0300. Ассемблер удаляет все комментарии и пробелы. Комментарии и пробелы тратят память, которой всегда не хватает. Возможная пустая строка между предыдущим сегментом кода подпрограммы и вызовом подпрограммы является примером пробела. Собранный файл по-прежнему сохраняется на диске и называется примерно так: «sample.exe». «Образец» — это имя по выбору программиста, но расширение «.exe» должно указывать на то, что это исполняемый файл.

Собранную программу можно задокументировать следующим образом:

Говорят, что создание такого документа производится вручную. Обратите внимание, что комментарии в этом документе не отображаются в памяти (для выполнения). Столбец адреса в таблице указывает начальные адреса инструкций в памяти. Обратите внимание, что «старт JSR», то есть «JSR $0300», который, как ожидается, будет закодирован как «20 03 00», на самом деле кодируется как «20 00 03», причем адрес младшего байта памяти занимает младший байт в памяти, а Адрес старшего байта памяти, принимающий старший байт в памяти – небольшой порядок байтов. Код операции для JSR — 20. 16 .

Обратите внимание, что смещение для команды ветвления, такой как BNE, представляет собой число с дополнением до двух в диапазоне 128. 10 до + 127 10 . Итак, «петля BNE» означает «BNE-1». 10 », что на самом деле является «D0 FF» в кодовой форме FF. 16 равен -1 в дополнении до двух, которое записывается как = 11111111 по основанию два. Программа на ассемблере заменяет метки и поля реальными шестнадцатеричными числами (шестнадцатеричные числа — это двоичные числа, сгруппированные в четыре бита). Фактически включены адреса, с которых начинается каждая инструкция.

Примечание: Инструкция «JSR start» заменяется более короткими инструкциями, которые отправляют текущее содержимое (старшие и младшие байты) счетчика программы в стек с указателем стека, который уменьшается два раза (один раз для старшего байта и один раз для младшего байта) и затем перезагружает компьютер с адресом $0300. Указатель стека теперь указывает на $00FD, если предположить, что он инициализирован как $01FF.

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

Примечание: Текст метки не должен содержать более 8 символов.

«Петля BNE» использует относительную адресацию. Это значит добавить -3 10 к следующему содержимому счетчика программы $0305. Байты для «цикла BNE» — это «D0 FD», где FD — это дополнение до двух чисел -3. 10 .

Примечание. В этой главе не представлены все инструкции для 6502 µP. Все инструкции и их подробности можно найти в документе под названием «Семейство 8-битных микропроцессоров SY6500». Для этого документа существует PDF-файл с названием «6502.pdf», который находится в свободном доступе в Интернете. 6502 мкП, описанный в этом документе, — это 65C02.

4.16 Прерывания

Сигналы любого устройства, подключенного к внешним (вертикальным) портам Commodore 64, должны пройти через схемы CIA 1 или CIA 2 (IC), прежде чем достичь микропроцессора 6502. Сигналы с шины данных 6502 µP должны пройти либо через чип CIA 1, либо через CIA 2, прежде чем достичь любого внешнего устройства. ЦРУ означает «Адаптер сложного интерфейса». На рис. 4.1 «Блок-схема материнской платы Commodore_64» блоки устройств ввода/вывода представляют собой CIA 1 и CIA 2. Когда программа выполняется, ее можно прервать для запуска какой-либо другой части кода, прежде чем продолжить. Существует аппаратное и программное прерывание. Для аппаратного прерывания на 6502 мкП имеются два входных сигнальных контакта. Названия этих контактов прерывание и НМИ . Это не линии передачи данных µP. Линии данных для µP: D7, D6, D5, D4, D3, D2, D1 и D0; с D0 для младшего бита и D7 для старшего бита.

прерывание означает «активный» низкий уровень запроса прерывания. Эта входная линия микропроцессора обычно имеет высокий уровень, примерно 5 В. Когда оно упадет примерно до 0 В, это будет запрос на прерывание, сигнализирующий микропроцессору. Как только запрос будет удовлетворен, на линии снова появится высокий уровень. Предоставление запроса на прерывание означает, что микропроцессор переходит к коду (подпрограмме), который обрабатывает прерывание.

НМИ означает «активный» низкий уровень немаскируемого прерывания. Хотя код для прерывание исполняется НМИ может опуститься низко. В этом случае, НМИ обрабатывается (выполняется собственный код). После этого код для прерывание продолжается. После кода для прерывание заканчивается, основной код программы продолжается. То есть, НМИ прерывает прерывание обработчик. Сигнал для НМИ может по-прежнему передаваться микропроцессору, даже когда микропроцессор простаивает, ничего не обрабатывает или не запускает основную программу.

Примечание: На самом деле это переход от высокого к низкому, НМИ , это НМИ сигнал – об этом позже. прерывание обычно исходит от ЦРУ 1 и НМИ обычно исходит от ЦРУ 2. НМИ , что означает немаскируемое прерывание, можно рассматривать как неостановимое прерывание.

Обработка прерываний
Является ли запрос от прерывание или НМИ , текущая инструкция должна завершиться. У 6502 есть только регистры A, X и Y. Во время работы подпрограммы она может использовать эти три регистра вместе. Обработчик прерываний по-прежнему является подпрограммой, хотя и не рассматривается как таковая. После завершения текущей инструкции содержимое регистров A, X и Y микропроцессора 65C02 сохраняется в стеке. Адрес следующей инструкции счетчика программ также отправляется в стек. Затем µP переходит к коду прерывания. После этого содержимое регистров A, X и Y восстанавливается из стека в порядке, обратном отправке.

Пример кода прерывания
Для простоты предположим, что процедура для µP прерывание Прерывание состоит в том, чтобы просто сложить числа $01 и $02 и сохранить результат $03 по адресу памяти $0400. Код:

ИСР ФА
ПХХ
ФИЗИЧЕСКИЙ
;
LDA #$01
АЦП #$02
ОНИ СТОЯТ 0400$
;
ПЛИ
ПЛХ
НОАК
РТИ

ISR — это метка, идентифицирующая адрес памяти, в которой находится инструкция PHA. ISR означает процедуру обслуживания прерываний. PHA, PHX и PHY отправляют содержимое регистров A, X и Y в стек в надежде, что они понадобятся любому коду (программе), который выполняется непосредственно перед прерыванием. Следующие три инструкции составляют ядро ​​обработчика прерываний. Инструкции PLY, PLX и PLA должны быть именно в этом порядке, и они возвращают содержимое регистров Y, X и A. Последняя инструкция, RTI (без операнда), возвращает продолжение выполнения любого кода (программы), который выполнялся до прерывания. RTI извлекает адрес следующей инструкции исполняемого кода из стека обратно в программный счетчик. RTI означает возврат из прерывания. На этом обработка прерывания (подпрограммы) завершена.

Программное прерывание
Основным способом создания программного прерывания для 6502 µP является использование команды подразумеваемого адреса BRK. Предположим, что основная программа запущена и встречает инструкцию BRK. С этого момента адрес следующей инструкции на ПК должен быть отправлен в стек по мере завершения текущей инструкции. Подпрограмму для обработки инструкций программного обеспечения следует называть «следующей». Эта подпрограмма прерывания должна поместить содержимое регистров A, X и Y в стек. После выполнения ядра подпрограммы содержимое регистров A, X и Y должно быть возвращено из стека в свои регистры завершающей подпрограммой. Последний оператор в программе — RTI. Содержимое ПК также автоматически возвращается из стека на ПК из-за RTI.

Сравнение и противопоставление подпрограммы и процедуры обслуживания прерываний
В следующей таблице сравниваются и противопоставляются подпрограмма и процедура обслуживания прерываний:

4.17 Обзор основных режимов адресации 6502

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

Режим немедленной адресации
В режиме непосредственной адресации после операнда указывается значение, а не адрес памяти. Перед значением должен стоять #. Если значение шестнадцатеричное, за «#» должен следовать «$». Инструкции непосредственной адресации для 65C02: ADC, AND, BIT, CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA, SBC. Читателю следует обратиться к документации по 65C02 µP, чтобы узнать, как использовать перечисленные здесь инструкции, которые не объяснены в этой главе. Пример инструкции:

LDA #$77

Режим абсолютной адресации
В режиме абсолютной адресации имеется один операнд. Этот операнд представляет собой адрес значения в памяти (обычно в шестнадцатеричном формате или в виде метки). Есть 64 тыс. 10 = 65 536 10 адреса памяти для 6502 мкП. Обычно однобайтовое значение находится по одному из этих адресов. Инструкции абсолютной адресации для 65C02: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA. , СТХ, СТЙ, СТЗ, ТРБ, БСЭ. Читателю следует обратиться к документации 65C02 µP, чтобы узнать, как использовать инструкции, перечисленные здесь, а также остальные режимы адресации, которые не объяснены в этой главе. Пример инструкции:

ОНИ СТОЯТ $1234

Неявный режим адресации
В режиме подразумеваемой адресации операнд отсутствует. Любой задействованный регистр µP подразумевается инструкцией. Подразумеваемые инструкции адресации для 65C02: BRK, CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, PHA, PHP, PHX, PHY, PLA, PLP, PLX, PLY, RTI, RTS, SEC. , SED, SEI, TAX, TAY, TSX, TXA, TXS, TYA. Пример инструкции:

DEX: Уменьшите регистр X на одну единицу.

Режим относительной адресации
Режим относительной адресации касается только инструкций перехода. В режиме относительной адресации имеется только один операнд. Это значение от -128 10 до +127 10 . Это значение называется смещением. В зависимости от знака это значение добавляется или вычитается из следующей инструкции счетчика программ, в результате чего получается адрес предполагаемой следующей инструкции. Инструкции режима относительного адреса: BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC, BVS. Примеры инструкций:

BNE $7F : (перейти, если Z = 0 в регистре состояния, P)

При этом к текущему счетчику программы (адресу выполнения) добавляется 127 и начинается выполнение инструкции по этому адресу. Сходным образом:

BEQ $F9 : (перейти, если Z = : в регистре состояния, P)

При этом к счетчику текущей программы добавляется -7 и начинается выполнение по новому адресу счетчика программы. Операнд представляет собой число, дополняемое до двух.

Абсолютная индексированная адресация
При абсолютной индексной адресации содержимое регистра X или Y добавляется к заданному абсолютному адресу (от $0000 до $FFFF, т.е. от 0). 10 на 65536 10 ), чтобы иметь реальный адрес. Этот заданный абсолютный адрес называется базовым адресом. Если используется регистр X, инструкция ассемблера выглядит примерно так:

ЛДА $C453,X

Если используется регистр Y, это примерно так:

ЛДА $C453,Y

Значение регистра X или Y называется значением счетчика или индекса и может составлять от $00 (0 10 ) до $FF (250 10 ). Это не называется смещением.

Инструкции абсолютной индексной адресации: ADC, AND, ASL (только X), BIT (с аккумулятором и памятью, только с X), CMP, DEC (только память и X), EOR, INC (только память и X), LDA. , LDX, LDY, LSR (только X), ORA, ROL (только X), ROR (только X), SBC, STA, STZ (только X).

Абсолютная косвенная адресация
Используется только с инструкцией перехода. При этом данный абсолютный адрес имеет адрес указателя. Адрес указателя состоит из двух байтов. Двухбайтовый указатель указывает (является адресом) значения байта назначения в памяти. Итак, инструкция на языке ассемблера:

JMP (3456 долларов США)

В скобках $13 находится по адресу $3456, а $EB — по адресу $3457 (= $3456 + 1). Тогда адрес назначения будет равен $13EB, а $13EB — это указатель. Абсолютные $3456 указаны в круглых скобках в инструкции, где 34 — младший байт, а 56 — старший байт.

4.18 Создание строки на языке ассемблера 6502 µP

Как показано в следующей главе, после создания файла в памяти его можно сохранить на диск. Файлу необходимо дать имя. Имя является примером строки. Есть много других примеров использования строк в программировании.

Существует два основных способа создания строки кодов ASCII. В обоих случаях все коды ASCII (символы) занимают в памяти последовательные байты. В одном из способов этой последовательности байтов предшествует целочисленный байт, который представляет собой длину (количество символов) в последовательности (строке). В другом случае за последовательностью символов следует (сразу за ней) нулевой байт, равный 00. 16 , то есть 00 долларов. По-другому длина строки (количество символов) не указывается. Нулевой символ не используется первым способом.

Например, рассмотрим фразу «Я люблю тебя!» строка без кавычек. Длина здесь равна 11; пробел считается одним байтом (символом) ASCII. Предположим, что строку необходимо поместить в память, причем первый символ должен находиться по адресу $0300.

В следующей таблице показаны настройки строковой памяти, когда первый байт равен 11. 10 = 0Б 16 :

В следующей таблице показаны настройки строковой памяти, когда первый байт равен «I», а последний байт равен нулю ($00):

Для начала создания строки можно использовать следующую инструкцию:

ОНИ СТОЯТ 0300$

Предположим, что первый байт находится в аккумуляторе, который должен быть отправлен по адресу $0300. Эта инструкция верна для обоих случаев (оба типа строк).

После размещения всех символов в ячейках памяти один за другим строку можно прочитать с помощью цикла. В первом случае считывается количество символов после длины. Во втором случае символы считываются от «I» до тех пор, пока не встретится нулевой символ, который равен «Null».

4.19 Создание массива с помощью ассемблера 6502 µP

Массив однобайтовых целых чисел состоит из последовательных ячеек памяти с целыми числами. Затем есть указатель, указывающий на местоположение первого целого числа. Итак, массив целых чисел состоит из двух частей: указателя и последовательности ячеек.

В массиве строк каждая строка может находиться в другом месте памяти. Затем есть последовательные ячейки памяти с указателями, где каждый указатель указывает на первую ячейку каждой строки. Указатель в этом случае состоит из двух байтов. Если строка начинается с ее длины, соответствующий указатель указывает на местоположение этой длины. Если строка не начинается с ее длины, а заканчивается нулевым символом, соответствующий указатель указывает на местоположение первого символа строки. И есть указатель, который указывает на младший байтовый адрес первого указателя из последовательных указателей. Итак, массив строк состоит из трех частей: строк в разных местах памяти, соответствующих последовательных указателей и указателя на первый указатель из последовательных указателей.

4.20 Проблемы

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

  1. Напишите программу на языке ассемблера, которая начинается с $0200 для 6502 µP и добавляет беззнаковые числа 2A94. ЧАС (добавить) к 2ABF ЧАС (авгенд). Пусть входы и выход находятся в памяти. Кроме того, вручную создайте собранный программный документ.
  2. Напишите программу на языке ассемблера, которая начинается с $0200 для 6502 µP и вычитает беззнаковые числа 1569. ЧАС (вычесть) из 2ABF ЧАС (уменьшаемое). Пусть входы и выходы будут в памяти. Кроме того, вручную создайте собранный программный документ.
  3. Напишите программу на языке ассемблера для 6502 µP, которая считает от $00 до $09 с помощью цикла. Программа должна начинаться с $0200. Кроме того, вручную создайте собранный программный документ.
  4. Напишите программу на ассемблере стоимостью от 0200 долларов США для 6502 µP. Программа имеет две подпрограммы. Первая подпрограмма добавляет беззнаковые числа 0203. ЧАС (дополнение) и 0102H (добавление). Вторая подпрограмма добавляет сумму из первой подпрограммы (0305H) к 0006. ЧАС (авгенд). Конечный результат сохраняется в памяти. Вызовите первую подпрограмму FSTSUB и вторую подпрограмму SECSUB. Пусть входы и выходы будут в памяти. Кроме того, вручную создайте собранный программный документ для всей программы.
  5. Учитывая, что прерывание обработчик добавляет от $02 до $01 в аккумуляторе в качестве основной обработки, в то время как НМИ выдается и основная обработка для НМИ добавляет от $05 до $04 в аккумуляторе, напишите ассемблер для обоих обработчиков, включая их вызовы. Звонок в прерывание обработчик должен находиться по адресу $0200. прерывание обработчик должен начинаться с адреса $0300. НМИ обработчик должен начинаться с адреса $0400. Результат прерывание обработчик должен быть помещен по адресу $0500, а результат НМИ обработчик должен быть помещен по адресу $0501.
  6. Кратко объясните, как инструкция BRK используется для создания программного прерывания в компьютере 65C02.
  7. Создайте таблицу, в которой сравниваются и противопоставляются обычная подпрограмма и процедура обработки прерываний.
  8. Кратко объясните основные режимы адресации 65C02 µP на примерах инструкций на языке ассемблера.
  9. а) Напишите программу на машинном языке 6502, которая бы выводила фразу «Я люблю тебя!» строка кодов ASCII в памяти, начиная с адреса $0300 и длины строки. Программа должна запускаться по адресу $0200. Получите каждый символ из аккумулятора по одному, предполагая, что они отправлены туда, с помощью некоторой подпрограммы. Также соберите программу вручную. (Если вам нужно знать коды ASCII для «Я люблю тебя!». Вот они: «Я»:49 16 , мест : 20 16 , 'л': 6С 16 , 'о':6F 16 , 'в':76 16 , 'е':65, 'у':79 16 , 'в':75 16 и «!»:21 16 (Примечание: каждый код занимает 1 байт).
    б) Напишите программу на машинном языке 6502, которая бы выводила фразу «Я люблю тебя!» строка кодов ASCII в памяти, начиная с адреса $0300 без длины строки, но заканчивая 00 16 . Программа должна запускаться по адресу $0200. Получите каждый символ из аккумулятора, предполагая, что они отправляются туда один за другим некоторой подпрограммой. Также соберите программу вручную.