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

Glava 4 Samoucitel Za Ezik Za Asemblirane Na Mikroprocesor 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 µP. Наборът от инструкции на 6502 µP е почти всички инструкции на 6510 µP. Знанието за тази и следващата глава се основава на компютъра commodore_64. Тези знания се използват като основа за обяснение на съвременните компютърни архитектури и модерни операционни системи в тази част от онлайн курса за кариера.





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

Компютърът commodore_64 се смята за компютър с 8-битова компютърна дума. Това означава, че информацията се съхранява, прехвърля и манипулира под формата на осем-битови двоични кодове.



Блокова схема на дънната платка Commodore 64
Блоковата схема на дънната платка commodore 64 е:


Фигура 4.1 Блокова диаграма на системния модул Commodore_64

Представете си микропроцесора 6510 като микропроцесора 6502. Общата памет е поредица от байтове (8 бита на байт). Има памет с произволен достъп (четене/запис), в която байтовете могат да се записват или изтриват. Когато захранването на компютъра бъде изключено, цялата информация в паметта с произволен достъп (RAM) се изтрива. Има и памет само за четене (ROM). При изключване на захранването на компютъра информацията в ROM паметта остава (не се изтрива).

Има входно/изходен порт (верига), който на диаграмата се нарича входно/изходни устройства. Този порт не трябва да се бърка с портовете, които се виждат на лявата и дясната или предната и задната вертикални повърхности на системния модул на компютъра. Това са две различни неща. Връзките от този вътрешен порт към периферните устройства като твърдия диск (или флопи диска), клавиатурата и монитора не са показани на диаграмата.

В диаграмата има три шини (групи електрически много малки проводници). Всеки проводник може да прехвърли бит 1 или бит 0. Шината за данни за прехвърляне на осем бита байт наведнъж (един тактов импулс) към RAM и входно/изходния порт (входно/изходни устройства) е двупосочна. Шината за данни е осем бита широка.

Всички компоненти са свързани към адресната шина. Адресната шина е еднопосочна от микропроцесора. Има шестнадесет проводника за адресната шина и всеки носи един бит (1 или 0). Шестнадесет бита се изпращат в един тактов импулс.

Там е контролната шина. Някои от проводниците на управляващата шина биха прехвърлили по един бит от микропроцесора към другите компоненти. Няколко контролни линии пренасят битовете от входно/изходния (IO) порт към микропроцесора.

Компютърна памет
RAM и ROM се считат за един модул памет. Тази група е представена схематично, както следва, където шестнадесетичните числа имат префикса „$“:


Фигура 4.11 Оформление на паметта за компютъра Commodore 64

RAM е от 0000 16 към DFFF 16 което се записва като от $0000 до $DFFF. С асемблерния език 6502 µP шестнадесетичното число е с префикс “$” и не е с суфикс (подписан) с 16 или H или шестнадесетичен. Цялата информация в RAM изчезва, когато компютърът е изключен. ROM започва от $E000 до $FFFF. Има подпрограми, които не се изключват, когато компютърът е изключен. Тези подпрограми са често използвани процедури, които помагат при програмирането. Потребителската програма ги извиква (вижте следващата глава).

Пространството (байтове) от $0200 до $D000 е за потребителските програми. Мястото от $D000 до $DFFF е за информация, която е пряко свързана с периферните устройства (устройства за вход/изход). Това е част от операционната система. И така, операционната система на компютъра commodore-64 се състои от две основни части: частта в ROM, която никога не се изключва, и частта от $D000 до $DFFF, която се изключва при изключване на захранването. Тези IO (входно-изходни) данни трябва да се зареждат от диск при всяко включване на компютъра. Днес такива данни се наричат ​​периферни драйвери. Периферните устройства започват от порта за входно/изходно устройство през връзките на дънната платка до разпознаваемите портове на вертикалните повърхности на компютъра, към които са свързани мониторът, клавиатурата и т.н., и към самите периферни устройства (монитор, клавиатура и т.н. .).

Паметта се състои от 2 16 = 65 536 байта местоположения. В шестнадесетичен вид това са 10 000 16 = 10 000 з = 10 000 шестнадесетичен = $10 000 местоположения. В компютрите броенето при основа две, основа десет, основа шестнадесет и т.н. започва от 0, а не от 1. Така че първото местоположение всъщност е числото на местоположението 0000000000000000 2 = 0 10 = 0000 16 = $0000. В асемблерния език 6502 µP идентифицирането на местоположението на адреса е с префикс $ и няма суфикс или долен индекс. Последното местоположение е номерът на местоположение 1111111111111111 2 = 65 535 10 = FFFF 16 = $FFFF, а не 10000000000000000 2 или 65 536 10 , или 10000 16 , или $10 000. 10000000000000000 2 , 65,536 10 , 10 000 16 , или $10 000 дава общия брой местоположения на байтове.

Тук, 2 16 = 65 536 = 64 x 1024 = 64 x 2 10 = 64 Кбайта (Килобайта). Суфиксът от 64 в името Commodore-64 означава 64KB обща памет (RAM и ROM). Един байт е 8 бита и 8-те бита ще отидат в едно място за байт в паметта.

Паметта от 64 Kbytes е разделена на страници. Всяка страница има 0100 16 = 256 10 местоположения на байтове. Първите 256 10 = първи 0100 16 locations е страница 0. Втората е страница 1, третата е страница 2 и т.н.

За да се адресират 65 536 местоположения, са необходими 16 бита за всяко местоположение (адрес). И така, адресната шина от микропроцесора към паметта се състои от 16 линии; един ред за един бит. Битът е или 1, или 0.

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


Фиг. 4.12 6502 µP регистри

Програмният брояч или PC може да се види като 16-битов регистър на диаграмата. По-малките осем бита са обозначени като PCL за нисък програмен брояч. Осемте по-високи значими бита са обозначени като PCH за висок програмен брояч. Една инструкция в паметта за Commodore-64 може да се състои от един, два или три байта. 16-те бита в компютъра сочат към следващата инструкция, която трябва да бъде изпълнена, в паметта. Сред схемите в микропроцесора две от тях се наричат ​​аритметично логическо устройство и декодер на инструкции. Ако текущата инструкция, която се обработва в µP (микропроцесора) е дълга един байт, тези две вериги увеличават PC за следващата инструкция с 1 единица. Ако текущата инструкция, която се обработва в µP, е дълга два байта, което означава, че заема два последователни байта в паметта, тези две вериги увеличават компютъра за следващата инструкция с 2 единици. Ако текущата инструкция, която се обработва в µP, е дълга три байта, което означава, че заема три последователни байта в паметта, тези две вериги увеличават компютъра за следващата инструкция с 3 единици.

Акумулаторът 'A' е осембитов регистър с общо предназначение, който съхранява резултата от повечето аритметични и логически операции.

Всеки от регистрите “X” и “Y” се използва за преброяване на стъпките на програмата. Броенето в програмирането започва от 0. Затова те се наричат ​​индексни регистри. Те имат няколко други цели.

Въпреки че регистърът на указателя на стека, 'S' има 9 бита, което се счита за осем-битов регистър. Съдържанието му сочи към местоположение на байт в страница 1 на паметта с произволен достъп (RAM). Страница 1 започва от байт $0100 (256 10 ) до байт $01FF (511 10 ). Когато една програма работи, тя преминава от една инструкция към следващата последователна инструкция в паметта. Това обаче не винаги е така. Има моменти, когато прескача от една област на паметта в друга област на паметта, за да продължи да изпълнява инструкциите там последователно. Страница 1 в RAM се използва като стек. Стекът е голяма област на RAM паметта, която има следващите адреси за продължение на кода, откъдето има скок. Кодовете с инструкции за прескачане не са в стека; те са другаде в паметта. Въпреки това, след като инструкциите за прескачане се изпълнят, адресите за продължение (не кодови сегменти) са в стека. Те са били бутнати там в резултат на инструкции за скок или разклоняване.

Осембитовият регистър за състоянието на процесора на P е специален вид регистър. Отделните битове не са свързани или свързани един с друг. Всеки бит там се нарича флаг и се оценява независимо от останалите. Значенията на флаговете са дадени по-долу, ако възникне необходимост.

Първият и последният битов индекс за всеки регистър са посочени над всеки регистър в предишната диаграма. Броенето на битовия индекс (позиция) в регистъра започва от 0 вдясно.

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

Всяка страница има 1 000 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 а не AE 16 което е равно на 10101110 2 .

В таблицата всички байтове под заглавията на режима на адресиране се наричат ​​Операционни кодове, което е съкратено като кодове на операции. Може да има повече от един код за операция за една мнемоника, в зависимост от режима на адресиране.

Забележка: Думата „зареждане“ в компютърната системна единица може да има две значения: може да се отнася до зареждането на файл от диск в паметта на компютъра или може да се отнася до прехвърлянето на байт от място на байт в паметта към микропроцесорен регистър .

Има повече режими на адресиране от четирите в таблицата за 6502 µP.

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

Памет М и Акумулатор А

Памет към акумулатор

Незабавно адресиране
Следващата инструкция съхранява числото 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. Това е малък endianness, който се използва от асемблерния език 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, която би погълнала байт от общата памет от 64K, спестява пространството в паметта.

Акумулатор към паметта

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

ТЕ СА $1444

Твърди се, че това се прехвърля от акумулатора към паметта. Не се зарежда. Зареждането е обратното. Байтът на кода на операцията за STA е 8D 16 = 10001101 2 . Тази инструкция се състои от три последователни байта в паметта. 8D 16 е на място $0200. 44-те 16 от $1444 адреса е в $0201 местоположение. и 14 16 е в местоположението $0202 – малко endianity. Действителният байт, който се копира, не е част от инструкцията. 8D, а не 85 за адресиране на нулева страница (в таблицата) се използват тук за STA.

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

STA 0050 $

Байтът на кода на операцията за STA тук е 85 16 = 10000101 2 . Тази инструкция се състои от два последователни байта в паметта. 85-те 16 е на място $0200. 50-те 16 от $0050 адрес е в местоположение $0201. Въпросът за endianness не възниква тук, защото адресът има само един байт, който е по-малкият байт. Действителният байт, който се копира, не е част от инструкцията. Тук за STA се използват 85, а не 8D за адресиране на нулева страница.

Няма смисъл да се използва незабавно адресиране за прехвърляне на байт от акумулатора към място в паметта. Това е така, защото действителната стойност като $FF трябва да бъде цитирана в инструкцията при незабавно адресиране. Така че незабавното адресиране не е възможно за прехвърляне на байтова стойност от регистър в µP към което и да е място в паметта.

Мнемоники 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, инструкцията е:

TX

За да копирате байта от A до Y, инструкцията е:

РЪКА

За да копирате байта от Y в A, инструкцията е:

TYA

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

Указателят на стека „S“ е 9-битов регистър в 6502 µP. Първият бит (най-ляво) винаги е 1. Всички адреси на местоположението на байтове в страница първа започват с 1, последвано от 8 различни бита за 256 10 местоположения. Указателят на стека има адреса на местоположението в страница 1, което има адреса на следващата инструкция, която програмата трябва да върне и да продължи след изпълнение на текущия (прескочен) кодов сегмент. Тъй като първият бит от всички адреси на стека (първа страница) започва с 1, регистърът на указателя на стека трябва да съдържа само останалите осем бита. В крайна сметка неговият първи бит, който е най-левият бит (деветият бит, броен от дясно), винаги е 1.

За да копирате байта от S в X, инструкцията е:

TSX

За да копирате байта от X в S, инструкцията е:

текст

Инструкциите от регистър към регистър не приемат никакъв операнд. Те се състоят само от мнемоника. Всяка мнемоника има свой код за операция в шестнадесетичен формат. Това е в режим на имплицитно адресиране, защото няма операнд (няма адрес на паметта, няма стойност).

Забележка: Няма прехвърляне (копиране) от X към Y или Y към X.

4.3 Аритметични операции

Веригата, аритметична логическа единица в 6502 µP, може да добавя само две осем-битови числа наведнъж. Не изважда, не умножава и не дели. Следващата таблица показва операционните кодове и режимите на адресиране за аритметични операции:

Забележка: Всички мнемоники за аритметични операции и други типове операции (т.е. всички 6502 мнемоники) вземат един байт код на операция (op). Ако има повече от един режим на адресиране за мнемониката, ще има различни кодове за операция за една и съща мнемоника: по един за режим на адресиране. C, D и V в таблицата са флаговете на регистъра на състоянието. Техните значения ще бъдат дадени по-късно, когато възникне необходимост.

Събиране на числа без знак
При 6502 µP числата със знак са числа, допълващи две. Числата без знак са обикновени положителни числа, които започват от нула. И така, за байт от осем бита, най-малкото число без знак е 00000000 2 = 0 10 = 00 16 а най-голямото число без знак е 11111111 2 = 255 10 = FF 16 . За две неподписани числа събирането е:

A+M+C→A

Това означава, че 8-битовото съдържание на акумулатора се добавя от аритметично-логическото устройство към байт (8-бита) от паметта. След добавянето на A и M, пренасянето към деветия бит отива в клетката с флаг за пренасяне в регистъра на състоянието. Всеки предишен бит за пренос от предишно добавяне, който все още е в клетката с флаг за пренос в регистъра на състоянието, също се добавя към сумата от A и M, което прави A+M+C→A. Резултатът се поставя обратно в акумулатора.

Ако добавянето на лихвата е:

A + M

И няма нужда да добавяте предишно пренасяне, флагът за пренасяне трябва да бъде изчистен, което се прави 0, така че добавянето е:

A+M+0→A същото като A+M→A

Забележка: Ако M се добави към A, се получава пренасяне на 1, защото резултатът е по-голям от 255 10 = 11111111 2 = FF 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 = FF 16 . Така че няма резултатно пренасяне на 1. Казано по друг начин, полученото пренасяне е 0. Преди добавянето няма предишно пренасяне на 1. С други думи, предишното пренасяне е 0. Кодът за извършване на това добавяне може да бъде:

CLC
LDA#$3F
ADC #$15

Забележка: Докато въвеждате асемблерния език, в края на всяка инструкция се натиска клавишът 'Enter' на клавиатурата. В този код има три инструкции. Първата инструкция (CLC) изчиства флага за пренасяне в случай, че предишно добавяне има 1. CLC може да се извърши само в режим на имплицитно адресиране. Мнемониката за имплицитния режим на адресиране не приема операнд. Това изчиства клетката за пренасяне от регистъра на състоянието на P. Изчистването означава даване на бит 0 на клетката с флаг за пренасяне. Следващите две инструкции в кода използват режима на незабавно адресиране. При незабавно адресиране има само един операнд за мнемониката, който е число (а не адрес на паметта или регистъра). И така, числото трябва да бъде предшествано от „#“. „$“ означава, че числото, което следва, е шестнадесетично.

Втората инструкция зарежда числото 3F 16 в акумулатора. За третата инструкция веригата на аритметичната логическа единица на µP взема предишното (изчистено) пренасяне на 0 (принудително към 0) от клетката с флаг за пренасяне от регистъра на състоянието и го добавя към 15 16 както и към стойността, която вече е в 3F 16 акумулатор и поставя пълния резултат обратно в акумулатора. В този случай има резултатно пренасяне от 0. ALU (Аритметична логическа единица) изпраща (поставя) 0 в клетката с флаг за пренасяне на регистъра на състоянието. Регистърът на състоянието на процесора и регистърът на състоянието означават едно и също нещо. Ако се получи пренасяне на 1, ALU изпраща 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 = 2A95 16 = 10 901 10 . Сумата е 0101010101010100 2 = 5554 16 = 21 844 10 .

Добавянето на тези две числа без знак към основа две е както следва:

Следващата таблица показва същото добавяне с пренасяне на 1 от осмия бит до деветия бит, започвайки отдясно:

При кодирането това първо се добавят двата по-ниски байта. След това ALU (аритметична логическа единица) изпраща пренасянето на 1 от позицията на осмия бит до позицията на деветия бит, към клетката с флаг за пренасяне в регистъра на състоянието. Резултатът от 0 1 0 1 0 1 0 0 без пренасяне отива в акумулатора. След това втората двойка байтове се добавя с пренасянето. Мнемониката ADC означава автоматично добавяне с предишното пренасяне. В този случай предишното пренасяне, което е 1, не трябва да се променя преди второто добавяне. За първото добавяне, тъй като всяко предишно пренасяне не е част от това пълно добавяне, то трябва да бъде изчистено (направено 0).

За пълното събиране на двете двойки байтове, първото добавяне е:

A + M + 0 -> A

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

A + M + 1 -> A

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

CLC
LDA $0213
ADC $0215
; няма изчистване, защото е необходима стойността на флага за пренасяне
STA $0217
LDA $0214
ADC $0216
STA $0218

Обърнете внимание, че при асемблерния език 6502 коментарът започва с точка и запетая. Това означава, че при изпълнението на програмата точката и запетаята и всичко отдясно се игнорира. Програмата, която е написана преди това, е в текстов файл и се записва с името по избор на програмиста и с разширението „.asm“. Предишната програма не е точната програма, която отива в паметта за изпълнение. Съответната програма в паметта се нарича преведена програма, където мнемониките се заменят с кодовете за операции (байтове). Всички коментари остават в текстовия файл на асемблерния език и се премахват, преди преведената програма да достигне паметта. Всъщност има два файла, които се записват на диска днес: файлът „.asm“ и файлът „.exe“. Файлът „.asm“ е този в предишната илюстрация. Файлът „.exe“ е файлът „.asm“ с премахнати всички коментари и всички мнемоники, заменени от техните кодове за операции. Когато се отвори в текстов редактор, файлът „.exe“ е неразпознаваем. Освен ако не е посочено друго, за целите на тази глава файлът „.exe“ се копира в паметта, започвайки от местоположението $0200. Това е другото значение на зареждането.

Двете 16-битови числа, които трябва да се добавят, заемат четири байта в паметта за абсолютно адресиране: два байта на число (паметта е поредица от байтове). При абсолютно адресиране операндът към кода на операцията е в паметта. Резултатът от сумирането е широк два байта и също трябва да бъде поставен в паметта. Това дава общо 6 10 = 6 16 байтове за входове и изходи. Входовете не са от клавиатурата и изходът не е от монитора или принтера. В тази ситуация входовете са в паметта (RAM), а изходът (резултатът от сумирането) се връща в паметта (RAM).

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

По-малкият байт на augend трябва да бъде в адреса $0213, а по-високият байт на същия augend трябва да бъде в адреса $0214 – малко endianness. По същия начин, по-малкият байт на добавката трябва да бъде в адреса $0215, а по-високият байт на същата добавка трябва да бъде в адреса $0216 – малко endianness. По-малкият байт от резултата (сумата) трябва да бъде в адреса $0217, а по-високият байт от същия резултат трябва да бъде в адреса $0218 – малко endianness.

Операционният код 18 16 за CLC (имплицитно адресиране) е в местоположението на байта от $0200. Операционният код за „LDA $0213“, т.е. AD 16 за LDA (абсолютно адресиране), е в местоположението на байта $0201. Долният байт на augend, който е 10111111, е в местоположението на байта на паметта на $0213. Не забравяйте, че всеки операционен код заема един байт. Адресът “$0213” на “LDA $0213” е в местоположенията на байтовете на $0202 и $0203. Инструкцията “LDA $0213” зарежда долния байт на augen в акумулатора.

Операционният код за „ADC $0215“, т.е. 6D 16 за ADC (абсолютно адресиране), е в местоположението на байта $0204. Долният байт на добавката, който е 10010101, е в местоположението на байта $0215. Адресът “$0215” на “ADC $0215” е в местоположенията на байтовете на $0205 и $0206. Инструкцията “ADC $0215” добавя долния байт на addend към долния байт на augend, който вече е в акумулатора. Резултатът се поставя обратно в акумулатора. Всяко пренасяне след осмия бит се изпраща към флага за пренасяне на регистъра на състоянието. Клетката с флаг за пренасяне не трябва да се изчиства преди второто добавяне на по-високите байтове. Това пренасяне се добавя автоматично към сумата от по-високите байтове. Всъщност пренасяне от 0 се добавя автоматично към сумата от по-ниските байтове в началото (еквивалентно на липса на добавяне на пренасяне) поради CLC.

Коментарът отнема следващите 48 10 = 30 16 байтове. Това обаче остава само в текстовия файл „.asm“. Не достига до паметта. Премахва се чрез превода, който се извършва от асемблера (програма).

За следващата инструкция, която е „STA $0217“, кодът на операцията на STA е 8D 16 (абсолютно адресиране) е в местоположението на байта $0207. Адресът „$0217“ на „STA $0217“ е в местоположенията на паметта на $0208 и $0209. Инструкцията “STA $0217” копира осембитовото съдържание на акумулатора в местоположението на паметта $0217.

По-големият байт на augend, който е 00101010, е в местоположението на паметта $0214, а по-високият байт на добавката, който е 00101010, е в местоположението на байта на $02 16 . Операционният код за “LDA $0214”, който е AD16 за LDA (абсолютно адресиране), е в местоположението на байта $020A. Адресът „$0214“ на „LDA $0214“ е в местоположенията на $020B и $020C. Инструкцията “LDA $0214” зарежда по-високия байт от augen в акумулатора, изтривайки всичко, което е в акумулатора.

Операционният код за „ADC $0216“, който е 6D 16 за ADC (абсолютно адресиране) е в местоположението на байта $020D. Адресът „$0216“ на „ADC 0216“ е в местоположенията на байтовете на $020E и $020F. Инструкцията “ADC $0216” добавя по-високия байт на addend към по-високия байт на augend, който вече е в акумулатора. Резултатът се поставя обратно в акумулатора. Ако има пренасяне на 1, за това второ добавяне, то автоматично се поставя в клетката за пренасяне на регистъра на състоянието. Въпреки че пренасянето след шестнадесетия бит (вляво) не е необходимо за този проблем, хубаво е да проверите дали е възникнало пренасяне на 1, като проверите дали флагът за пренасяне е станал 1.

За следващата и последна инструкция, която е “STA $0218”, кодът на операцията на STA, който е 8D16 (абсолютно адресиране), е в местоположението на байта $0210. Адресът “$0218” на “STA $0218” е в местоположенията на паметта на $0211 и $0212. Инструкцията “STA $0218” копира осембитовото съдържание на акумулатора в местоположението на паметта $0218. Резултатът от събирането на двете шестнадесет-битови числа е 0101010101010100, с по-малък байт от 01010100 в местоположението на паметта на $0217 и по-високия байт на 01010101 в местоположението на паметта на $0218 – малко endianness.

Изваждане
При 6502 µP числата със знак са числа, допълващи две. Допълнителното число на две може да бъде осем бита, шестнадесет бита или всяко кратно на осем бита. С допълнение от две, първият бит отляво е знаковият бит. За положително число този първи бит е 0, за да посочи знака. Останалите битове формират числото по нормалния начин. За да получите двойното допълнение на отрицателно число, обърнете всички битове за съответното положително число и след това добавете 1 към резултата от десния край.

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

Където пренасянето се приема за 1. Резултатът в акумулатора е разликата в допълнението на две. И така, за да извадите две числа, флагът за пренасяне трябва да бъде зададен (направен на 1).

При изваждане на две шестнадесетбитови числа, изваждането се извършва два пъти, както при събирането на две шестнадесетбитови числа. Тъй като изваждането е форма на събиране с 6502 µP, когато се изваждат две шестнадесет-битови числа, флагът за пренасяне се задава само веднъж за първото изваждане. За второто изваждане всяка настройка на флага за пренасяне се извършва автоматично.

Програмирането на изваждането за осембитови числа или шестнадесетбитови числа се извършва подобно на програмирането на събирането. Въпреки това флагът за пренасяне трябва да бъде зададен в самото начало. Мнемониката за това е:

Изваждане с шестнадесетбитови положителни числа
Помислете за изваждане със следните числа:

Това изваждане не включва допълнение на две. Тъй като изваждането в 6502 µP се извършва в допълнение от две, изваждането в основа две се извършва, както следва:

Резултатът от допълването на двете е същият като резултата, който се получава от обикновеното изваждане. Имайте предвид обаче, че 1, който отива на седемнадесетата битова позиция отдясно, се игнорира. Умаляваното и субтрахенда се разделят на две осми бита всеки. Допълнението на двата от 10010110 от долния байт на субтрахенда се определя независимо от неговия по-висок байт и от всяко пренасяне. Допълнението на двата от 11101011 от по-високия байт на субтрахенда се определя независимо от неговия по-нисък байт и от всяко пренасяне.

16-битата на умаляваното вече са в допълнение от две, започвайки с 0 отляво. Така че не се нуждае от корекция в битове. С 6502 µP долният байт на умаляваното без никаква модификация се добавя към долния байт на допълнението на двете на субтрахенда. Долният байт на умаленото не се преобразува в допълнение на две, тъй като шестнадесетте бита на цялото умалено трябва вече да са в допълнение на две (с 0 като първи бит вляво). В това първо добавяне се добавя задължително пренасяне на 1 поради инструкцията 1=0 SEC.

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

Следващото нещо е просто да кодирате цялата тази схема, както следва:

SEC
LDA $0213
SBC $0215
; няма изчистване, защото е необходима стойността на обърнатия флаг за пренасяне
STA $0217
LDA $0214
SBC $0216
STA $0218

Не забравяйте, че при асемблерния език 6502 точка и запетая започва коментар, който не е включен в преведената версия на програмата в паметта. Двете 16-битови числа за изваждане заемат четири байта памет с абсолютно адресиране; две на число (паметта е поредица от байтове). Тези входове не са от клавиатурата. Резултатът от сумирането е два байта и също трябва да бъде поставен в паметта на различно място. Този изход не отива към монитора или принтера; отива в паметта. Това дава общо 6 10 = 6 16 байтове за входове и изходи, които да бъдат поставени в паметта (RAM).

Преди да се изпълни една програма, тя трябва първо да бъде в паметта. При разглеждане на програмния код се вижда, че инструкциите без коментар са 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 – малко endianness. По-малкият байт от резултата (разликата) трябва да бъде в адреса $0217, а по-високият байт от същия резултат трябва да бъде в адреса $0218 – малко endianness.

Операционният код на 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 – малко endianness.

6502 µP има схема само за добавяне и косвено за изваждане на комплемента на двете. Той няма схема за умножение и деление. За да се извърши умножението и делението, трябва да се напише програма на асемблер с подробности, включително преместване на частични продукти и частични дивиденти.

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

В 6502 µP мнемониката за ИЛИ е ORA, а мнемониката за изключително ИЛИ е EOR. Забележете, че логическите операции нямат подразбиращо се адресиране. Подразбиращото се адресиране не приема операнд. Всеки от логическите оператори трябва да приема два операнда. Първият е в акумулатора, а вторият е в паметта или в инструкцията. Резултатът (8 бита) се връща в акумулатора. Първият в акумулатора или се поставя там чрез незабавна инструкция, или се копира от паметта с абсолютно адресиране. В този раздел за илюстрация се използва само адресирането на нулева страница. Всички тези логически оператори са побитови оператори.

И
Следната таблица илюстрира побитово И в двоичен, шестнадесетичен и десетичен:

Всички програми в тази глава трябва да стартират от местоположението на байта в паметта от $0200. Програмите в този раздел обаче са на нулева страница, с цел да се илюстрира използването на нулева страница без по-високия байт от 00000000 2 . Предишното И може да бъде кодирано по следния начин:

LDA #$9A ; не по памет – незабавно адресиране
И #$CD ; не по памет – незабавно адресиране
STA $30; съхранява $88 на нулева база $0030

ИЛИ
Следната таблица илюстрира побитово ИЛИ в двоичен, шестнадесетичен и десетичен:

LDA #$9A ; не по памет – незабавно адресиране
ORA #$CD ; не по памет – незабавно адресиране
STA $30; съхранява $CF на нулева база $0030

БЕЗПЛАТНО
Следващата таблица илюстрира побитово XOR в двоичен, шестнадесетичен и десетичен:

LDA #$9A ; не по памет – незабавно адресиране
EOR #$CD ; не по памет – незабавно адресиране
STA $30; съхранява $57 на нулева база $0030

4.5 Операции за преместване и завъртане

Мнемониката и кодовете за операции за операторите за преместване и завъртане са:

ASL: Преместване наляво с един бит от акумулатор или място в паметта, като вмъкнете 0 в освободената най-дясна клетка.

LSR: Преместване надясно с един бит на акумулатор или място в паметта, вмъквайки 0 в освободената най-лява клетка.
ROL: Завъртете един бит наляво от мястото на акумулатора или паметта, като вмъкнете бита, който е изпуснат отляво, в освободената най-дясна клетка.
ROR: Завъртете един бит вдясно от мястото на акумулатора или паметта, като вмъкнете бита, който е изпуснат вдясно, в освободената най-лява клетка.

За да направите смяна или ротация с акумулатора, инструкцията е нещо подобно:

ЛСР А

Това използва друг режим на адресиране, наречен акумулаторен режим на адресиране.

За да извършите преместване или завъртане с място в паметта на байт, инструкцията е нещо подобно:

ROR $2BCD

Където 2BCD е местоположението на паметта.

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

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

Микропроцесорът винаги увеличава (с 1, 2 или 3 единици) програмния брояч (PC), за да посочи следващата инструкция, която трябва да бъде изпълнена. 6502 µP има инструкция, чиято мнемоника е BVS, което означава разклоняване при набор за препълване. Компютърът се състои от два байта. Тази инструкция кара компютъра да има различен адрес на паметта, за да бъде изпълнена следващата инструкция, която не е резултат от нормално нарастване. Това става чрез добавяне или изваждане на стойност, наречена отместване, към съдържанието на компютъра. И така, след това компютърът посочва различно (разклонено) място в паметта, за да може компютърът да продължи да изпълнява от там. Отместването е цяло число от -128 10 до +127 10 (допълнение на две). Така че отместването може да направи скока напред в паметта. Ако е положителен или изостанал в паметта, или ако е отрицателен.

BVS инструкцията приема само един операнд, който е отместването. BVS използва относително адресиране. Обърнете внимание на следната инструкция:

BVS $7F

В основа две, 7F з е 01111111 2 = 127 10 . Да приемем, че съдържанието в компютъра за следващата инструкция е $0300. BVS инструкцията кара $7F (положително число, което вече е в допълнение от две) да бъдат добавени към $0300, за да се получат $037F. Така че, вместо следващата инструкция да бъде изпълнена в местоположението на паметта от $0300, тя е в местоположението в паметта на $037F (приблизително половин страница разлика).

Има и други инструкции за разклоняване, но BVS е много добър за използване за илюстриране на относителното адресиране. Относителното адресиране се занимава с инструкции за разклонения.

4.7 Индексирано адресиране и непряко адресиране поотделно

Тези режими на адресиране позволяват на 6502 µP да обработва огромните количества данни за кратки периоди от време с намален брой инструкции. Има 64KB места за цялата памет на Comodore-64. И така, за достъп до произволно място на байт, от 16 бита, са необходими два байта. Единственото изключение от необходимостта от два байта е за нулева страница, където по-високият байт от $00 е пропуснат, за да се спести пространството, което се заема от инструкцията в паметта. При режим на адресиране без страница-нула, както по-високите, така и по-малките байтове на 16-битовия адрес на паметта са предимно посочени по някакъв начин.

Основно индексирано адресиране

Абсолютно индексно адресиране
Не забравяйте, че регистърът X или Y се нарича индексен регистър. Обърнете внимание на следната инструкция:

LDA $C453, X

Да приемем, че стойността на 6 з е в регистър X. Имайте предвид, че 6 не е въведено никъде в инструкцията. Тази инструкция добавя стойността на 6H към C453 з което е част от въведената инструкция в текстовия файл, който все още предстои да се сглоби – C453 з + 6 з = C459 з . LDA означава зареждане на байт в акумулатора. Байтът, който трябва да бъде зареден в акумулатора, идва от адреса $C459. $C459, което е сумата от $C453, въведена с инструкцията и 6 з който се намира в регистъра X, става ефективният адрес, от който идва байтът, който ще бъде зареден в акумулатора. Ако 6 з беше в регистъра Y, Y се въвежда на мястото на X в инструкцията.

Във въведената инструкция $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 з + 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. И така, въведената инструкция за прескачане е:

JMP ($0210)

JMP мнемониката има три кода за операции, които са 4C, 6C и 7C. Операционният код за абсолютно индиректно адресиране е 6C. Това, което е въведено в текстовия файл, е „JMP ($0210)“. Поради скобите асемблерът (преводачът) използва кода на операцията 6C за JMP, а не 4C или 7C.

При абсолютно непряко адресиране всъщност има три области на паметта. Първият регион може да се състои от байтови местоположения на $0200, $0201 и $0202. Това съдържа трите байта за инструкцията „JMP ($0210)“. Вторият регион, който не е непременно до първия, се състои от две последователни байтови местоположения на $0210 и $0211. Това е долният байт тук ($0210), който се въвежда в програмната инструкция на асемблерния език. Ако адресът, който представлява интерес, е $8765, долният байт от 65 з е в местоположението на байта $0210 и по-високия байт от 87 з е в $0211 байтово местоположение. Третият регион се състои само от местоположение на един байт. Той е с адрес $8765 за целевия байт (крайният интересен байт). Двойката последователни адреси, $0210 и $0211, съдържа указателя $8765, който е адресът, който представлява интерес. След изчислителната интерпретация $8765 отиват в компютъра (програмен брояч) за достъп до целевия байт.

Индиректно адресиране на нулева страница
Това адресиране е същото като абсолютното индиректно адресиране, но указателят трябва да е в страница нула. Адресът на долния байт на областта на указателя е това, което е във въведената инструкция, както следва:

JMP ($50)

По-високият байт на показалеца е в местоположението на $51 байта. Ефективният адрес (посочен) не трябва да е в страница нула.

И така, при индексно адресиране, стойността в индексен регистър се добавя към основния адрес, който е даден в инструкцията, за да има ефективния адрес. Непрякото адресиране използва указател.

4.8 Индексирано индиректно адресиране

Абсолютно индексирано индиректно адресиране
Този режим на адресиране се използва само с JMP инструкцията.
При абсолютно непряко адресиране има указаната стойност (байт) със собствени два последователни байтови адреса. Тези два последователни адреса формират указателя да бъде в областта на указателя на два последователни байта в паметта. Долният байт на областта на показалеца е това, което е въведено в инструкцията в скоби. Указателят е адресът на посочената стойност. В предишната ситуация $8765 е адресът на посочената стойност. $0210 (последван от $0211) е адресът, чието съдържание е $8765, което е указателят. При режима на абсолютно непряко адресиране в програмата (текстовия файл) се въвежда ($0210), включително скобите.

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

JMP ($020A, X)

Където регистърът X има стойност 6 з . 020A з + 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), Y

4.9 Инструкции за увеличаване, намаляване и тестови BITs

Следната таблица показва операциите на инструкциите за увеличаване и намаляване:

INA и DEA съответно увеличават и намаляват акумулатора. Това се нарича адресиране на акумулатора. INX, DEX, INY и DEY са съответно за регистрите X и Y. Те не приемат никакъв операнд. Така че те използват имплицитния режим на адресиране. Увеличаването означава добавяне на 1 към регистъра или байта на паметта. Декремент означава изваждане на 1 от регистъра или байта от паметта.

INC и DEC увеличават и намаляват съответно байт памет (а не регистър). Използването на адресиране на нулева страница вместо абсолютно адресиране е за икономия на паметта за инструкцията. Адресирането на нулева страница е с един байт по-малко от абсолютното адресиране за инструкцията в паметта. Режимът на адресиране на нулева страница обаче засяга само нулевата страница.

Инструкцията BIT тества битовете на байт в паметта с 8-те бита в акумулатора, но не променя нито едното, нито другото. Зададени са само някои флагове на регистъра на състоянието на процесора „P“. Битовете на посоченото място в паметта са логически И с тези на акумулатора. След това се задават следните битове за състояние:

  • N, който е бит 7 и последният бит (вляво) от регистъра на състоянието, получава бит 7 от местоположението на паметта преди ANDing.
  • V, който е бит 6 от регистъра на състоянието, получава бит 6 от местоположението на паметта преди ANDing.
  • Флагът 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 µP. С това таблицата става разбираема, ако се чете отляво надясно и отгоре надолу.

Имайте предвид, че разклоненията могат да се прилагат само към адреси в рамките на -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 µP да спре да изпълнява една програма и да го накара да започне да изпълнява друга. В този случай първата програма се прекъсва. Подобно на подпрограмите, сегментите на кода за прекъсване могат да бъдат вложени. Обработката на прекъсване се обсъжда в следващата глава.

Забележка : Указателят на стека има 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; X = X – 1
BNE контур; ако X не е нула, тогава отидете в цикъл
RTS ; връщане

Всеки ред има коментар. Коментарите никога не влизат в паметта за изпълнение. Асемблерът (транслаторът), който преобразува програма в това, което е в паметта за изпълнение (изпълнение), винаги премахва коментарите. Коментарът започва с „;“ . „Старт“ и „цикъл“ в тази програма се наричат ​​етикети. Етикетът идентифицира (името) за адреса на инструкцията. Ако инструкцията е еднобайтова инструкция (подразбиращо се адресиране), етикетът е адресът на тази инструкция. Ако инструкцията е многобайтова инструкция, етикетът идентифицира първия байт за многобайтовата инструкция. Първата инструкция за тази програма се състои от два байта. Ако приемем, че започва от адрес $0300, адресът $0300 може да бъде заменен с „старт“ надолу в програмата. Втората инструкция (DEX) е еднобайтова инструкция и трябва да бъде на адрес $0302. Това означава, че адресът $0302 може да бъде заменен с „loop“ надолу в програмата, което всъщност е така в „BNE loop“.

„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 инструкция в програмата, която е еднобайтова инструкция (подразбиращо се адресиране), се връща от подпрограмата. Ефектът от тази инструкция е да направи адреса на програмния брояч в стека за кода, който трябва да се изпълни преди извикването на подпрограмата и да се върне обратно към програмния брояч (PC). Този адрес е адресът на инструкцията, която трябва да бъде изпълнена преди извикването на подпрограмата.

Забележка: Когато пишете програма на асемблер за 6502 µP, само етикет трябва да започва в началото на реда; всеки друг редов код трябва да бъде изместен поне с един интервал надясно.

Извикване на подпрограма
Пренебрегвайки пространството в паметта, заето от предишните етикети, програмата заема 6 байта последователни местоположения в паметта (RAM) от $0300 до $0305. В този случай програмата е:

LDX #$FF ; заредете X с $FF = 255
DEX ; X = X – 1
BNE $0302; ако X не е нула, тогава отидете в цикъл
RTS ; връщане

Започвайки от адреса $0200 в паметта, може да бъде извикването на подпрограмата. Инструкцията за обаждане е:

начало на JSR; началото е адрес $0300, т.е. JSR $0300

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

стартирайте LDX #$FF; заредете X с $FF = 255
цикъл DEX; X = X – 1

BNE контур; ако X не е нула, тогава отидете в цикъл
RTS ; връщане

Начало на JSR: преминете към рутина, започваща от $0300

Сега може да има много подпрограми в една дълга програма. Всички те не могат да имат името 'старт'. Те трябва да имат различни имена. Всъщност никой от тях може да има името „старт“. „Старт“ се използва тук за обучение.

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

Преводът на програма или асемблирането й означава едно и също нещо. Помислете за следната програма:

стартирайте LDX #$FF : заредете X с $FF = 255
цикъл DEX: X = X – 1
BNE цикъл: ако X не е нула, тогава отидете в цикъл
RTS : връщане
Начало на JSR: преминете към рутина, започваща от $0300

Това е програмата, която е написана преди. Състои се от подпрограмата, start и извикването на подпрограмата. Програмата отброява от 255 10 до 0 10 . Програмата започва от началния адрес на потребителя от $0200 (RAM). Програмата се въвежда в текстов редактор и се записва на диска. Има име като „sample.asm“, където „sample“ е името по избор на програмиста, но разширението „.asm“ за асемблерния език трябва да бъде свързано с името на файла.

Асемблираната програма се произвежда от друга програма, която се нарича асемблер. Асемблерът се доставя от производителя на 6502 µP или от трета страна. Асемблерът възпроизвежда програмата по такъв начин, че тя да е в паметта (RAM), докато се изпълнява (изпълнява).

Да приемем, че JSR инструкцията започва от адрес $0200, а подпрограмата започва от адрес $0300. Асемблерът премахва всички коментари и бели полета. Коментарите и белите полета губят паметта, която винаги е оскъдна. Възможен празен ред между предишния сегмент на кода на подпрограмата и извикването на подпрограмата е пример за интервал. Сглобеният файл все още се запазва на диска и се нарича нещо като „sample.exe“. „Пробата“ е името по избор на програмиста, но разширението „.exe“ трябва да е там, за да покаже, че това е изпълним файл.

Сглобената програма може да бъде документирана, както следва:

Създаването на документ като този се нарича сглобяване на ръка. Имайте предвид, че коментарите в този документ не се появяват в паметта (за изпълнение). Адресната колона в таблицата показва началните адреси на инструкциите в паметта. Имайте предвид, че „JSR start“, което е „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. Всички инструкции и техните подробности могат да бъдат намерени в документа, озаглавен „SY6500 8-Bit Microprocessor Family“. Има PDF файл с името “6502.pdf” за този документ, който е свободно достъпен в Интернет. 6502 µP, който е описан в този документ, е 65C02.

4.16 Прекъсвания

Сигналите на всяко устройство, което е свързано към външните (вертикални повърхностни) портове на Commodore 64, трябва да преминат или през CIA 1, или през CIA 2 вериги (IC), преди да достигнат микропроцесора 6502. Сигналите от шината за данни на 6502 µP трябва да преминат или през чипа CIA 1, или през CIA 2, преди да достигнат до което и да е външно устройство. CIA означава Адаптер за сложен интерфейс. На Фигура 4.1 „Блокова диаграма на дънната платка Commodore_64“, блоковите входно/изходни устройства представляват CIA 1 и CIA 2. Когато дадена програма работи, тя може да бъде прекъсната, за да изпълни друга част от кода, преди да продължи. Има хардуерно прекъсване и софтуерно прекъсване. За хардуерно прекъсване има два щифта за входен сигнал към 6502 µP. Имената на тези щифтове са IRQ и NMI . Това не са µP линии за данни. Линиите за данни за µP са D7, D6, D5, D4, D3, D2, D1 и D0; с D0 за най-малкия бит и D7 за най-значимия бит.

IRQ означава Interrupt ReQuest „активно“ ниско. Тази входна линия към µP обикновено е висока, приблизително 5 волта. Когато падне до приблизително 0 волта, това е заявка за прекъсване, която сигнализира µP. Веднага щом заявката бъде удовлетворена, линията се връща високо. Предоставянето на заявка за прекъсване означава, че µP се разклонява към кода (подпрограмата), който обработва прекъсването.

NMI означава Non-Maskable Interrupt „активно“ ниско. Докато кодът за IRQ се изпълнява NMI може да падне ниско. В такъв случай, NMI се обработва (изпълнява се собствен код). След това кодът за IRQ продължава. След кода за IRQ приключва, основният програмен код продължава. Това е, NMI прекъсва на IRQ манипулатор. Сигналът за NMI все още може да се даде на µP, дори когато µP е неактивен и не обработва нищо или не изпълнява основна програма.

Забележка: Това всъщност е преходът от високо към ниско, на NMI , това е NMI сигнал – повече за това по-късно. IRQ обикновено идва от ЦРУ 1 и NMI обикновено идва от CIA 2. NMI , което означава Non-Maskable Interrupt, може да се счита за неспиращо прекъсване.

Обработка на прекъсвания
Дали заявката е от IRQ или NMI , текущата инструкция трябва да завърши. 6502 има само регистрите A, X и Y. Докато една подпрограма работи, тя може да използва тези три регистъра заедно. Манипулаторът на прекъсване все още е подпрограма, макар и да не се разглежда като такава. След като текущата инструкция бъде завършена, съдържанието на регистрите A, X и Y за 65C02 µP се записва в стека. Адресът на следващата инструкция на програмния брояч също се изпраща към стека. След това µP се разклонява към кода за прекъсването. След това съдържанието на регистрите A, X и Y се възстановява от стека в обратния ред, към който са изпратени.

Примерно кодиране за прекъсване
За простота приемете, че рутината за µP IRQ прекъсването е просто да съберете числата $01 и $02 и да запишете резултата от $03 на адреса на паметта $0400. Кодът е:

ISR PHA
PHX
PHY
;
LDA #$01
ADC #$02
СТРУВАТ $0400
;
PLY
PLX
PLA
RTI

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

Режим на абсолютно адресиране
В режим на абсолютно адресиране има един операнд. Този операнд е адресът на стойността в паметта (обикновено в шестнадесетична форма или етикет). Има 64K 10 = 65 536 10 адреси на паметта за 6502 µP. Обикновено еднобайтовата стойност е на един от тези адреси. Абсолютните инструкции за адресиране за 65C02 са: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA , STX, STY, STZ, TRB, TSB. Читателят трябва да се консултира с документацията за 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, инструкцията за асемблиране е нещо подобно:

LDA $C453, X

Ако се използва регистър Y, това е нещо като:

LDA $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 = 0B 16 :

Следващата таблица показва настройката за памет на низа, когато първият байт е „I“, а последният байт е Null ($00):

Следната инструкция може да се използва, за да започнете създаването на низа:

СТРУВАТ $0300

Да приемем, че първият байт е в акумулатора, който трябва да бъде изпратен до местоположението на адреса $0300. Тази инструкция е вярна и за двата случая (и за двата вида низове).

След поставяне на всички символи в клетките на паметта, един по един, низът може да бъде прочетен с помощта на цикъл. В първия случай се чете броя на знаците след дължината. Във втория случай знаците се четат от „I“, докато се срещне нулевият знак, който е „Null“.

4.19 Създаване на масив с асемблерния език 6502 µP

Масив от еднобайтови цели числа се състои от последователни местоположения на байтове в паметта с целите числа. След това има указател, който сочи към местоположението на първото цяло число. И така, масив от цели числа се състои от две части: указател и поредица от местоположения.

За масив от низове всеки низ може да бъде на различно място в паметта. След това има последователни места в паметта с указатели, където всеки указател сочи към първото местоположение на всеки низ. Указателят в този случай се състои от два байта. Ако даден низ започва с неговата дължина, съответният указател сочи към местоположението на тази дължина. Ако даден низ не започва с дължината си, а завършва с нулев знак, съответният указател сочи към местоположението на първия знак от низа. И има указател, който сочи към адреса на долния байт на първия указател от последователни указатели. И така, масивът от низове се състои от три части: низовете на различни места в паметта, съответните последователни указатели и указателят към първия указател от последователните указатели.

4.20 Проблеми

На читателя се препоръчва да реши всички задачи в дадена глава, преди да премине към следващата глава.

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