Москва 2001 г тайный язык информатики Чарльз Петцольд ббк 32. 973. 26–018



Pdf көрінісі
бет14/26
Дата07.04.2020
өлшемі3,29 Mb.
#61783
1   ...   10   11   12   13   14   15   16   17   ...   26
Байланысты:
Petcold Kod-Taynyy-yazyk-informatiki.535358


262

Глава семнадцатая

Записываем 

результат

10h


20h

21h


FFh

0000h:


Сохранить

11h


Загрузить 

Сложить


Вычесть

Остановить

56h

2Ah


38h

0000h:


Данные

Коды


После выполнения команды Загрузить в аккумуляторе запи-

сано число  56h. После команды Сложить в нем содержится

сумма 56h и 2Ah, т. е. 80h. При выполнении команды Вычесть

биты следующего по порядку числа в массиве Данные (38h)

инвертируются. Инвертированное значение C7h складывает-

ся с числом 80h, при этом на вход сумматора для переноса (CI)

подается 1.

C7h


+80h

+1h


48h

Окончательный результат равен  48h (в десятичной системе

86 + 42 – 56 = 72).

Настало время обратиться к проблеме недостаточной раз-

рядности сумматора и подключенных к нему устройств. Рань-

ше я говорил лишь о наиболее прямолинейном решении этой

проблемы: включить в схему еще один 8-битовый сумматор

(и еще одну защелку, и еще один набор лампочек и т. д.), что-

бы в итоге получить 16-битовое устройство.

Но есть и более экономичное решение. Рассмотрим в каче-

стве примера сумму 16-разрядных чисел:

76ABh


+232Ch

Сложить два этих 16-битовых числа есть то же самое, что по

отдельности сложить их младшие байты:

ABh


+2Ch

D7h


263

Автоматизация

и старшие байты:

76h

+23h


99h

Получаем 99D7h. Если мы расположим 16-разрядные числа в

памяти таким образом:

Старший 


байт результата

10h


20h

11h


20h

0000h:


Загрузить

10h


Загрузить

Сложить


Сохранить

Сложить


ABh

2Ch


Данные

Коды


11h

Сохранить

FFh

Остановить



76h

23h


Младший 

байт результата

0000h:

число D7h будет сохранено по адресу 0002h, а 99h — по адресу



0005h.

Конечно, такая последовательность действий далеко не все-

гда будет приводить к желаемому результату. В данном кон-

кретном примере она сработала, но что если придется склады-

вать числа 76ABh и 236Ch? В этом случае сложение двух млад-

ших байтов приведет к появлению переноса:

ABh

+6Ch


117h

Это перенос нужно добавить к сумме старших байтов:

1h

+76h


+23h

9Ah


чтобы получить окончательный результат — 9A17h.

Можно ли усовершенствовать наш автоматический сум-

матор, чтобы он корректно складывал 16-разрядные числа?

Можно. Для этого нужно лишь сохранить бит переноса после



264

Глава семнадцатая

первого сложения, а затем подать его на вход сумматора для

переноса при втором сложении. Как сохранить этот бит? Ко-

нечно, в 1-битовой защелке, которую мы назовем защелкой для



переноса.

Для работы с защелкой для переноса нам понадобится еще

одна команда. Назовем ее Сложить с переносом. При сложе-

нии 8-битовых чисел вы используете обычную команду Сло-

жить. Вход CI сумматора равен 0, а выход CO сохраняется в

защелке для переноса (хотя в данном случае запоминать его и

не нужно).

Суммируя 16-битовые числа, вы сначала складываете их

младшие байты с помощью обычной команды Сложить. Вход

CI сумматора и в этом случае равен 0, а выход CO сохраняется

в защелке для переноса. Для сложения старших байтов вы при-

меняете команду Сложить с переносом. При ее выполнении

на вход сумматора для переноса подается содержимое защел-

ки для переноса. Если первое суммирование привело к появ-

лению переноса, он используется во втором суммировании.

Если переноса не было, выход защелки для переноса равен 0.

Для вычитания 16-битовых чисел нам понадобится еще

одна новая команда — Вычесть с заимствованием. Для выпол-

нения обычной команды Вычесть надо инвертировать вычи-

таемое и установить в 1 вход сумматора для переноса. При этом

обычно 1 равен и выход сумматора для переноса, но на это

при обычном вычитании можно закрыть глаза. Другое дело

— вычитание 16-битовых чисел. Тут значение выхода для пе-

реноса надо сохранять в защелке для переноса. При втором

вычитании содержимое этой защелки подается на вход CI сум-

матора.


С учетом двух новых команд мы набрали уже 7 кодов:

Команда

Код

Загрузить

10h

Сохранить



11h

Сложить


20h

Вычесть


21h

Сложить с переносом

22h

Вычесть с заимствованием



23h

Остановить

FFh


265

Автоматизация

При выполнении команд Вычесть и Вычесть с заимствовани-

ем число, направляемое в сумматор, инвертируется. Выход CO

сумматора является входом защелки для переноса. Его значе-

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

Вычесть, Сложить с переносом и Вычесть с заимствованием.

Вход сумматора для переноса устанавливается в 1 при выпол-

нении команды Вычесть или при выполнении команд Сложить

с переносом и Вычесть с заимствованием при условии, что 1

равен выход защелки для переноса.

Не забывайте, что при выполнении команды Сложить с

переносом вход сумматора для переноса устанавливается в 1,

только если к появлению переноса привело выполнение пре-

дыдущей команды Сложить или Сложить с переносом. При

сложении многобайтовых чисел всегда следует применять ко-

манду Сложить с переносом независимо от того, появится при

суммировании перенос или нет. В разобранном выше приме-

ре правильная последовательность команд такова:

10h

20h


11h

22h


0000h:

Загрузить

10h

Загрузить



Сложить

Сохранить

ABh

2Ch


Данные

Коды


11h

Сохранить

FFh

Остановить



76h

23h


0000h:

Старший 


байт результата

Младший 


байт результата

Сложить с переносом

Она корректно сложит любые 16-разрядные числа.

Всего две новые команды, но как они расширили возмож-

ности машины! Мы более не связаны необходимостью рабо-

тать только с 8-битовыми числами. Многократное примене-

ние команды Сложить с переносом позволит нам суммиро-

вать 16-битовые, 24-битовые, 32-битовые, 40-битовые значе-

ния и т. д. Например, для сложения 32-битовых чисел

7A892BCDh и 65A872FFh нам понадобится одна команда Сло-

жить и три команды Сложить с переносом:


266

Глава семнадцатая

10h


20h

11h


22h

0000h:


Загрузить 

10h


Загрузить

Сложить


Сохранить

Сложить с переносом

CDh

FFh


Данные

Коды


11h

Сохранить

10h

Загрузить 



2Bh

72h


0000h:

Следующий 

за младшим 

байт 


результата

89h


22h

A8h


11h

10h


7Ah

22h


65h

11h


FFh

Сложить с переносом

Сохранить

Загрузить

Сложить с переносом

Сохранить

Остановить

Младший 


байт 

результата

Предыдущий 

перед 


старшим 

байт 


результата

Старший 


байт 

результата

Конечно, заносить эти числа в память не ахти как интересно.

Мало того, что придется изрядно пощелкать переключателя-

ми, нужно еще и следить за тем, чтобы числа вводились в нуж-

ные ячейки. Число  7A892BCDh, например, занимает адреса

0000h, 0003h, 0006h и 0009h, начиная с младшего байта. А ре-

зультат сложения придется извлекать из ячеек 0002h, 0005h,

0008h и 000Bh.

Кроме того, сумматор в его теперешнем виде не допускает

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

сложили вы три 8-битовых числа, а затем вычли из суммы еще

одно 8-битовое число. Это легко сделать командами Загрузить,

Сложить, Сложить, Вычесть и Сохранить. Но если вы теперь

решите вычесть из суммы другое 8-битовое число, вам придет-

ся считать ее заново, так как нигде в памяти она не сохранилась.

Проблема нашего сумматора в том, что в нем доступ к ячей-

кам массивов Данные и Коды осуществляется одновременно

и последовательно, начиная с адреса 0000h. Каждой команде в

массиве Коды соответствует ячейка массива Данные, располо-

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

Данные командой Сохранить, вернуть обратно в аккумулятор

нельзя.


267

Автоматизация

Для решения этой проблемы я намерен внести в сумматор

фундаментальное изменение, которое на первый взгляд кажет-

ся довольно сложным. Но со временем вы поймете (надеюсь!),

какие просторы оно перед нами открывает.

Поехали! Итак, у нас сейчас 7 команд.



Команда

Код

Загрузить

10h

Сохранить



11h

Сложить


20h

Вычесть


21h

Сложить с переносом

22h

Вычесть с заимствованием



23h

Остановить

FFh

Пока каждый из кодов занимает в памяти 1 байт. Но я своей



властью выделяю каждому из них, кроме кода Остановить, по

3 байта памяти. В первом будет находиться сам код, а в двух

оставшихся — 16-битовый адрес ячейки памяти. В команде За-

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

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

Сложить с переносом и Вычесть с заимствованием по этому

адресу будет храниться число, которое нужно прибавить к со-

держимому аккумулятора или вычесть из него. В команде Со-

хранить в этих двух байтах будет указываться адрес ячейки, в

которую нужно записать содержимое аккумулятора.

Рассмотрим в качестве примера простейшую задачу, кото-

рую в состоянии решить наш сумматор, — сложение пары

чисел. Для ее решения вы заполняете массивы Данные и Коды

такими значениями:

10h

20h


11h

0000h:


Остановить

FFh


Загрузить

Сложить


Сохранить

4Ah


B5h

Данные


Коды

0000h:


Сумма

В модернизированном сумматоре все команды, кроме Ос-

тановить, занимают по 3 байта:


268

Глава семнадцатая

10h


00h

00h


00h

0000h:


Сложить байт по адресу 0001h 

и содержимое аккумулятора

20h

Загрузить в аккумулятор 



байт по адресу 0000h

Коды


01h

11h


Сохранить содержимое 

аккумулятора по адресу 0002h

00h

02h


FFh

Остановить

0003h:

0006h:


0009h:

За каждой командой, кроме Остановить, следуют два байта,

указывающие 16-битовый адрес ячейки в массиве Данные. В

данном случае это адреса 0000h, 0001h и 0002h.

Чуть раньше я показал вам, как командами Сложить и Сло-

жить с переносом найти сумму двух 16-битовых чисел —

76ABh и 232Ch. При этом младшие байты слагаемых мы дол-

жны были записать в ячейки 0000h и 0001h, а старшие — в

ячейки 0003h и 0004h. Результат сложения оказывался в ячей-

ках 0002h и 0005h.

С учетом нашего нововведения слагаемые и результат мож-

но разместить в памяти более понятным способом, причем в

той ее области, куда мы еще не забирались.

76h


ABh

Данные


4000h:

Сюда запишется старший байт суммы

23h

2Ch


Сюда запишется младший байт суммы

4002h:


4004h:

269

Автоматизация

В таком порядке я разместил все числа исключительно для

удобства. На самом деле они могут быть разбросаны по всем

64 К памяти в произвольном порядке. Для сложения чисел,

сохраненных в указанных выше ячейках, в массив Коды мы

должны ввести такие команды:

10h

40h


01h

40h


0000h:

Сложить байт по адресу

4003h и содержимое

аккумулятора

20h

Загрузить в аккумулятор



байт по адресу 4001h

Коды


Коды

03h


11h

40h


05h

10h


40h

00h


21h

Загрузить в аккумулятор 

байт по адресу 4000h

Сложить с переносом 

байт по адресу 4002h и 

содержимое аккумулятора

40h

02h


11h

Сохранить содержимое 

аккумулятора 

по адресу 4004h

40h

04h


FFh

Остановить

0003h:

0006h:


0009h:

000Ch:


000Fh:

0012h:


Сохранить содержимое

аккумулятора

по адресу 4005h

Сначала суммируются два младших байта, расположенные по

адресам 4001h и 4003h, а их сумма записывается в ячейку 4005h.

Старшие (из ячеек 4000h и 4002h) — суммируются командой

Сложить с переносом, а сумма сохраняется по адресу 4004h.

Теперь мы можем убрать команду Остановить и записать в

массив Коды дополнительные команды. Во всех последующих

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

так и результат их суммирования, просто обращаясь к соот-

ветствующим ячейкам памяти.

Чтобы воплотить эту систему в жизнь, мы должны под-

ключить к выходам массива Коды три 8-битовых защелки. В

каждой будет храниться один из байтов 3-байтовой команды.

В первую защелку попадет код команды, во вторую — стар-

ший байт адреса, в третью — младший. Выход второй и тре-

тьей защелок станет 16-битовым адресом ячейки в массиве

Данные:


270

Глава семнадцатая

Clk


Clr

Addr


DO

Пульт


управления

Пульт


управления

16

8



8-битовая

защелка


8-битовая

защелка


8-битовая

защелка


8

8

8



16

8

8



8

Коды


Addr

DO

8



DI

8

Дан-



ные

16-битовый

счетчик

Clk


W

Clk


Clk

64K 


× 

8

RAM



64K 

× 

8



RAM

Процесс извлечения команды из памяти называется выбор-



кой команды (instruction fetch). В нашем сумматоре каждая ко-

манда занимает по 3 байта и извлекается из памяти побайто-

во. Выборка одной команды занимает три цикла синхронизи-

рующего сигнала, а полный командный цикл — четыре цикла

синхронизирующего сигнала. Из-за этого система управляю-

щих сигналов, конечно, усложнится.

Слова «машина выполнила команду» подразумевают, что

в машине реализованы некие действия, зашифрованные ко-

дом команды. Это, разумеется, не означает, что машина живая

и способна анализировать код, чтобы решить, что делать даль-

ше. Назначение кода команды в том, чтобы генерировать уни-

кальную последовательность управляющих сигналов, которые

приводят к определенным последствиям.

Обратите внимание, что расширение возможностей маши-

ны отрицательно сказалось на ее быстродействии. При той же

частоте вибратора она занимается сложением вчетверо доль-

ше, чем исходная версия сумматора. Это следствие инженер-

ного принципа «Бесплатных обедов не бывает», который оз-

начает, что усовершенствование машины в одном отношении

приводит к ее ухудшению в чем-то другом.

Если бы вы в самом деле собирали эту машину из реле,

большую часть схемы составляли бы, очевидно, два 64-кило-

байтных массива памяти. Конечно, вы можете решить, что для

начала вам вполне хватит двух массивов объемом по 1 кб, и



271

Автоматизация

скорее всего так оно и есть. Но нельзя ли как-нибудь обойтись



одним  массивом? Вообще-то можно. Я разбил память на два

массива — для данных и для кодов — с единственной целью:

сделать архитектуру автоматического сумматора максималь-

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

команд до 3 байтов, используя второй и третий байты для ука-

зания адреса в памяти, надобность в двух отдельных массивах

отпала. И коды, и данные можно хранить в одном и том же

массиве.


Для этого нам понадобится селектор 2 линии на 1, кото-

рый будет определять способ адресации массива RAM. Один

адрес, как и раньше, поступает на селектор с 16-битового счет-

чика. Выход массива данных по-прежнему подключен к трем

защелкам, в которых сохраняется код команды и сопровожда-

ющие его два байта адреса. Этот 16-битовый адрес также по-

дается на вход селектора. Когда в защелки записывается адрес,

селектор пропускает его на адресный вход массива RAM:

Clk

Clr


Addr

DO

Пульт



управления

Селектор «2 на 1»

16

16

16



8

8

8



8

8

16



8

8

8



8

DI

Коды



Дан-

ные


16-битовый

счетчик


W

Clk


Clk

Clk


Sel

8-битовая

защелка

8-битовая



защелка

8-битовая

защелка

64K 


× 

8

RAM



Как мы продвинулись! Теперь можно вводить команды и

данные в один и тот же массив RAM. Вот как, например, мож-

но сложить два 8-битовых числа и вычесть из суммы третье:


272

Глава семнадцатая

10h


00h

10h


00h

0000h:


Сложить байт по адресу 0011h 

и содержимое аккумулятора

20h

Загрузить в аккумулятор байт 



по адресу 0010h

11h


21h

Вычесть байт по адресу 0012h 

из содержимого аккумулятора

00h


12h

11h


00h

13h


FFh

Сохранить содержимое аккумулятора 

по адресу 0013h

Остановить

..

.

45h



A9h

8Eh


000Ch:

0010h:


Ячейка для окончательного

 результата

Как обычно, размещение команд начинается с адреса 0000h,

так как именно с этого значения начинает считать 16-битовый

счетчик. Заключительная команда Остановить находится в

ячейке 000Ch. Три обрабатываемых числа и результат можно

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

13 ячеек, занятых командами. Я решил занять для них ячейки,

начиная с адреса 0010h.

Теперь допустим, что вам понадобилось прибавить к ре-

зультату еще два числа. Что ж, можно заменить только что

введенные команды новыми. Но не исключено, что вы пред-

почтете просто продлить уже введенную последовательность,

заменив команду Остановить в ячейке по адресу 000Ch новой

командой Загрузить. За ней последуют две команды Сложить,

команда Сохранить и команда Остановить. Но вот беда — на-

чиная с адреса 0010h, память занята данными. Придется пере-


273

Автоматизация

двинуть их дальше, соответствующим образом отредактиро-

вав команды, в которых эти данные используются.

Да-а-а, думаете вы. Наверное, с объединением данных и

кодов в одном массиве мы поторопились. Но уверяю вас, что

проблема такого рода возникла бы рано или поздно в любом

случае, поэтому мы должны ее решить. Попробуем, не сдви-

гая старые данные, разместить новые команды, начиная с ад-

реса 0020h, а новые данные — начиная с адреса 0030h:

10h


00h

13h


00h

0020h:


Сложить байт по адресу 0030h 

и содержимое аккумулятора

20h

Загрузить в аккумулятор байт 



по адресу 0013h

30h


20h

00h


31h

11h


00h

32h


FFh

Сохранить содержимое аккумулятора 

по адресу 0032h

Остановить

43h

2Fh


0030h:

Ячейка для окончательного 

результата

..

.



Сложить байт по адресу 0031h 

и содержимое аккумулятора

Заметьте: первая команда Загрузить обращается по адресу

0013h, где сохранен результат предыдущего вычисления.

Теперь память заполнена так: по адресу 0000h — команды, по

адресу 0010h — данные, по адресу 0020h — опять команды, а по

адресу 0030h — снова данные. Мы хотим, чтобы сумматор авто-

матически выполнил все команды, начав работу с ячейки 0000h.

Прежде всего нужно убрать из ячейки 000Ch команду Ос-

тановить. Проблема в том, что записанная по этому адресу



274

Глава семнадцатая

величина будет интерпретироваться как код команды. Та же

судьба постигнет и величину в ячейке, отстоящей от 000Ch на

3 байта, т. е. 000Fh, а также и в следующих ячейках с 3-байто-

вым интервалом — 0012h, 0015h, 0018h, 001Bh и 001Eh. Что

если один из этих байтов случайно окажется равен 11h — коду

команды Сохранить, а два байта за ним — 00h и 23h? Машина

послушно запишет содержимое аккумулятора в ячейку с ад-

ресом 0023h. Но эта ячейка содержит важную для нас инфор-

мацию! Даже если ничего подобного и не случится, нас все рав-

но ждут неприятности. С точки зрения машины, следующая

за 001Eh команда расположена в ячейке 0021h, а не 0020h, где

она находится на самом деле.

Все согласны с тем, что нельзя просто убрать из ячейки

000Ch команду Остановить и уповать на лучшее?

Мы должны заменить ее на новую команду, а именно коман-

ду Перейти, которую уже давно пора включить в наш репертуар.

Команда

Код

Загрузить

10h

Сохранить



11h

Сложить


20h

Вычесть


21h

Сложить с переносом

22h

Вычесть с заимствованием



23h

Перейти


30h

Остановить

FFh

Обычно адресация ячеек в автоматическом сумматоре проис-



ходит последовательно. Команда Перейти позволяет нарушить

это правило. После ее выполнения адресация массива  RAM

начинается с нового адреса. Команды такого рода называют

еще командами ветвления (branch).

В нашем примере командой Перейти нужно заменить

команду Остановить в ячейке 000Ch:

30h

00h


20h

000Ch:


Перейти к команде по адресу 0020h

275

Автоматизация

Величина 30h — это код команды Перейти. За ней располага-

ется 16-битовый адрес ячейки, где содержится следующая

команда, которую должен выполнять сумматор.

В нашем примере в начале работы сумматор выполняет

команду в ячейке 0000h — Загрузить. Затем исполняются

команды Сложить, Вычесть и Сохранить. Следующая — Пе-

рейти — заставляет сумматор прервать эту последовательность

и перейти к команде в ячейке 0020h. Это команда Загрузить, за

которой следуют Сложить, Сложить, Сохранить и наконец

Остановить.

Команда Перейти действует на 16-битовый счетчик. Вся-

кий раз, когда она встречается в последовательности команд,

на выходе счетчика должен появляться стоящий в ней адрес.

Это осуществляется с помощью входов  Pre и  Clr триггера

D-типа со срабатыванием по фронту,

Q

D

Clk



Q

Pre


Clr

который, как вы помните, является основным компонентом

счетчика.  Обычно входы Pre и Clr равны 0. Если сигнал Pre

равен 1, в 1 обращается и сигнал Q. Если 1 равен сигнал Clr,

сигнал Q обращается в 0.

Чтобы записать в триггер новое значение (будем называть

его А — адрес), его нужно включить в такую схему:

Q

Сброс



D

Clk


Q

Pre


Clr

Задать


A

276

Глава семнадцатая

Как правило, сигнал Задать равен 0. В этом случае вход Pre

триггера также равен 0. Если сигнал Сброс не равен 1, нулю

равен и сигнал Clr. Вход Сброс нужен, чтобы триггер можно

было очистить независимо от значения сигнала Задать. Если

сигнал Задать равен 1 и сигнал А тоже равен 1, сигнал Pre об-

ратится в 1, а Clr — в 0. Если сигнал А равен 0, сигнал Pre обра-

тится в 0, а Clr — в 1. Иными словами, значение выхода Q со-

впадает со значением на входе A.

В 16-битовом счетчике нам понадобится 16 таких схем. За-

грузите в счетчик новое значение, и он будет считать, начиная

с него.


Других серьезных изменений в схеме пока нет. 16-битовый

адрес, переписанный из памяти в защелки, подается как на вход

селектора «2 на 1» (откуда он попадает на адресный вход мас-

сива RAM), так и на вход 16-битового счетчика.

Clk

Clr


Addr

DO

Пульт



управления

Селектор «2 на 1»

16

16

16



8

8-битовая

защелка

8-битовая



защелка

8-битовая

защелка

8

8



8

8

16



8

8

8



8

DI

Коды



Дан-

ные


Задать

Сброс


16

Sel


16-битовый

счетчик


W

Clk


Clk

Clk


64K 

× 

8



RAM

Разумеется, сигнал должен обращаться в 1 лишь при выпол-

нении двух условий: код команды равен 30h и адрес перехода

сохранен в защелках.

Команда Перейти очень полезна. Но несравненно полез-

нее команда, осуществляющая переход лишь при выполнении

определенного условия. Такой переход называется условным


277

Автоматизация

(conditional jump). Чтобы проиллюстрировать его необходи-

мость, зададимся простым вопросом: способен ли наш сумма-

тор перемножить два 8-битовых числа, например, A7h и 1Ch?

Произведение двух 8-битовых чисел является 16-битовым

числом. Для простоты будем считать, что 16-битовыми явля-

ются и сомножители. Для начала решим, куда поместить ис-

ходные числа и их произведение.

00h

A7h


00h

00h


1000h:

16-битовый сомножитель

1Ch

16-битовый сомножитель



00h

1002h:


1004h:

16-битовое произведение разместится здесь

и здесь

В десятичном счислении 1Ch равно 28. Нет нужды доказы-



вать вам, что умножение A7h на 1Ch равносильно сложению

28 чисел A7h. Поэтому в ячейках 1004h и 1005h на самом деле

будет размещен 16-битовый результат этих многократных сло-

жений. Вот как выглядит набор кодов для размещения по это-

му адресу первой суммы:

10h


10h

05h


10h

0000h:


Сложить байт по адресу

1001h и содержимое 

аккумулятора

20h


Загрузить 

в аккумулятор байт 

по адресу 1005h

01h


11h

Сохранить содержимое

аккумулятора 

по адресу 1005h

10h

05h


10h

10h


04h

22h


Сложить байт по адресу

1000h и содержимое

аккумулятора

Сохранить содержимое

аккумулятора по адресу 

1004h


04h

00h


11h

10h


0012h:

10h


..

.

Загрузить в аккумулятор 



байт по адресу 1004h

0003h:


0006h:

000Fh:


000Ch:

0009h:


В начале работы ячейки 1004h и 1005h содержат нули. После

выполнения шести этих команд размещенное в них 16-бито-



278

Глава семнадцатая

вое значение равно A7h умножить на 1. Чтобы в ячейках 1004h

и 1005h оказалось нужное значение, ту же последовательность

кодов следует исполнить еще 27 раз. Достичь этого можно,

скопировав последовательность 27 раз, начиная с адреса 0012h,

или же разместить по этому адресу команду Остановить и 28

раз нажать кнопку Сброс.

Конечно, и тот, и другой вариант на практике использо-

вать неудобно. В обоих случаях от вас требуется некое действие:

ввести набор кодов или нажать кнопку Сброс, причем ровно

столько раз, на сколько нужно умножить число. Один-два раза

— куда ни шло, но перемножать числа таким способом всю

жизнь охотников найдется немного.

А что если разместить по адресу 0012h команду Перейти?

После ее выполнения счетчик снова начнет счет с 0000h:

30h


00h

00h


0012h:

Перейти к команде по адресу 0000h

Вроде бы то, что нужно. После первого выполнения кодов

ячейки 1004h и 1005h содержат значение, равное произведе-

нию A7h и 1. Затем команда Перейти осуществляет переход к

началу фрагмента, и после следующего его выполнения в ячей-

ках 1004h и 1005h содержится число A7h, умноженное на 2. В

конце концов машина доберется и до произведения A7h и 1Ch,

но, увы, в нужный момент не остановится!

Мы хотим, чтобы команда Перейти срабатывала только нуж-

ное число раз, т. е. совершала условный переход. Добиться это-

го на самом деле не так сложно. Для начала добавим в схему 1-

битовую защелку, похожую на защелку для переноса, и назо-

вем ее нулевой защелкой, так как ее содержимое будет равняться

1, только если все выходы 8-битового сумматора равны 0.

Флажок


нуля

DI

Clk



DO

Clr


8-битовый сумматор

279

Автоматизация

Выход 8-входового вентиля ИЛИ-НЕ равен 1, только если все

входы равны 0. Как и в защелке для переноса, синхронизиру-

ющий сигнал Clk в нулевой защелке вызывает запоминание

входного сигнала только при выполнении команд Сложить,

Вычесть, Сложить с переносом и Вычесть с заимствованием.

Величина, хранимая в нулевой защелке, называется флажком

нуля (Zero flag). Не запутайтесь: флажок нуля равен 1, если все

выходы сумматора равны 0; флажок нуля равен 0, если на не-

которых выходах сумматора имеются 1.

Защелка для переноса и нулевая защелка позволяют рас-

ширить набор доступных действий на 4 команды.

Команда

Код

Загрузить

10h

Сохранить



11h

Сложить


20h

Вычесть


21h

Сложить с переносом

22h

Вычесть с заимствованием



23h

Перейти


30h

Перейти если 0

31h

Перейти если перенос



32h

Перейти если не 0

33h

Перейти если не перенос



34h

Остановить

FFh

Например, команда  Перейти если не 0  вызывает переход на



заданный адрес, только если выход нулевой защелки равен 0.

Иначе говоря, перехода  не  будет, если результат последней

команды Сложить, Вычесть, Сложить с переносом или Вычесть

с заимствованием равен 0. Для реализации этой команды дос-

таточно расширить набор управляющих сигналов, применяе-

мых для обычной команды Перейти. При выполнении коман-

ды  Перейти если 0 сигнал Задать 16-битового счетчика уста-

навливается в 1, только если флажок нуля равен 0.

Имеющегося в нашем распоряжении набора команд хва-

тит для написания кодов, умножающих одно число на другое:



280

Глава семнадцатая

10h


10h

03h


00h

0012h:


Сложить байт по адресу 001Eh 

и содержимое аккумулятора

20h

Загрузить в аккумулятор байт 



по адресу 1003h

1Eh


11h

Сохранить содержимое аккумулятора 

по адресу 1003h

10h


03h

33h


00h

00h


FFh

Остановить

001Eh:

Перейти к команде по адресу 0000h, 



если флажок нуля не равен 1

0015h:


0018h:

001Bh:


Как мы уже установили, к началу этого фрагмента в ячейках

0004h и 0005h содержится 16-битовое число A7h, умноженное

на 1. Первая команда фрагмента загружает в аккумулятор число

из ячейки 1003h, т. е. 1Ch. Оно складывается с содержимым

ячейки 001Eh. Да, в ячейке 001Eh записан код команды Оста-

новить, но это не мешает ему быть и просто обычным чис-

лом. Сложить FFh и 1Ch — это все равно что вычесть из 1Ch

единицу. В результате получается 1Bh. Это не 0, поэтому фла-

жок нуля равен 0. Число 1Bh записывается обратно в ячейку

1003h. Далее следует команда Перейти если не 0. Поскольку

результат действительно не равен 0, условие перехода соблю-

дается, и следующей будет выполнена команда по адресу 0000h.

Не забывайте: команда Сохранить на значение флажка нуля

не влияет. Он задается лишь при выполнении команд Сложить,

Вычесть, Сложить с переносом и Вычесть с заимствованием и

сохраняет значение до следующего выполнения одной из этих

команд.

При втором выполнении фрагмента ячейки 0004h и 0005h



содержат произведение числа A7h на 2. Число 1Bh прибавля-

ется к FFh, и получается 1Ah. Это не 0, поэтому вновь проис-

ходит возвращение к началу.


281

Автоматизация

На 28-й раз ячейки 0004h и 0005h содержат произведение

чисел A7h и 1Ch. По адресу 1003h хранится число 1. Его сумма с

числом FFh равна 0, и флажок нуля наконец-то устанавливает-

ся в 1! Условие команды Перейти если не 0 не выполняется, пе-

рехода нет, и следующей командой становится Остановить. Есть!

Наступает великий миг: я утверждаю, что собранное нами

устройство может с полным правом именоваться компьютером!

Очень примитивным, но компьютером. Его ключевое свойство

— наличие команды условного перехода. Именно возможность

управляемых  циклических  процедур отличает компьютер от

калькулятора. Я только что продемонстрировал, как наша ма-

шина с помощью условного перехода умножила одно число на

другое. Подобным образом можно осуществить и деление. Да-

лее, действие нашей машины не ограничено 8-битовыми чис-

лами. Она способна складывать, вычитать, умножать и делить

16-битовые, 24-битовые, 32-битовые числа и числа большей

разрядности. А значит, ей подвластны квадратные корни, лога-

рифмы и тригонометрические функции.

Раз уж мы собрали компьютер, пора начать говорить о нем,

как о компьютере.

Разработанное нами устройство относится к  цифровым

(digital) компьютерам, поскольку работает с дискретными циф-

рами. Это отличает его от аналоговых (analog) компьютеров,

которые существовали некоторое время назад, а сейчас прак-

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

способные принимать лишь набор фиксированных значений.

Аналоговые данные непрерывны и могут принимать любое

значение из заданного интервала.

Цифровой компьютер состоит из 4 основных компонен-

тов: процессорапамяти, минимум одного устройства ввода и

минимум одного устройства вывода. В нашей машине память

состоит из 64-килобайтового массива RAM. Роль устройств

ввода и вывода играют ряды переключателей и лампочек на

пульте управления памятью. Они позволяют нам (исполняю-

щим в этом шоу роли людей) вводить в память числа и про-

сматривать результаты вычислений.

Все остальное — процессор (processor) или, как его еще

называют,  центральное процессорное устройство (Central

Processor Unit) — ЦПУ (CPU). Процессор часто называют моз-



гом компьютера, но я стараюсь не прибегать к подобным срав-

282

Глава семнадцатая

нениям, поскольку лично мне собранная схема мозг не напо-

минает. В наши дни часто приходится слышать слово микро-

процессор. Это тот же процессор, только маленький-малень-

кий, благодаря изобретениям, о которых я расскажу в главе

18. К нашему релейному детищу приставка «микро» вряд ли

подходит!

Процессор, который мы собрали, является  8-разрядным.

8 битам равна ширина аккумулятора и большинства каналов

данных. Из 16 битов состоит только адрес в массиве RAM. Если

бы он был 8-битовым, мы могли бы адресовать не 65 536, а

лишь 256 байтов — тут не разгуляешься.

Процессор тоже состоит из нескольких компонентов. Я уже

неоднократно упоминал аккумулятор — защелку для хране-

ния чисел внутри процессора. 8-битовый инвертор и 8-бито-

вый сумматор вместе составляют арифметико-логическое ус-

тройство (Arithmetic Logic Unit) — АЛУ (ALU). В нашем слу-

чае оно способно выполнять только арифметические действия,

а именно сложение и вычитание. В несколько более сложных

компьютерах (с которыми мы еще познакомимся) арифмети-

ко-логическое устройство выполняет также логические опера-

ции — И, ИЛИ и исключающее ИЛИ. 16-битовый счетчик на-

зывается программным счетчиком (program counter).

Наш компьютер состоит из реле, проводов, переключате-

лей и лампочек. Все вместе они называются аппаратным обес-

печением  (hardware) компьютера. Команды и другие числа,

которые мы вводили в память, составляют его  программное



обеспечение (software).

В разговорах о  компьютерах программное обеспечение

обычно называют просто программами, а процесс их создания

—  программированием. Придумывая набор команд, которые

позволили бы нашему компьютеру умножать одно число на

другое, именно программированием я и занимался.

Обычно в компьютерных программах различают код (code),

т. е. собственно команды, и данные (data), т. е. числа, с которы-

ми работает код. Иногда это различие не столь очевидно. На-

пример, в разобранном нами примере код команды Остано-

вить одновременно играет роль числа –1. Коды команд (на-

пример, 10h для команды Загрузить), на основании которых

процессор выполняет то или иное действие, называются ма-

шинными кодами или машинным языком. Слово «язык» впол-



283

Автоматизация

не оправданно, так как именно с помощью кодов человек

«объясняет» машине, что она должна сделать.

До сих пор я называл команды, выполняемые машиной,

довольно длинными словами и целыми фразами, например,

Сложить с переносом. Но на практике для обозначения команд

используют двух- трехбуквенные английские сокращения —

мнемонические коды, — записываемые прописными буквами.

Вот как может выглядеть набор мнемокодов для нашего ком-

пьютера.


Команда

Английское название

Код

Мнемокод

Загрузить

Load

10h


LOD

Сохранить

Store

11h


STO

Сложить


Add

20h


ADD

Вычесть


Subtract

21h


SUB

Сложить


Add with Carry

22h


ADC

с переносом

Вычесть

Subtract with Borrow



23h

SBB


с заимство-

ванием


Перейти

Jump


30h

JMP


Перейти

Jump If Zero

31h

JZ

если 0



Перейти

Jump If Carry

32h

JC

если



перенос

Перейти


Jump If Not Zero

33h


JNZ

если не 0

Перейти

Jump If Not Carry



34h

JNC


если не

перенос


Остановить

Halt


FFh

HLT


Удобство мнемокодов станет более очевидным, если мы

присовокупим к ним еще пару обозначений. Например, усло-

вимся писать вместо многословной инструкцию «Загрузить в

аккумулятор байт по адресу 1003h» короткое выражение:

LOD A,[1003h]


284

Глава семнадцатая

Обозначения A и [1003h], стоящие справа от мнемокода, на-

зываются аргументами. Аргументы конкретизируют выпол-

нение команды. Например, в команде Загрузить они указыва-

ют, куда (аргумент слева) следует загрузить данные (А означа-

ет аккумулятор) и откуда (аргумент справа) их следует извлечь.

Квадратные скобки означают, что в аккумулятор надлежит заг-

рузить не число 1003h, а содержимое ячейки памяти по адресу

1003h.

Подобным же образом инструкцию «Сложить байт по ад-



ресу 001Eh и содержимое аккумулятора» можно сократить до:

ADD A,[001Eh]

а инструкцию «Сохранить содержимое аккумулятора по адре-

су 1003h» — до:

STO [1003h],A

Заметьте: в команде STO мы также слева указываем, куда со-

храняются данные, и справа — откуда они извлекаются: со-

держимое аккумулятора записывается в ячейку 1003h. Нако-

нец, команда «Перейти к команде по адресу 0000h, если фла-

жок нуля не равен 1» превращается в краткое указание:

JNZ 0000h

Здесь квадратные скобки не применяются, поскольку переход

всегда осуществляется только по адресу. Числом аргумент этой

команды быть не может.

С учетом всех обозначений команды удобно записывать в

столбик, причем обводить их рамками уже не нужно; они и

без этого прекрасно читаются. Адрес, по которому хранится

команда (точнее, ее первый байт), мы будем указывать шест-

надцатеричными числом с двоеточием:

0000h: LOD A,[1005h]

А вот так будут обозначаться записанные в память данные:

1000h: 00h, A7h

1002h: 00h, 1Ch

1004h: 00h, 00h

Перечисление байтов через запятую означает, что первый байт

записан в ячейке, адрес которой указан слева, а второй байт —



285

Автоматизация

в следующей за ней ячейке. Эти три строчки можно было бы

заменить одной:

1000h: 00h, A7h, 00h, 1Ch, 00h, 00h

Целиком программа для умножения выглядит так:

0000h:


LOD A,[1005h]

ADD A,[1001h]

STO [1005h],A

LOD A,[1004h]

ADC A,[1000h]

STO [1004h],A

LOD A,[1003h]

ADD A,[001Eh]

STO [1003h],A

JNZ 0000h

001Eh:

HLT


1000h:

00h, A7h


1002h:

00h, 1Ch


1004h:

00h, 00h


Пробелы и пустые строки расставлены здесь с единственной

целью — сделать программу более понятной.

При написании кодов численные значения адресов лучше

не использовать, так как они могут измениться. Если вы, на-

пример, решите хранить данные, начиная с адреса 2000h, а не

1000h, вам придется переписывать многие команды. Для обо-

значения ячеек памяти предпочтительнее пользоваться мет-

ками (labels):

BEGIN:


LOD A,[RESULT + 1]

ADD A,[NUM1 + 1]

STO [RESULT + 1],A

LOD A,[RESULT]

ADC A,[NUM1]

STO [RESULT],A



286

Глава семнадцатая

LOD A,[NUM2 + 1]

ADD A,[NEG1]

STO [NUM2 + 1],A

JNZ BEGIN

NEG1:


HLT

NUM1:


00h, A7h

NUM2:


00h, 1Ch

RESULT:


00h, 00h

Метки NUM1, NUM2 и RESULT ссылаются на ячейки, храня-

щие по 2 байта. В приведенной выше программе выражения

NUM1 + 1, NUM2 + 1 и RESULT + 1 ссылаются на второй байт

соответствующей метки. Обратите внимание на метку NEG1

у команды HLT: она означает «negative one», т. е. «минус один».

Наконец, на случай, если вы забудете, зачем нужна та или

иная команда, в программе предусмотрены комментарии. Они

пишутся на простом человеческом языке и отделяются от кода

точкой с запятой:

BEGIN:

LOD A,[RESULT + 1]



ADD A,[NUM1 + 1]

; Сложить младшие байты

STO [RESULT + 1],A

LOD A,[RESULT]

ADC A,[NUM1]

; Сложить старшие байты

STO [RESULT],A

LOD A,[NUM2 + 1]

ADD A,[NEG1]

; Уменьшить число на 1

STO [NUM2 + 1],A

JNZ BEGIN

NEG1:

HLT


NUM1:

00h, A7h


NUM2:

00h, 1Ch


RESULT:

00h, 00h


287

Автоматизация

Язык программирования такого типа называется языком ас-



семблера  (assembly language). Это своеобразный компромисс

между бессловесными машинными кодами и многословными

командами на «человеческом» языке, дополненный текстовы-

ми ссылками на ячейки памяти. Язык ассемблера и машинные

коды часто путают, поскольку это просто различные способы

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

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

Если бы вам пришлось писать программу для компьютера,

разработанного в этой главе, вы, наверное, предпочли бы сна-

чала написать ее на языке ассемблера (и на бумаге). Затем, когда

вы решили бы, что программа в основном написана и готова к

тестированию, вам пришлось бы  вручную ассемблировать ее,

т. е. переводить операторы ассемблера в соответствующие чис-

ловые машинные коды, опять же на бумаге. Далее машинные

коды вводились бы в память компьютера с помощью переклю-

чателей, и программу можно было бы запускать, т. е. указать

компьютеру выполнить все составляющие ее команды.

После знакомства с концепцией программирования самое

время поговорить об ошибках. Совершать их при написании

программ, особенно, в машинных кодах, очень легко. Нехо-

рошо, конечно, когда в программе используются неверные

числа. Но что если с ошибкой вы введете код команды, напри-

мер, наберете с помощью переключателей 11h (код команды

Сохранить) вместо 10h (код команды Загрузить)? Компьютер

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

ло в аккумулятор, но и выполнит ненужное — запишет по-

верх этого числа теперешнее содержимое аккумулятора.

Последствия некоторых ошибок бывают непредсказуемы,

например, когда по адресу, указанному в команде Перейти,

отсутствует корректный код команды или когда командой Со-

хранить в ячейку с кодом команды по ошибке записывается

число. Произойти в таких случаях может (и происходит) все

что угодно.

Ошибка имеется даже в моей программе для умножения.

Если вы запустите ее во второй раз, она умножит A7h на 256 и

запишет результат поверх уже посчитанного произведения.

Причина понятна: после первого выполнения программы в

ячейке 1003h записан 0. Запустите программу еще раз, и к нему

будет прибавлено число  FFh. Результат не равен 0, поэтому

выполнение программы продолжится.



288

Глава семнадцатая

Мы убедились, что наша машина умеет умножать, а зна-

чит, и делить. Я заявил также, что эти простейшие операции

позволяют находить корни, логарифмы и тригонометричес-

кие функции. На аппаратную часть компьютера возлагаются

три обязанности: сложение, вычитание и условный переход.

Как говорят программисты: «Для остального напишем про-

грамму».


Конечно, программа эта может оказаться очень сложной.

Об алгоритмах решения конкретных вычислительных задач

написано множество книг. Но нам пока рано задумываться об

этом. Мы ведь до сих пор ограничивались целыми числами,

не взяв на себя смелость подумать о дробях. Но мы еще вер-

немся к ним — в главе 23.

Я несколько раз говорил о том, что все приборы, нужные

для сборки компьютера, изобретены более 100 лет назад. Но

это, конечно, не означает, что уже тогда создание подобного

устройства было возможно. Многие принципы, рассмотрен-

ные нами в этой главе, даже в эпоху появления первых релей-

ных компьютеров (в 1930-е годы) все еще не были известны.

Додуматься до них люди смогли лишь в середине XX в. До того

времени многие изобретатели, например, упорно пытались

создать устройства, работающие не с двоичными, а с десятич-

ными числами. Не сразу оформилась и идея совместного хра-

нения кода и данных. Часто предпочитали вводить програм-

му в компьютер по мере ее выполнения с помощью перфо-

ленты. С памятью на заре компьютерной эры вообще были

большие трудности. Сборка 64 К памяти из 5 млн. реле сто лет

назад была такой же абсурдной задачей, как и сейчас.

Настало время немного оторваться от практических упраж-

нений и коротко познакомиться с историей появления счет-

ных устройств и машин. Не исключено, что в конце концов

окажется, что мы напрасно возились с нашим релейным ком-

пьютером. В главе 12 я уже говорил, что на смену реле при-

шли вакуумные лампы и транзисторы. Мы узнаем также, что

за это время люди научились делать разработанные нами про-

цессор и память совсем-совсем миниатюрными.




Достарыңызбен бөлісу:
1   ...   10   11   12   13   14   15   16   17   ...   26




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет