Глава 16
Сборка памяти
Каждое утро, когда мы просыпаемся, включается наша память. Мы вспоминаем, где находимся, что делали накануне, что планируем сделать сегодня. Память возвращается сразу или фрагментами, и в течение еще нескольких минут человек может чего-то не помнить («Забавно, я не помню, что лег спать в носках»), однако в целом мы способны восстановить непрерывность своей жизни, чтобы начать новый день.
Разумеется, человеческая память не вполне упорядочена. Попытайтесь вспомнить что-нибудь из школьного курса геометрии. Вероятно, начнете думать о сидевшем перед вами однокласснике или о том дне, когда сработала пожарная тревога как раз в тот момент, когда учитель собирался объяснить вам, что значит выражение «что и требовалось доказать».
Человеческая память не является вполне надежной. Письменность, возможно, была изобретена специально, чтобы компенсировать недостатки человеческой памяти. Может быть, прошлой ночью вы внезапно проснулись в 3:00 с отличной идеей для сценария. Схватили ручку и бумагу, которые держите у кровати специально для таких случаев, и записали идею. На следующее утро вы читаете свою блестящую мысль и начинаете работу над сценарием («Парень встречает девушку, погоня на машинах и взрывы»… и это всё?). Или не начинаете.
Мы пишем, а затем читаем. Мы сохраняем, а потом извлекаем. Мы храним информацию, а в дальнейшем получаем к ней доступ. Функция памяти заключается в том, чтобы сохранять информацию без искажений между этими двумя событиями. Каждый раз, когда мы сохраняем информацию, мы используем разные типы памяти. Бумага — хороший носитель для хранения текстовой информации, магнитная лента подходит для хранения музыки и фильмов.
Телеграфные реле, будучи объединенными в вентили, а затем в триггеры, также могут хранить информацию. Как мы видели ранее, триггер способен хранить один бит. Это не очень много, но это начало. Как только мы научимся сохранять один бит, мы легко сможем справиться с двумя, тремя и более.
В главе 14 мы познакомились с D-триггером со срабатыванием по уровню, который состоит из инвертора, двух вентилей И и двух вентилей ИЛИ-НЕ.
Когда вход Clk равен 1, выходной сигнал Q совпадает с входным сигналом «Данные». Когда значение входа Clk меняется на 0, выход Q сохраняет последнее значение входа «Данные». Дальнейшие изменения входного сигнала «Данные» не влияют на выходы до тех пор, пока значение входа Clk снова не изменится на 1. Вот таблица логики для триггера.
В главе 14 этот триггер использовался в разных схемах, а сейчас он будет применяться исключительно для хранения одного бита. По этой причине я собираюсь переименовать входы и выходы, чтобы они соответствовали цели.
Это тот же триггер, только теперь выход Q называется «Вывод данных» (Data Out, DO), а вход Clk («Запомнить этот бит») стал «Записью» (Write, W). Так же, как мы можем записать некоторую информацию на бумаге, сигнал «Запись» приводит к записи или сохранению сигнала «Ввод данных» (Data In, DI) в схеме. Обычно вход «Запись» равен 0, а сигнал «Ввод данных» не влияет на выход. Однако всякий раз, когда мы хотим сохранить значение сигнала «Ввод данных» в триггере, подаем на вход «Запись» 1, а затем снова 0. Как я упоминал в главе 14, схема такого типа также называется защелкой, поскольку она как бы «запирает» данные. Вот как мы можем представить однобитную защелку без изображения всех отдельных компонентов.
Мы можем достаточно легко объединить несколько однобитных защелок в многобитную. Все, что для этого нужно сделать, — соединить входы «Запись».
Эта 8-битная защелка содержит восемь входов и восемь выходов. Кроме того, защелка имеет один вход под названием «Запись», который обычно равен 0. Чтобы сохранить 8-битное значение в этой защелке, подайте на вход «Запись» 1, а затем 0. Эту защелку также можно изобразить следующим образом.
Или так, чтобы она больше напоминала изображение однобитной.
Другой способ соединения восьми однобитных защелок более сложен. Допустим, нам нужен только один сигнал «Ввод данных» и один сигнал «Вывод данных». Однако мы хотим сохранить значение сигнала «Ввод данных» восемь раз в течение дня или восемь раз в течение следующей минуты. Кроме того, мы хотим иметь возможность в дальнейшем просмотреть эти восемь значений, только бросив взгляд на один сигнал «Вывод данных».
Другими словами, вместо сохранения одного 8-битного значения, как в случае с 8-битной защелкой, мы хотим сохранить восемь отдельных однобитных значений.
Почему мы хотим сделать именно так? Вероятно, потому, что у нас есть только одна лампочка.
Мы знаем, что нам требуется восемь однобитных защелок. Давайте пока не будем волноваться, как именно данные в них сохраняются. Сосредоточимся на проверке сигналов «Вывод данных» этих восьми защелок, используя только одну лампочку. Конечно, мы могли бы проверять выход каждой защелки, вручную перенося лампочку от одной защелки к другой, но мы бы предпочли более автоматизированный способ. Фактически мы хотим выбирать одну из восьми однобитных защелок, используя переключатели.
Сколько переключателей нужно? Если хотим выбрать один из восьми элементов, потребуются три переключателя. Три переключателя могут представлять восемь разных значений: 000, 001, 010, 011, 100, 101, 110 и 111.
Итак, вот наши восемь однобитных защелок, три переключателя, лампочка и устройство, которое необходимо поместить между переключателями и лампочкой.
Устройство — это некий корпус с восемью входами сверху и тремя входами слева. Замыкая и размыкая три переключателя, мы можем выбрать, какой из восьми входов должен быть перенаправлен на выход в нижней части корпуса. Этот выход зажигает лампочку.
Так что же это за устройство? Мы уже видели что-то подобное, хотя и не с таким количеством входов. Оно похоже на схему, которую мы использовали в главе 14 в первой модифицированной версии сумматора. В том случае нам нужно было нечто позволяющее выбрать, откуда должен поступать сигнал на вход сумматора: от ряда переключателей или с выхода защелки. Тогда мы назвали устройство селектором «2 на 1». В данном случае нам нужен селектор «8 на 1».
Селектор восьми линий на одну имеет восемь входов для данных (вверху) и три входа для выборки (Select, Sel) (слева). Входы Select позволяют выбрать, сигнал какого входа для данных появится на выходе. Например, если сигналы Select равны 000, то выходной сигнал совпадает с D0. Если входы Select равны 111, то выходной сигнал совпадает с D7. Если входы Select — 101, выходной сигнал совпадает с D5. Приведем таблицу логики для этого селектора.
Селектор «8 на 1» состоит из трех инверторов, восьми четырехвходовых вентилей И и одного восьмивходового вентиля ИЛИ.
Эта схема может показаться довольно запутанной, однако с помощью следующего примера постараюсь убедить вас, что она работает. Допустим, сигналы Sel2 и Sel0 равны 1, а сигнал S1— 0. На входы шестого сверху вентиля И подаются сигналы Sel0, Sel1, Sel2, каждый из которых равен 1. Ни на один другой вентиль И эти три сигнала не подаются, поэтому выход всех остальных вентилей И будет равен 1. Выход шестого вентиля И — 0 при D5, равном 0, или 1 при D5, равном 1. То же касается крайнего справа вентиля ИЛИ. Таким образом, если сигналы для выборки равны 101, выходной сигнал совпадает с сигналом D5.
Давайте еще раз повторим, чего хотим добиться. Мы пытаемся соединить восемь однобитных защелок так, чтобы в них можно было записывать и считывать данные по отдельности, используя один сигнал «Ввод данных» и один сигнал «Вывод данных». Мы уже выяснили, что можно выбрать сигнал «Вывод данных» одной из восьми защелок, используя селектор «8 на 1».
Итак, наша задача наполовину решена. Теперь, когда мы определились с устройством на выходе, давайте займемся входом.
На входе мы имеем сигналы «Данные» и «Запись». Входы «Данные» защелок можно соединить между собой. Однако мы не можем сделать то же самое с сигналами «Запись», поскольку хотим записывать данные отдельно, следовательно, должны подавать один сигнал «Запись» на одну (и только одну!) защелку.
Теперь нужна другая схема, которая немного похожа на селектор «8 на 1», но выполняет прямо противоположное действие. Эта схема называется дешифратор «3 на 8». В главе 11 мы уже видели простой дешифратор данных, когда соединяли переключатели для выбора цвета нашей идеальной кошки.
Дешифратор «3 на 8» имеет восемь выходов. В любой момент все эти выходы равны 0, кроме одного, который выбран входными сигналами Sel0, Sel1 и Sel2. Значение этого выхода совпадает со значением входа «Ввод данных».
Обратите внимание: входными сигналами шестого вентиля И сверху являются Sel0, Sel1, Sel2. Они не подаются ни на один другой вентиль И, поэтому если на входы для выборки подается значение 101, то выходы всех остальных вентилей И будут равны 0. Вход шестого вентиля И может иметь значение 0, если вход «Ввод данных» равен 0, или 1, если вход «Ввод данных» равен 1. Полная таблица логики имеет следующий вид.
Полная схема с восемью защелками выглядит таким образом.
Важно: три сигнала выборки для дешифратора и селектора являются одинаковыми (они обозначены словом «адрес» — address, Addr). Подобно почтовому индексу, этот 3-битный адрес определяет, к какой из восьми однобитных защелок мы обращаемся. На входе сигнал «Адрес» определяет, какая защелка сохранит сигнал «Данные» под воздействием сигнала «Запись». На выходе (в нижней части схемы) вход «Адрес» управляет селектором «8 на 1» для того, чтобы считать выходной сигнал одной из восьми защелок.
Эта конфигурация защелок иногда называется памятью с записью/чтением, но чаще — памятью с произвольным доступом, или произвольной выборкой (random access memory, RAM). Эта конкретная конфигурация RAM хранит восемь отдельных однобитных значений. Ее можно изобразить следующим образом.
Устройство называется памятью, потому что оно сохраняет информацию. Возможность чтения/записи говорит о том, что вы можете сохранить новое значение в любой защелке (записать значение), а также узнать, что хранится в каждой из защелок (прочитать значение). Термин «произвольный доступ» означает, что запись и считывание информации из защелок могут осуществляться путем изменения входных сигналов «Адрес». Кроме памяти с произвольным доступом, существует память с последовательным доступом, при использовании которой для считывания значения, хранящегося по адресу 101, требуется сначала прочитать значение, хранящееся по адресу 100.
Описанная выше конфигурация RAM часто называется массивом RAM. Этот конкретный массив RAM организован по схеме, иногда сокращенно обозначаемой «8 × 1» — восемь однобитных значений. Чтобы определить общее количество битов, которые можно сохранить в массиве RAM, нужно перемножить эти два числа.
Массивы RAM можно комбинировать. Например, объединить два массива RAM «8 × 1».
В данном случае входы «Адрес» и «Запись» двух массивов RAM «8 × 1» соединены, поэтому в результате получается массив RAM «8 × 2».
Этот массив RAM хранит восемь значений, размер каждого из которых составляет два бита.
Кроме того, два массива RAM «8 × 1» можно объединить как отдельные защелки, используя селектор «2 на 1» и дешифратор «1 на 2».
Сигнал «Выборка», который подается как на дешифратор, так и на селектор, по сути, выбирает один из двух массивов RAM «8 × 1». На самом деле он является четвертой адресной линией. Таким образом, мы имеем дело с массивом RAM «16 × 1».
Этот массив RAM хранит 16 значений, размер каждого из которых составляет один бит. Количество значений, хранящихся в массиве RAM, напрямую зависит от количества входов «Адрес». В отсутствие таких входов (как в случае с однобитной и 8-битной защелками) может быть сохранено только одно значение. При наличии одного входа «Адрес» можно сохранить два значения. Два входа «Адрес» позволяют хранить четыре значения, три входа «Адрес» — восемь, четыре входа — шестнадцать. Такое отношение можно выразить с помощью уравнения:
Количество значений в массиве RAM = 2 количество входов «Адрес».
Я показал, как можно сконструировать небольшие массивы RAM, поэтому вам нетрудно будет представить гораздо более крупные. Например, такой.
Этот массив RAM хранит в общей сложности 8196 бит информации, которые организованы в виде 1024 значений по восемь бит каждое. Этот массив имеет десять входов «Адрес», так как 210 равно 1024, восемь входов и восемь выходов для данных.
Другими словами, этот массив RAM хранит 1024 байт. Он похож на почтовое отделение с 1024 абонентскими ящиками. В каждом из них хранится значение размером один байт (которое, правда, может представлять просто спам).
Одна тысяча двадцать четыре байта — килобайт, и здесь возникает большая путаница. Чаще всего приставка «кило-» (от греческого «тысяча») используется в метрической системе. Например, килограмм — это 1000 граммов, километр — 1000 метров. Однако килобайт составляет 1024 байт, а не 1000 байт.
Проблема в том, что метрическая система основана на степенях 10, а двоичные числа — на степенях 2, и этим системам никогда не сойтись. Степенями 10 являются 10, 100, 1000, 10 000, 100 000 и т. д., а степенями 2 — 2, 4, 8, 16, 32, 64 и т. д. Не существует степени 10, которая была бы равна некоторой степени 2.
Однако время от времени эти две системы сближаются. Да, значение 1000 достаточно близко к значению 1024. Выражаясь математическим языком, 2 в степени 10 «приблизительно равно» 10 в степени 3:
210 ≈ 103.
В этом соотношении нет ничего волшебного. Оно всего лишь подразумевает, что конкретная степень 2 приблизительно равна конкретной степени 10. Это совпадение позволяет людям использовать термин «килобайт памяти», подразумевая 1024 байта.
Килобайт сокращенно обозначается Кбайт (международное обозначение — Kb). Описанный выше массив RAM может хранить 1024 байт, или один килобайт (1 Кбайт).
Мы не подразумеваем, что в массиве RAM емкостью один килобайт хранится 1000 байт. В нем хранится больше тысячи байт, а именно 1024. Чтобы произвести впечатление знающего человека, следует говорить «один килобайт».
Один килобайт памяти имеет восемь входов и восемь выходов для данных, а также десять входов «Адрес». Поскольку доступ к байтам осуществляется с помощью десяти входов «Адрес», массив RAM хранит 210 байт. Всякий раз, когда добавляем еще один вход «Адрес», мы удваиваем объем памяти. Каждая строка следующей последовательности представляет собой удвоение памяти:
1 килобайт = 1024 байт = 210 байт ≈ 103 байт;
2 килобайта = 2048 байт = 211 байт;
4 килобайта = 4096 байт = 212 байт;
8 килобайт = 8192 байт = 213 байт;
16 килобайт = 16 384 байт = 214 байт;
32 килобайта = 32 768 байт = 215 байт;
64 килобайта = 65 536 байт = 216 байт;
128 килобайт = 131 072 байт = 217 байт;
256 килобайт = 262 144 байт = 218 байт;
512 килобайт = 524 288 байт = 219 байт;
1024 килобайт = 1 048 576 байт = 220 байт ≈ 106 байт.
Обратите внимание: указанные слева количества килобайтов — степени 2.
Ту же логику, которая позволяет называть 1024 байт килобайтом, мы можем использовать для того, чтобы назвать 1024 килобайт мегабайтом (приставка «мега-» — от греческого «великий»). Мегабайт сокращенно обозначается Мбайт (Mbyte, реже MB). Удвоение памяти продолжается:
1 мегабайт = 1 048 576 байт = 220 байт ≈ 106 байт;
2 мегабайта = 2 097 152 байт = 221 байт;
4 мегабайта = 4 194 304 байт = 222 байт;
8 мегабайт = 8 388 608 байт = 223 байт;
16 мегабайт = 16 777 216 байт = 224 байт;
32 мегабайта = 33 554 432 байт = 225 байт;
64 мегабайта = 67 108 864 байт = 226 байт;
128 мегабайт = 134 217 728 байт = 227 байт;
256 мегабайт = 268 435 456 байт = 228 байт;
512 мегабайт = 536 870 912 байт = 229 байт;
1024 мегабайт = 1 073 741 824 байт = 230 байт ≈ 109 байт.
Одна тысяча двадцать четыре мегабайта составляют гигабайт (приставка «гига-» — от греческого «гигантский»), который обозначается буквами Гб (GB).
Один терабайт (от греческого «чудовищный») равен 240 байт (приблизительно 1012), или 1 099 511 627 776 байт. Терабайт обозначается буквами Тб (TB).
Килобайт равен примерно тысяче байтов, мегабайт — миллиону, гигабайт — миллиарду, терабайт — триллиону байтов.
Петабайт равен 250, или 1 125 899 906 842 624 байт (приблизительно 1015, или квадриллион), а экзабайт равен 260, или 1 152 921 504 606 846 976 байт (приблизительно 1018, или квинтиллион).
Примите к сведению, что домашние компьютеры, купленные в период написания этой книги (1999 год), обычно имели 32 или 64 (иногда 128) мегабайта памяти с произвольным доступом. (Заметьте, я говорю о памяти RAM, а не о емкости жестких дисков.) Это 33 554 432 байт, или 67 108 864 байт, или 134 217 728 байт.
Разумеется, в разговоре люди используют сокращения. Обладатель 65 536 байтов памяти скажет: «У меня 64 килобайта (и я гость из далекого 1980 года)». Пользователь компьютера с памятью 33 554 432 байт уточнит: «У меня 32 мега». А везунчик, имеющий 1 073 741 824 байт памяти, подчеркнет: «У меня целый гиг».
Иногда упоминают килобиты или мегабиты (обратите внимание на использование слова «биты» вместо «байты»), но это бывает редко. Почти всегда, когда речь идет о памяти, сообщают количество байтов, а не битов. (Чтобы преобразовать байты в биты, нужно умножить их на 8.) Обычно когда в разговоре упоминаются килобиты или мегабиты, они имеют отношение к скорости передачи данных по кабелю и используются в таких словосочетаниях, как «килобиты в секунду» и «мегабиты в секунду». Например, когда речь идет о модеме 56 K, имеется в виду именно 56 килобит в секунду, а не килобайт; технология Gigabit Ethernet обеспечивает передачу одного гигабита информации в секунду и т. д.
Теперь, научившись собирать массивы RAM любого нужного размера, постараемся не сильно увлекаться. Давайте просто представим массив RAM емкостью 65 536 байт.
Почему 64 килобайт? Почему не 32 килобайт или не 128 килобайт? Потому что 65 536 — хорошее круглое число. Оно равно 216. Этот массив RAM имеет 16-битный адрес. Другими словами, этот адрес равен двум байтам. В шестнадцатеричной системе счисления значение этого адреса находится в диапазоне от 0000h до FFFFh.
Ранее я намекнул на то, что объем памяти, равный 64 килобайт, был характерен для персональных компьютеров, купленных в 1980-х годах, хотя эта память собиралась и не из телеграфных реле. Удастся ли сконструировать такое устройство, используя реле? Надеюсь, вы не рассматриваете такую возможность всерьез. Наша конструкция предполагает использование девяти реле для каждого бита памяти, поэтому для создания массива RAM 64 Kб × 8 потребуются почти пять миллионов реле.
Нам также не помешает пульт управления, позволяющий пользоваться этой памятью: записывать значения или считывать их. Такой пульт должен иметь 16 переключателей для указания адреса, восемь переключателей для задания 8-битного значения, которое мы хотим записать, еще одного переключателя для самого сигнала записи и восемь лампочек для отображения определенного 8-битного значения.
Все переключатели изображены в положении «Выключено» (0). Я также добавил переключатель с надписью «Перехват». Цель этого переключателя — позволить другим схемам использовать ту же память, к которой подключен пульт управления. Когда этот переключатель установлен в положение 0 (как показано на рисунке), остальные переключатели пульта управления ничего не делают. Однако когда переключатель установлен в положение 1, управление памятью осуществляется исключительно с помощью пульта.
Для создания переключателя «Перехват» потребуется набор селекторов «2 на 1», а именно 25 штук: шестнадцать — для сигналов «Адрес», восемь — для переключателей, позволяющих вводить данные, и еще один — для переключателя «Запись». Ниже показана схема.
Когда переключатель «Перехват» разомкнут (как показано на рисунке), на входы массива RAM 64 Кбайт × 8 «Адрес», «Данные» и «Запись» поступают сигналы извне, как показано над левым верхним углом блока селекторов «2 на 1». Когда переключатель «Перехват» замкнут, сигналы на входы массива RAM «Адрес», «Данные» и «Запись» поступают от переключателей на пульте управления. В любом случае сигналы «Вывод данных» из массива RAM поступают на восемь лампочек и, вероятно, куда-нибудь еще.
Массив RAM 64 Kбайт × 8 с таким пультом управления можно изобразить следующим образом.
Когда переключатель «Перехват» замкнут, вы можете использовать 16 переключателей «Адрес» для выбора любого из 65 536 адресов. Лампочки показывают 8-битное значение, которое в настоящий момент хранится в памяти по этому адресу. Вы можете использовать восемь переключателей «Данные» для задания нового значения, а записать это значение в память с помощью переключателя «Запись».
Массив RAM 64 Kб × 8 и пульт управления, безусловно, помогут вам отследить любое из 65 536 8-битных значений, которое может понадобиться. Однако эта конструкция также позволяет некоторым другим схемам использовать значения, которые мы сохранили в памяти, и записывать в нее новые.
Есть еще одна важная деталь, которую необходимо знать о памяти: когда в главе 11 вы познакомились с концепцией вентилей, я перестал рисовать отдельные реле, из которых состоят эти вентили. В частности, с тех пор я больше не указывал на схемах, что каждое реле подключено к какому-то источнику питания. Всякий раз при срабатывании реле электричество течет через катушку электромагнита и удерживает металлический контакт на месте.
Итак, у вас есть массив RAM 64 Kб × 8, весь объем которого заполнен вашими любимыми байтами. Что произойдет, если вы отключите его от источника питания? Все электромагниты потеряют свои магнитные свойства, и с громким щелчком все контакты реле вернутся в свое исходное положение. А содержимое этой памяти? Оно исчезнет навсегда!
Вот почему память с произвольным доступом также называется энергозависимой. Для хранения содержимого ей требуется постоянное энергоснабжение.