** ПЭВМ АГАТ **

Программирование для ПЭВМ АГАТ

Александр Голов

Скан оригинала.

******************************
*                            *
* A L V                      *
* COMPUTER AND PROGRAMME     *
* CORPORATION                *
*                            *
******************************

Сей документ не является руководством по программированию на языках высокого уровня - Бейсик, Рапира, а освещает приёмы составления программ на языке ассемблера и в машинных кодах.

В микро-ЭВМ "Агат" установлен микропроцессор 6502 (USA), система команд которого и будет рассматриваться далее. В основном программное обеспечения компьютера APPLE II подходит для использования в "Агате", но в деталях отличается (по вине конструкторов: за это давайте их коллективно поругаем. Если уж взялись делать новую машину - должны быть за неё ответственны!)

1. МИКРОПРОЦЕССОР

Каждый микропроцессор, в том числе и 6502, характеризуется определённой системой команд. Система команд - это полный перечень элементарных действий, которые способен производить микропроцессор. Управляемый этими командами микропроцессор выполняет очень простые действия, такие, как элементарные арифметические и логические операции, операции пересылки данных, сравнения двух величин и другие. Однако, составив программу из последовательности таких команд, можно запрограммировать выполнение алгоритма любой сложности. Память, адресуемая микропроцессором, представляет собой последовательность байтов (байт - это машинное слово, содержащее 8 бит).

По формату (числу отведённых для неё разрядов) команды делятся на одно-, двух-, трёхбайтовые. Байты команды последовательно друг за другом располагаются соответственно в одной, двух или трёх ячейках ЗУ (запоминающего устройства) микро-ЭВМ. Первый байт любой команды содержит код операции. Он определяет формат команды и те действия, которые должны быть произведены микропроцессором над данными в процессе её выполнения. Эти данные обычно называются операндами.

Микропроцессор имеет сложную структуру, но с точки зрения программиста он состоит только из пяти 8-разрядных (речь идёт о двоичных числах) регистров A, X, Y, регистра признаков выполнения операции F, регистра указателя стека S и 16-разрядного регистра указателя очереди команд PC.

Рассмотрим назначение внутренних регистров микропроцессора. Регистр A, так называемый аккумулятор, используется для хранения операнда, с которым работает арифметико-логическое устройство (АЛУ) микропроцессора. Результат по окончании обработки данных вновь помещают в регистр A.

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

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

В системе команд есть также двухбайтовые команды для косвенной адресации по двум соседним ячейкам, находящимся в области первых 256 адресов.

Кроме описанных двух способов адресации возможна адресация к ячейкам памяти по 8-разрядному регистру указателя стека S.

Под стеком в микропроцессоре 6502 подразумевается область памяти из 256 ячеек, расположенных непосредственно за ячейками данных с короткой адресацией. Адресация к ним осуществляется с помощью указателя стека S. При обращении к ячейке памяти, расположенной в стековой области, на шину адресов передаётся содержимое регистра S. С помощью команд, использующих стековую адресацию, в стек можно переслать любое 8-разрядное число из аккумулятора.

Запись числа в память в ячейку с адресом на единицу меньше указателя стека (т.е. в ячейку с адресом S-1). Таким образом, после записи содержимое указателя стека становится равным (S-1).

В системе команд микропроцессора есть команды, которые позволяют осуществить обратную операцию, т.е. переслать содержимое стека в аккумулятор или в счётчик команд PC. При этом сначала в регистр PC переписывается младший байт из ячейки памяти, адресуемый текущим положением указателя стека, затем старший байт из ячейки памяти с адресом S+1. После выполнения команды указатель стека принимает значение S+2.

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

Для хранения в памяти 16-разрядного числа всегда отводятся две смежные ячейки. Запись чисел в эти ячейки происходит побайтно, причём в ячейку с меньшим адресом записывается младший байт, а в ячейку с большим адресом заносится старший байт числа. Это правило выполняется при любых способах адресации, а также при записи в память трёхбайтовых команд, где второй и третий байты являются соответственно младшим и старшим байтами 16-разрядного числа.

2.СИСТЕМА КОМАНД

При написании программ для микро-ЭВМ программисту необходимо хорошо знать её систему команд. Это означает, что программист должен помнить весь перечень команд, хорошо представлять себе те действия, которые будут выполняться микропроцессором при выполнении каждой из них.

Код операции любой команды (для однобайтовой команды - это просто код команды) в ЗУ микро-ЭВМ представляется двоичным 8-разрядным числом. Всего двоичным кодом можно представить 256 различных комбинаций. Почти столько же команд, около 200, имеет и микропроцессор 6502.

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

После мнемоники для двухбайтовых команд записывается 8-разрядный операнд, обозначаемый при описании системы команд "8"; "8,X"; "8,Y"; "(8,X)"; "(8),Y", а для трёхбайтовых команд - "16"; "16,X"; "16,Y". Разберём что это означает: "8" - восьмиразрядный операнд для непосредственного использования. "8,X" - здесь к 8-разрядному числу предварительно прибавляется содержимое регистра X. "8,Y" - то же, только предварительно прибавляется содержимое регистра Y. "(8,X)" - косвенная адресация по двум соседним ячейкам, адрес младшей указывается в поле команды. Перед исполнением команды к операнду 8 прибавляется содержимое регистра X. Получившееся число и является адресом младшей ячейки, используемой при косвенной адресации. "(8),Y" - используется так же для косвенной адресации, но назначение регистра Y здесь другое. Его значение прибавляется к уже вычисленному значению по двум ячейкам. Т.е. его изменение приводит к изменению косвенного адреса, а не адреса ячеек для косвенной адресации. "16" - шестнадцатиразрядный операнд для непосредственного использования. "16;X" и "16;Y" - тоже что и "8,X", "8,Y", только с шестнадцатиразрядным операндом.

Все команды микропроцессора 6502 приведены ниже. Слева указан код команды, справа её мнемоническое обозначение. Далее для наглядности и упрощения записи все двоичные коды будем представлять в шестнадцатеричном виде. Для этого двоичный код числа делится на группы по 4 разряда. Для 8-разрядного кода операции или операнда таких групп будет две, а для 16-разрядного адреса таких групп будет четыре. Четырёхразрядным двоичным кодом можно представить любое десятичное число от 0 до 15. Обозначив эти величины цифрами от 0 до 9 и далее буквами латинского алфавита от A де F, мы получим шестнадцатеричные цифры. В таблице приведено соответствие между десятичными, двоичными, шестнадцатеричными значениями величин.

десятичное	двоичное	шестнадцат.

0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010	A
11 1011	B
12 1100	C
13 1101	D
14 1110	E
15 1111	F

Например, двоичный код 11000011 можно представить в виде шестнадцатеричного числа C3, операнду или коду B8 соответствует код 10111000, а адресу F204 - код 1111001000000100.

Таблица кодов команд

Код команды	-	Мнемоника	Тип адресации
00	-	BRK	
01	-	ORA	(8,X)
05	-	ORA	8
06	-	ASL	8
08	-	PHP	
09	-	ORA	#8
0A	-	ASL	
0D	-	ORA	16
0E	-	ASL	16
10	-	BPL	8
11	-	ORA	(8),Y
15	-	ORA	8,X
16	-	ASL	8,X
18	-	CLC	
19	-	ORA	16,Y
1D	-	ORA	16,X
1E	-	ASL	16,X
20	-	JSR	16
21	-	AND	(8,X)
24	-	BIT	8
25	-	AND	8
26	-	ROL	8
28	-	PLP	
29	-	AND	#8
2A	-	ROL	
2C	-	BIT	16
2D	-	AND	16
2E	-	ROL	16
30	-	BMI	8
31	-	AND	(8),Y
35	-	AND	8,X
36	-	ROL	8,X
38	-	SEC	
39	-	AND	16,Y
3D	-	AND	16,X
3E	-	ROL	16,X
40	-	RTI	
41	-	EOR	(8,X)
45	-	EOR	8
46	-	LSR	8
48	-	PHA	
49	-	EOR	#8
4A	-	LSR	
4C	-	JMP	16
4D	-	EOR	16
4E	-	LSR	16
50	-	BVS	8
51	-	EOR	(8),Y
55	-	EOR	8,X
56	-	LSR	8,X
58	-	CLI	
59	-	EOR	16,Y
5D	-	EOR	16,X
5E	-	LSR	16,X
60	-	RTS	
61	-	ADC	(8,X)
65	-	ADC	8
66	-	ROR	8
68	-	PLA	
69	-	ADC	#8
6A	-	ROR	
6C	-	JMP	(16)
6D	-	ADC	16
6E	-	ROR	16
70	-	BVS	8
71	-	ADC	(8),Y
75	-	ADC	8,X
76	-	ROR	8,X
78	-	SEI	
79	-	ADC	16,Y
7D	-	ADC	16,X
7E	-	ROR	16,X
81	-	STA	(8,X)
84	-	STY	8
85	-	STA	8
86	-	STX	8
88	-	DEY	
8A	-	TXA	
8C	-	STY	16
8D	-	STA	16
8E	-	STX	16
90	-	BCC	8
91	-	STA	(8),Y
94	-	STY	8,X
95	-	STA	8,X
96	-	STX	8,Y
98	-	TYA	
99	-	STA	16,Y
9A	-	TXS	
9D	-	STA	16,X
A0	-	LDY	#8
A1	-	LDA	(8,X)
A2	-	LDX	#8
A4	-	LDY	8
A5	-	LDA	8
A6	-	LDX	8
A8	-	TAY	
A9	-	LDA	#8
AA	-	TAX	
AC	-	LDY	16
AD	-	LDA	16
AE	-	LDX	16
B0	-	BCS	8
B1	-	LDA	(8),Y
B4	-	LDY	8,X
B5	-	LDA	8,X
B6	-	LDX	8,Y
B8	-	CLV	
B9	-	LDA	16,Y
BA	-	TSX	
BC	-	LDY	16,X
BD	-	LDA	16,X
BE	-	LDX	16,Y
C0	-	CPY	#8
C1	-	CMP	(8,X)
C4	-	CPY	8
C5	-	CMP	8
C6	-	DEC	8
C8	-	INY	
C9	-	CMP	#8
CA	-	DEX	
CC	-	CPY	16
CD	-	CMP	16
CE	-	DEC	16
D0	-	BNE	8
D1	-	CMP	(8),Y
D5	-	CMP	8,X
D6	-	DEC	8,X
D8	-	CLD	
D9	-	CMP	16,Y
DD	-	CMP	16,X
DE	-	DEC	16,X
E0	-	CPX	#8
E1	-	SBC	(8,X)
E4	-	CPX	8
E5	-	SBC	8
E6	-	INC	8
E8	-	INX	
E9	-	SBC	#8
EA	-	NOP	
EC	-	CPX	16
ED	-	SBC	16
EE	-	INC	16
F0	-	BEQ	8
F1	-	SBC	(8),Y
F5	-	SBC	8,X
F6	-	INC	8,X
F8	-	SED	
F9	-	SBC	16,Y
FD	-	SBC	16,X
FE	-	INC	16,X

Полный список команд включает в себя все коды. На самом же деле команд меньше (56). В полном списке они отличаются лишь операндами, а сама операция, производимая командой, остаётся такой же.

Список команд в алфавитном порядке:
ADC, AND, ASL, BCC, BCS, BEQ, BIT, BMI
BNE, BPL, BRK, BVC, BVS, CLC, CLD, CLI
CLV, CMP, CPX, CPY, DEC, DEX, DEY, EOR
INC, INX, INY, JMP, JSR, LDA, LDX, LDY
LSR, NOP, ORA, PHA, PHP, PLA, PLP, ROL
ROR, RTI, RTS, SBC, SEC, SED, SEI, STA
STX, STY, TAX, TAY, TSX, TXA, TXS, TYA

В полном списке команд встречается ещё один операнд, который не был описан ранее - #8. Он означает, что операция производится с константой, записанной в поле команды. Разберём подробно каждую команду.

ADC

Команда сложения двух операндов, учитывает признак переноса C, т.е. если признак переноса установлен в 1, то к полученной сумме прибавится 1. Если он равен 0, то сумма не изменяется. Команда ADC устанавливает признаки C, Z, N, V.

AND

Команда, выполняющая логическую операцию "И". Для 8-разрядного числа это выглядит так (пример):

10101010
10010011
--------
10000010

т.е. если в одноимённых разрядах стоят единицы, то и в полученном разряде будет 1. В других случаях там будет 0.

ASL

Команда сдвига байта. Если операнд не указан, т.е. команда однобайтовая, то сдвигается содержимое аккумулятора. То же правило сохраняется во всех командах сдвига. Команда ASL производит сдвиг влево через признак C, т.е. 8-й разряд записывается в признак переноса, а в 1 разряд записывается 0.

признак C - байт
0 - 10101101
после сдвига:
1 - 01011010

BCC

Команда условного перехода по нулевому значению признака C.

BCS

Команда условного перехода по единичному значению признака C.

BEQ

Команда условного перехода по единичному значению признака Z.

BIT

Команда аналогична команде AND, но в отличие от неё не изменяет содержимое аккумулятора, а лишь устанавливает признаки в соответствии с тем, что бы было, если бы AND выполнился.

BMI

Команда условного перехода по единичному значению признака N.

BNE

Команда условного перехода по нулевому значению признака Z

BPL

Команда условного перехода по нулевому значению признака N.

В поле команд условных переходов надо указать адрес перехода. На самом деле это не реальный адрес, а переход относительно регистра PC-программного счётчика. Цифра в поле команды перехода от 0 до 80 (не забывайте про шестнадцатеричную систему счисления) - это переход вперёд относительно программного счётчика, от 80 до FF назад. Причём при переходе вперёд, чтобы получить нужный операнд, записываемый в поле команды, надо из адреса "куда перейти" вычесть адрес "откуда перейти" и ещё 1. Адрес "откуда перейти" - имеется ввиду адрес ячейки, непосредственно следующей за операндом команды перехода. Назад переход осуществляется по-другому - из адреса "куда перейти" вычитается адрес "откуда перейти", потом прибавляется 1. Реальный код в поле команды образуется, если полученное значение вычесть из числа FF. Пример:

4000 - FF 02 BEQ $4004
4002 - A9 00 LDA #$00
4004 - 00 BRK

Здесь команда перехода BEQ осуществляет переход на адрес $4004 (знак "$" означает, что число шестнадцатеричное), т.е. цифра 02, указанная в поле команды, говорит о том, что надо пропустить 2 ячейки. Пример:

4000 - A9 00 LDA #$00
4002 - D0 FC BNE $4000
4004 - 00 BRK

Здесь команда перехода BNE осуществляет переход назад к ячейке $4000.

BRK

Останов выполнения программы. При этом на экран будет выведено содержимое всех регистров микропроцессора.

BVS

Команда условного перехода по единичному значению признака V.

BVC

Команда условного перехода па нулевому значению признака V.

CLC

Установка признака C в единичное значение.

CLD

Установка признака D в единичное значение. Вит D является признаком включения режима работы с десятичными числами. При этом перенос возникает, если число превышает 10 (десятичное).

CLI

Установка признака I в единицу. Бит I разрешает таймерное прерывание микропроцессора.

CLV

Установка признака V в единичное состояние.

CMP

Команда CMP позволяет сравнить два операнда. При выполнении этой команды из аккумулятора вычитается операнд (содержимое ячейки или непосредственный операнд) и устанавливаются все признаки. Содержимое регистров и ячеек не изменяется.

CPX

Выполняет такие же действия, что и команда CMP, только с регистром X.

CPY

То же, что и CMP, только с регистром Y.

DEC

Команда уменьшения содержимого ячейки на единицу. Воздействует на все признаки.

DEX

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

DEY

Уменьшает на единицу регистр Y.

EOR

Логическая операция "ИСКЛЮЧАЮЩЕЕ ИЛИ". Как меняется содержимое аккумулятора при такой команде показывает рисунок:

11100101
10101001
--------
01001100

Другими словами, если в двух разрядах - единицы или ноли, то получается ноль.

INC

Увеличивает на единицу содержимое ячейки. Воздействует на все признаки.

INX

Команда увеличения содержимого регистра X на единицу. Воздействует на все признаки.

INY

Увеличивает на единицу содержимое регистра Y.

JMP

Команда, осуществляющая безусловный переход. Адрес перехода указывается в поле команды - сначала младший байт адреса затем старший, как указывалось ранее. Команда JMP (16) осуществляет косвенный переход по содержимому любых двух ячеек, не только первых 256. Адрес состоит из двух байтов.

JSR

Команда перехода на подпрограмму. При переходах надо учитывать, что вложенность подпрограмм не должна превышать 128 (из-за ограниченного размера стека 256). Каждый адрес возврата из подпрограммы записывается в стек двумя байтами. Для возврата есть однобайтовая команда, которая будет описана далее.

LDA

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

LDX

Загрузка регистра X.

LDY

Загрузка регистра Y.

LSR

Операция сдвига байта вправо циклически. Содержимое бита 0 пересылается в C.

признак C - байт
0 - 10010011
после сдвига
1 - 01001001

* * *