ВНЕШНИЕ УСТРОЙСТВА
Работа программиста превратится в бессмысленные математические упражнения при отсутствии
связи компьютера с внешним миром, осуществляемой через порты.
Хотя Z80 имеет 16-разрядную шину адреса, в ZX Spectrum при обращении к большинству внешних
устройств значащими являются только 8 младших разрядов. Например, для изменения цвета бордю-
ра необходимо записать соответствующее значение в порт с адресом %0000000011111110 (254)*,
но если Вы запишете это же значение в порт %0000000111111110 (510), то получите тот же эф-
фект. Разряды, не влияющие на выбор устройства, обычно обозначаются знаком x , и, таким об-
разом, полный адрес упомянутого выше внешнего устройства записывается как xxxxxxxx11111110.
Для упрощения аппаратной части в Speccy выбор внешних устройств осуществляется сбросом в
ноль одного из разрядов адреса. Порт 254, например, выбирается при А0=0, порт 239 — при А4=0
и т. д. При разработке ZX Spectrum были сделаны следующие назначения для разрядов шины адре-
са:
АО — клавиатура, магнитофон, динамик; 254
А1 — не используется (в ZX Spectrum 48К);253
А2 — ZX Printer; 251
A3 и А4 — Interface 1 и микродрайв. 247 и 239(231) **
*) Ниже для обозначения шестнадцатеричных чисел использован символ #, двоичных — символ %.
**) Здесь и далее фразы на сером фоне означают, что они добавлены в оригинальную книгу под редакцией
Дегтяр Олега Прокопьевича.
Если несколько разрядов будут сброшены в ноль, окажутся выбранными одновременно несколько
устройств.
Разряды А5, А6 и А7 оставлены разработчиками для специального применения, но, в принципе,
могут быть использованы для подключения дополнительных внешних устройств, например, джойсти-
ка.
Разряды с А8 по А15 используются для сканирования клавиатуры (только при сброшенном АО).
Хотя в фирменном ZX Spectrum для выбора внешнего устройства и не используются все разряды
младшего байта адреса, тем не менее, во избежание различных накладок, в программах рекомен-
дуется всегда указывать точный 8-разрядный адрес порта.
Ниже рассмотрены стандартные порты ZX Spectrum. Для каждого порта указаны его десятичный
и, в скобках, шестнадцатеричный и двоичный адреса.
_Порт 255 (#FF, %11111111)
Внешнего устройства с таким адресом в ZX Spectrum нет, поэтому из порта 255 считывается
состояние «пассивной» шины данных. Благодаря оригинальному схемотехническому решению, в ZX
Spectrum шина данных используется одновременно для двух процессов: работы Z80 и вывода ин-
формации на дисплей. В момент формирования изображения из порта 255 считываются случайные
значения (анализ показывает, что преимущественно считываются
атрибуты отображаемого в данный момент знакоместа), а во время, не занятое выводом — зна-
чение 255.*
Чтение из порта 255 в некоторых фирменных программах используется для синхронизации отно-
сительно вывода на экран, и поэтому они отказываются работать на многих самоделках.**
*) На самом деле, если Вы попытаетесь обратиться по другим незадействованным адресам портов, то получите
аналогичный результат.
**) В ZX Spectrum +3 схема отображения выполнена более грамотно, чем в Speccy, однако это стало причиной не-
полной совместимости с базовой моделью. Ряд программ, например, Short Circuit, на Spectrum +3 не работают.
_Порт 254 (#FE, %11111110)
ZX Spectrum управляет магнитофоном, клавиатурой, цветом бордюра и динамиком через один-
единственный порт с адресом 254.
При записи байта в порт:
биты DO...D2 определяют цвет бордюра:
000 (0) — черный 100 (4) — зеленый
001 (1) —синий 101 (5) — голубой
010 (2) — красный 110 (6) — желтый
011 (3) — фиолетовый 111 (7) — белый;
бит D3 управляет выходом на магнитофон. Манипулируя этим битом, программы обслуживания
магнитофона формируют сигнал записи;
бит D4 управляет звуковым каналом. Например, для того чтобы получить звук частотой 1 кГц,
необходимо устанавливать и сбрасывать этот бит 1000 раз в секунду;
биты D5...D7 не используются.
При чтении байта из порта:
биты DO...D4 обслуживают клавиатуру.
Стандартная клавиатура ZX Spectrum состоит из 40 клавиш, которые разбиты на восемь рядов
по пять кнопок в каждом (рис. 12). Для того, чтобы узнать, какая из клавиш ряда нажата, нуж-
но прочесть байт из порта, полный 16-разрядный адрес которого задается так: младший байт ад-
реса равен 25 4 (#FE), а в старшем байте сброшен в ноль один из разрядов, соответствующий вы-
бран-
Номер джойстика |
1 |
2 |
Адрес порта |
#EFFE |
#F7FE |
Функция |
бит |
клавиша |
бит |
клавиша |
влево (left) |
D4 |
6 |
D0 |
1 |
вправо (right) |
D3 |
7 |
D1 |
2 |
вниз (down) |
D2 |
8 |
D2 |
3 |
вверх (up) |
D1 |
9 |
D3 |
4 |
стрельба (fire) |
DO |
0 |
D4 |
5 |
_Порт 251
(#FB, %11111011)
Порт обслуживает стандартный для ZX Spectrum
принтер—ZX Printer, драйвер которого «зашит» в
ПЗУ компьютера. Некоторые интерфейсы принтеров в тот момент, когда на адресной шине появляется
адрес 251, «перехватывают» управление. Например, интерфейс ZX Lprint III с помощью драйверов из
его собственного ПЗУ может через порт 251 управлять различными типами принтеров.
*) Interface 2 позволяет также использовать картриджи с ПЗУ, в которое при изготовлении записываются
готовые программы.
Порт 247 (#F7, %11110111)
Порт 239 (#EF, %11101111)
_Порт 231 (#Е7, %11100111)
Порты устройства Interface 1, которое позволяет: соединять компьютеры в локальную вычисли-
тельную сеть; использовать стандартный интерфейс RS—232C; подключать до восьми микродрайвов
(накопителей на «бесконечной» магнитной ленте), работать с которыми несколько удобнее, чем с
магнитофоном. Однако в Союзе Interface 1 по разным причинам не получил распространения.
_Порт 31 (#1F, %00011111)
Порт 31 служит для связи с самым распространенным типом
джойстика — Kempston Joystick. Старшие три бита (D5...D7)
этого порта всегда сброшены в ноль — именно по этому усло-
вию некоторые программы определяют, что kempston-джойстик
подключен. Младшие биты (DO...D4) индицируют состояние
джойстика (см. табл. 2). Таблица 2. Биты
состояния
kempston-джойстика.
Несколько битов может быть установлено одновременно. На-
пример, если установлены биты DO, D3 и D4, то это означа-
ет, что джойстик находится в положении «влево-вниз» и нажата «стрельба».
При нейтральном положении kempston-джойстика из порта 31 должен считываться ноль.
СИСТЕМА ПРЕРЫВАНИЙ
Прерывания являются необходимым средством для программирования параллельных процессов. С
их помощью, например, в ZX Spectrum одновременно с выполнением программы на Бейсике осущест-
вляется сканирование клавиатуры и отсчет времени системным таймером.
В процессоре Z80 имеется два аппаратных входа инициализации прерываний: INT — для маски-
руемых прерываний и NMI — для немаскируемых. Маскируемые прерывания получили свое название
благодаря возможности программно запрещать или разрешать реакцию на сигнал прерывания, тогда
как для немаскируемых прерываний это невозможно.
При поступлении сигнала прерывания микропроцессор завершает выполнение текущей команды,
помещает в стек адрес следующей и приступает к выполнению специальной программы, обслуживаю-
щей данное прерывание (за исключением режима 0 маскируемых прерываний). После завершения об-
работки прерывания процессор извлекает из стека адрес следующей команды и возвращается к вы-
полнению прерванной программы.
Необходимым условием правильного функционирования программ обслуживания прерываний являет-
ся их сбалансированная работа со стеком: к моменту возврата из прерывания стек должен быть в
том же состоянии, в котором он находился к моменту прихода прерывания. Другим условием явля-
ется сохранение всех регистров, задействованных в программе обслуживания прерываний, и вос-
становление их значений при возврате из прерывания.
_Маскируемые прерывания
В ZX Spectrum на вход INT процессора постоянно подается полукадровый синхронизирующий сиг-
нал с периодом 1/50 секунды. В операционной системе это используется для организации опроса
клавиатуры и наращивания значения системного счетчика одновременно с работой интерпретатора
Бейсика.
Управлять прохождением маскируемых прерываний можно командами DI и EI, которые изменяют
состояние специального внутреннего триггера микропроцессора IFF. Команда DI сбрасывает этот
триггер, запрещая прерывания, EI устанавливает его, разрешая прерывания.
При вызове маскируемого прерывания триггер IFF автоматически сбрасывается, запрещая по-
вторный вызов прерываний. После обработки прерывания процессор не устанавливает триггер
вновь — для разрешения прохождения последующих прерываний программист должен включить в про-
грамму команду EI.
Z8 0 имеет три режима обработки маскируемых прерываний, которые устанавливаются командами
процессора IM О, Ш 1 и IM 2. К сожалению, программным путем практически невозможно опреде-
лить, в каком режиме обработки прерываний находится процессор в конкретный момент времени.
_Режим 0
Режим устанавливается либо командой Ш 0, либо аппаратным сбросом процессора, и ничем не
отличается от режима обработки прерываний в микропроцессоре I8080. По приходу сигнала INT
процессор считывает с шины данных код команды (предварительно выставленный на шину внешним
прерывающим устройством) и выполняет ее. В принципе, это может быть любая команда (чаще все-
го используются команды RST N или CALL addr). Но ZX Spectrum устроен таким образом, что при
вызове прерывания в режиме 0 с шины данных всегда считывается значение 255 (#FF) — код ко-
манды RST 56. И, следовательно, для ZX Spectrum этот режим аналогичен режиму 1.*
*) Строго говоря, это не совсем так, см. примечание к режиму 2.
_Режим 1
Устанавливается командой IM 1. По прерыванию процессор передает управление на ячейку с ад-
ресом 56 (выполняется команда CALL 56). Именно в этом режиме обрабатывает прерывания опера-
ционная система ZX Spectrum.
_Режим 2
Устанавливается командой IM 2. Режим дает возможность программисту самостоятельно обраба-
тывать прерывания, чем и интересен.
установленный бит |
состояние джойстика |
D0 |
влево (left) |
D1 |
вправо (right) |
D2 |
вверх (up) |
D3 |
вниз (down) |
D4 |
стрельба (fire) |
При поступлении сигнала на прерывание, микропроцессор считывает с шины данных байт, назы-
ваемый вектором прерывания. ZX Spectrum устроен так, что вектор прерывания всегда равен 255
(#FF).* Он передается в младший байт шины адреса, а в старший байт записывается содержимое
регистра вектора прерываний I. По полученному таким образом адресу Z80 считывает из памяти
два последовательно расположенных байта, которые интерпретируются процессором как адрес про-
граммы обработки прерывания (сначала считывается младший байт адреса, затем старший). Следо-
вательно, выбрав режим прерываний 2 и задав значение регистра I, можно переопределить адрес
процедуры обработки прерывания.
Для задания адреса размещения программы обработки прерываний наиболее удобно использовать
значения, считываемые из стандартного ПЗУ ZX Spectrum. При этом в регистр I нужно занести
число в пределах от 0 до 63 (#00...#3F). Например, если в I содержится число 9, то адрес
ячейки, из которой будет считан младший байт адреса программы обработки прерываний, равен
2559 (9x256+255). Старший байт, соответственно, будет считан по адресу 2560. В данном случае
определить адрес, по которому необходимо разместить программу обработки прерываний, можно,
выполнив строку на Бейсике:
PRINT PEEK (2559)+256*РЕЕК (2560)
Результат должен быть равен 65129. Это и есть адрес, по которому должна располагаться под-
программа обработки прерываний.
Определить все возможные считанные из ПЗУ адреса размещения процедур обработки прерываний
можно с помощью следующей программы:
10 INPUT "Interrupt vector:";I:REM вектор прерывания
20 PRINT I,PEEK (I*256+255)+256*PEEK (I*256+255+1)
Уже рассчитанные адреса занесены в табл. 3.
Возврат из маскируемых прерываний производится командой RETI. Она распознается специальны-
ми периферийными_
*) Некоторые внешние устройства, например, AMX-mouse, могут генерировать вектор прерывания, отличный
от 255.
Таблица 3. Адреса процедур обработки прерываний.
I |
адрес |
I |
адрес |
I |
адрес |
I |
адрес |
0 |
20430 |
16 |
51984 |
32 |
52513 |
48 |
60208 |
1 |
52818 |
17 |
08729 |
33 |
33485 |
49 |
57640 |
2 |
22269 |
18 |
52481 |
34 |
00544 |
50 |
13627 |
3 |
39020 |
19 |
49749 |
35 |
49537 |
51 |
13256 |
4 |
10419 |
20 |
25705 |
36 |
08527 |
52 |
01560 |
5 |
02294 |
21 |
51673 |
37 |
23670 |
53 |
57124 |
6 |
29149 |
22 |
51568 |
38 |
20444 |
54 |
34307 |
7 |
16039 |
23 |
12493 |
39 |
00288 |
55 |
41231 |
8 |
02088 |
24 |
15582 |
40 |
32348 |
56 |
65535 |
9 |
65129 |
25 |
23842 |
41 |
58154 |
57 |
65535 |
10 |
32802 |
26 |
13824 |
42 |
19754 |
58 |
65535 |
11 |
58888 |
27 |
07306 |
43 |
23653 |
59 |
65535 |
12 |
53183 |
28 |
49947 |
44 |
07117 |
60 |
00255 |
13 |
52503 |
29 |
02344 |
45 |
55781 |
61 |
00000 |
14 |
14367 |
30 |
26573 |
46 |
23713 |
62 |
00255 |
15 |
27928 |
31 |
03360 |
47 |
04569 |
63 |
00060 |
микросхемами*, что позволяет организовать многоуровневую систему прерываний. Но, поскольку в
ZX Spectrum эта система не используется, то вернуться из прерывания можно и по команде RET.
_Немаскируемые прерывания
Немаскируемое прерывание вызывается при поступлении сигнала на вход NMI процессора. При
этом выполнение основной программы приостанавливается, и управление передается на ячейку с
адресом 102 (#66) (выполняется команда CALL 102).
В ZX Spectrum немаскируемое прерывание не задействовано, но оно может вызываться некоторы-
ми внешними устройствами. При этом вместо стандартной «прошивки» подключается ПЗУ вызвавшего
прерывание устройства, в котором записана программа обработки прерывания. Этот принцип ис-
пользуется, например, в дисковой системе Beta Disk фирмы Technology Research и интерфейсе
Multiface One фирмы Romantic Robot.
При входе в немаскируемое прерывание сбрасывается триггер IFF, и, следовательно, запреща-
ется вызов маскируемых прерываний.
Возврат из немаскируемого прерывания и восстановление состояния регистра IFF происходит по
команде процессора RETN.
Следует отметить, что на самом деле Z80 имеет два триггера, участвующих в обработке преры-
ваний: IFF1 и IFF2. Триггер IFF1 используется для управления разрешением маскируемых преры-
ваний, a IFF2 хранит его состояние при обработке немаскируемых. Состояние триггера IFF2 от-
ражается битом P/V флагового регистра после выполнения команд LD А, I или LD
A, R._
*) Фирмой Zilog были разработаны микросхемы, входящие совместно с Z80 CPU в комплект под общим названи-
ем Z80.
Действие |
IFF1 |
IFF2 |
Примечание |
сигнал RESET |
|
0 |
^ IFF1 |
0 ^ |
IFF2 |
устанавливает режим 0 |
команда DI |
|
0 |
|
IFF1 |
0 ^ |
IFF2 |
запрещает прерывания |
команда EI |
|
1 |
|
IFF1 |
1 ^ |
IFF2 |
разрешает прерывания |
сигнал INT |
|
0 |
|
IFF1 |
0 ^ |
IFF2 |
маскируемое прерывание |
команда RETI |
|
IFF2 |
^ IFF1 |
не изменяется |
возврат из маскируемого |
|
|
|
|
|
|
|
прерывания |
сигнал NMI |
|
0 |
^ IFF1 |
IFF1 |
^ IFF2 |
немаскируемое прерывание |
команда RETN |
|
IFF2 |
^ IFF1 |
не изменяется |
возврат из немаскируемо- |
|
|
|
|
|
|
|
го прерывания |
команда LD А, |
I |
не |
изменяется |
не изменяется |
IFF2 ^ P/V |
команда LD A, |
R |
не |
изменяется |
не изменяется |
IFF2 ^ P/V |