Глава 22
Операционная система
Наконец мы собрали нечто напоминающее полноценный компьютер, по крайней мере мысленно. Он оснащен микропроцессором, оперативной памятью, клавиатурой, монитором и жестким диском. Все оборудование на месте, и мы с нетерпением смотрим на кнопку включения, которая его оживит. Вероятно, этот проект напомнил, как Виктор Франкенштейн собирал своего монстра, как папа Карло строгал Буратино.
И все же нам чего-то не хватает. И отнюдь не молнии, не заклинаний. Включите этот новый компьютер и скажите, что вы видите.
По мере разогрева электронно-лучевой трубки на экране отобразится массив идеально оформленных, но совершенно случайных символов ASCII. Это мы и ожидали. Полупроводниковая память теряет свое содержимое при отключении питания, а при следующем включении приходит в случайное и непредсказуемое состояние. Вся созданная нами для микропроцессора память RAM — случайный набор байтов. Микропроцессор воспринимает этот набор как машинный код и начинает с ним работать, что не приведет к нежелательным последствиям, в частности компьютер не взорвется, — однако не будет и пользы.
Нам не хватает программного обеспечения. При первом включении или перезагрузке микропроцессор обращается к машинному коду, начиная с ячейки памяти с определенным адресом. В случае Intel 8080 это 0000h. При включении правильно спроектированного компьютера адрес памяти должен содержать машинную инструкцию (вероятно, первую из многих).
Как эта инструкция туда попадает? Процесс записи программного обеспечения в новый компьютер является, вероятно, одним из наиболее запутанных этапов. Один из способов решения этой задачи предполагает использование пульта управления, аналогичного описанному в главе 16, где он применялся для записи байтов в оперативную память и их последующего считывания.
В отличие от описанного ранее пульта управления, этот имеет переключатель «Сброс», который подключен к одноименному входу микропроцессора. Пока этот переключатель замкнут, микропроцессор ничего не делает. После размыкания переключателя микропроцессор обращается к машинному коду.
Чтобы использовать этот пульт управления, замкните переключатель «Сброс» для остановки микропроцессора, а переключатель «Перехват» — для перехвата управления адресными линиями и линиями данных шины. Теперь вы можете использовать переключатели с A0 по A15 для указания 16-разрядного адреса памяти. Лампочки с D0 по D7 показывают 8-битное содержимое этого адреса. Чтобы записать сюда новое значение, введите нужный адрес с помощью переключателей с D0 по D7, а затем последовательно замкните и разомкните переключатель «Запись». Закончив ввод новых данных в память, разомкните переключатели «Перехват» и «Сброс», и микропроцессор начнет выполнять программу.
Таким образом следует вводить первые машинные инструкции в только что собранный компьютер. Разумеется, это потребует больших усилий. Безусловно, время от времени вы будете ошибаться. Пальцы покроются мозолями, мозги закипят, но это издержки профессии.
Когда на дисплее увидите результаты работы своих программ, все усилия будут вознаграждены. Текстовый дисплей, который мы собрали в предыдущей главе, имеет видеопамять емкостью один килобайт для хранения текстов в кодировке ASCII объемом 25 строк по 40 символов каждая. Программа записывает данные в эту память так же, как в любую другую.
Однако вывести результат программы на дисплей не так просто, как может показаться. Например, если ваша программа совершает некоторые вычисления, в результате которых получается 4Bh, вы не можете просто записать это значение в видеопамять. В этом случае на экране отобразилась бы буква K, поскольку именно ей соответствует код ASCII 4Bh. Вместо этого вам нужно записать в видеопамять два символа ASCII: 34h — код ASCII для цифры 4 и 42h — код ASCII для буквы B. Каждая тетрада 8-битного результата — шестнадцатеричное значение, которое должно отображаться на экране.
Вероятно, придется написать небольшую подпрограмму для выполнения этого преобразования. Приведем одну из таких подпрограмм на языке ассемблера для микропроцессоров 8080, которая преобразует записанную в аккумуляторе тетраду (предполагается, что это значение находится в диапазоне от 00h до 0Fh включительно) в соответствующий ей код ASCII.
Следующая подпрограмма дважды вызывает подпрограмму NibbleToAscii для преобразования байта, записанного в аккумуляторе A, в две цифры ASCII и их записи в регистры B и C.
Эти подпрограммы теперь позволяют отобразить на дисплее байт в шестнадцатеричном формате. Если захотите преобразовать значение в десятичный формат, потребуется еще немного поработать. На самом деле этот процесс похож на то, как люди переводят значение из шестнадцатеричной системы счисления в десятичную путем многократного деления на 10.
Помните: фактически вы не вводите в память эти программы на ассемблере. Вместо этого вы пишете их на бумаге, а затем преобразуете в машинный код, который вводите в память. Мы продолжим заниматься такой «ручной сборкой» вплоть до главы 24.
Несмотря на то что с аппаратной точки зрения пульт управления прост, им неудобно пользоваться. Это наихудший из когда-либо разработанных способов ввода и вывода данных. Досадно, что нам хватило ума собрать с нуля собственный компьютер, но теперь мы вынуждены вводить значения в двоичном формате. Так что первым делом следует избавиться от пульта управления.
Конечно, его нужно заменить клавиатурой. Собранная ранее клавиатура прерывала работу микропроцессора при нажатии клавиши. Контроллер прерываний, который мы использовали, заставляет микропроцессор ответить на прерывание путем исполнения команды RST (Restart, «Перезагрузка»). Предположим, это команда RST1, и она заставляет микропроцессор сохранить текущее значение счетчика команд в стеке, а затем перейти по адресу 0008h. Начиная с этой ячейки, используя пульт управления, вы вводите некоторый код, который будем называть обработчиком клавиатуры.
Чтобы все работало правильно, понадобится код, который будет выполняться при перезагрузке микропроцессора, — код инициализации. Этот код сначала устанавливает указатель стека так, чтобы тот находился в допустимой области памяти, затем записывает во все ячейки видеопамяти шестнадцатеричное значение 20h, которое соответствует пробелу в кодировке ASCII. Это очищает экран от всех случайных символов.
Код инициализации использует команду OUT (Output, «Вывод») для установки курсора — символа подчеркивания, который обозначает место ввода следующего символа, — в первый столбец первой строки. Следующая команда EI разрешает обслуживание прерываний, благодаря чему микропроцессор может реагировать на сигналы прерывания клавиатуры. За ней следует команда HLT, останавливающая работу микропроцессора.
С кодом инициализации все готово. С этого момента компьютер в основном будет находиться в состоянии останова в результате выполнения инструкции HLT. Единственное событие, которое может вывести компьютер из этого состояния, — замыкание переключателя «Сброс» на пульте управления или прерывание от клавиатуры.
Код обработчика намного длиннее кода инициализации. Именно он отвечает за выполнение всех по-настоящему полезных функций.
При каждом нажатии клавиши на клавиатуре сигнал прерывания заставляет микропроцессор перейти от команды HLT в конце кода инициализации к обработчику клавиатуры, использующему инструкцию IN (Input, «Ввод») для определения нажатой клавиши, а затем производит некое действие в зависимости от нажатой клавиши (то есть обрабатывает ее нажатие) и выполняет команду RET (Return, «Возврат») для возвращения процессора к команде HLT, где он будет ожидать следующего прерывания.
Если нажатой клавише соответствует буква, цифра или знак препинания, обработчик клавиатуры использует скан-код, чтобы определить соответствующий код ASCII с учетом того, была ли нажата клавиша Shift. Впоследствии он записывает этот код ASCII в видеопамять в соответствии с позицией курсора. Эта процедура называется эхо — отображение на экране символов, соответствующих нажатым клавишам. Курсор сдвигается на одну позицию вправо, располагаясь сразу после только что выведенного на экран символа. Таким образом в клавиатуру можно ввести множество символов, и они будут отображены на экране.
Если была нажата клавиша Backspace (соответствующая коду ASCII 08h), обработчик клавиатуры стирает последний записанный в видеопамять символ и перемещает курсор на одну позицию назад. (Стирание символа происходит путем записи кода ASCII 20h (символ пробела) в конкретную ячейку памяти.)
Обычно человек, работающий с клавиатурой, набирает символьную строку, пользуясь клавишей Backspace для исправления ошибок, а затем нажимает клавишу Return, часто обозначаемую словом Enter. Точно так же, как нажатие клавиши Return на электрической пишущей машинке указывает на необходимость перехода к началу следующей строки, нажатие Enter означает, что пользователь закончил набирать строку текста.
Когда обработчик клавиатуры взаимодействует с клавишей Return, или Enter (которая соответствует коду ASCII 0Dh), строка текста в видеопамяти интерпретируется как команда компьютеру, указание выполнить некое действие. Обработчик клавиатуры включает командный процессор, который понимает, например, три команды: W, D и R.
Если строка текста начинается с буквы W, она соответствует команде «Записать» (Write) некоторые байты в память. Допустим, на экране введена следующая строка.
W 1020 35 4F 78 23 9B AC67
Эта команда сигнализирует командному процессору, что нужно записать шестнадцатеричные байты 35, 4F в адреса памяти начиная с 1020h. Для выполнения этого задания обработчик клавиатуры должен перевести коды ASCII в байты. Такая трансформация обратна той, что я продемонстрировал ранее.
Если строка текста начинается с буквы D, она соответствует команде «Отобразить» (Display) некоторые из содержащихся в памяти байтов. В ответ на строку командный процессор отображает на экране 11 байт, хранящихся в ячейках памяти начиная с 1030h.
D1030
Я упоминаю 11 байт, потому что именно столько уместится в строке шириной в 40 символов после адреса. Вы можете использовать команду «Отобразить» для просмотра содержимого памяти.
Если строка текста начинается с буквы R, то она соответствует команде Run («Запустить»). Эта команда выглядит так:
R1000
и означает: «Запустить программу, которая хранится в ячейках памяти начиная с адреса 1000h». Командный процессор сохраняет адрес 1000h в пару регистров HL, затем выполняет команду PCHL, которая загружает в счетчик команд содержимое регистров HL, при этом осуществляется переход к соответствующему адресу.
Создание работоспособного обработчика клавиатуры и командного процессора — шаг вперед. После этого вам больше не придется мучиться с пультом управления. Ввод данных с клавиатуры проще, быстрее и аккуратнее.
Конечно, все еще остается нерешенной проблема исчезновения написанного кода при отключении питания. По этой причине вы, вероятно, решите хранить весь этот новый код в постоянной памяти, или ПЗУ. В предыдущей главе мы обсуждали микросхему ПЗУ, содержащую все комбинации точек, необходимые для отображения на экране символов ASCII, и предположили, что эти данные были «зашиты» в нашу микросхему при ее производстве. Вы также можете программировать микросхемы ПЗУ дома. Программируемые постоянные запоминающие устройства (ППЗУ) можно запрограммировать только один раз. Стираемые программируемые постоянные запоминающие устройства (СППЗУ) можно программировать и перепрограммировать после полного удаления данных ультрафиолетовым излучением.
Как вы помните, мы оснастили платы RAM DIP-переключателем, который позволяет указать ее начальный адрес. Если вы работаете с системой 8080, то для одной из плат RAM начальным адресом будет 0000h. После подключения микросхемы ПЗУ она займет адрес 0000h, а плату RAM можно будет переключить.
Создание командного процессора — серьезная веха не только потому, что он позволяет быстрее записывать байты в память, но и потому, что компьютер становится интерактивным. Когда вы вводите символы с клавиатуры, компьютер реагирует и отображает их на экране.
После записи командного процессора в ПЗУ вы можете начать экспериментировать с записью данных из памяти на жесткий диск (вероятно, фрагментами, размер которых соответствует размеру сектора диска) и считыванием этих данных обратно в память. Хранить программы и данные на диске намного безопаснее, чем в оперативной памяти, где они исчезнут в случае отключения питания, и гораздо удобнее, чем в ПЗУ.
Рано или поздно вам захочется добавить в командный процессор новое. Например, команда S означает Store («Сохранить»):
S2080 2 15 3
и указывает, что блок памяти, начинающийся с ячейки 2080h, должен быть сохранен на диске по адресу: сторона 2, дорожка 15, сектор 3. (Размер этого блока памяти зависит от размера сектора диска.) Аналогично вы можете добавить команду Load («Загрузить»), чтобы загрузить данные этого сектора с диска обратно в память.
L 2080 2 15 3
Разумеется, придется помнить, что и где вы храните. Для этого вы, вероятно, попробуете использовать блокнот и карандаш. Имейте в виду: нельзя просто сохранить код в ячейке памяти с определенным адресом, а затем загрузить его в ячейку памяти с другим адресом и ожидать, что он будет работать. Все команды Jump («Переход») и Call («Вызов») окажутся неправильными, поскольку в них записаны старые адреса. Кроме того, объем кода вашей программы может превысить размер сектора диска, поэтому придется хранить его в нескольких. Поскольку одни сектора на диске могут быть заняты другими программами или данными, а вторые быть свободными, сектора, в которых вы храните длинную программу, могут располагаться на диске непоследовательно.
Рано или поздно вы решите, что вручную отслеживать содержимое секторов диска слишком утомительно. Это будет означать, что вы дозрели до создания файловой системы.
Файловая система — способ хранения данных, при котором они организуются в файлы. Файл — это просто набор связанных данных, который занимает один или несколько секторов на диске. Самое главное, что у каждого файла собственное имя, помогающее определить его содержимое. Диск похож на шкаф для хранения документов, где каждая папка имеет этикетку с названием.
Файловая система почти всегда входит в состав более крупной совокупности программного обеспечения — операционной системы. Обработчик клавиатуры и командный процессор, которые мы написали в этой главе, безусловно, могли бы эволюционировать в операционную систему. Однако вместо моделирования этого длительного процесса рассмотрим настоящую операционную систему (ОС) и постараемся разобраться, что она делает, как работает.
Исторически наиболее важной операционной системой для 8-битных микропроцессоров была CP/M (Control Program for Micros, управляющая программа для микрокомпьютеров), написанная в середине 1970-х для Intel 8080 Гэри Килдаллом (1942–1994), который позднее основал компанию Digital Research Incorporated (DRI).
На диске хранилась CP/M. На заре использования этой ОС наиболее распространенным носителем для нее была односторонняя 8-дюймовая дискета с 77 дорожками, 26 секторами на дорожке и 128 байтами в секторе (всего 256 байт). На первых двух дорожках диска содержалась сама CP/M. Чуть позже расскажу о том, как CP/M с диска переместилась в память компьютера.
Остальные 75 дорожек на диске CP/M использовались для хранения файлов. Файловая система CP/M довольно проста. Она удовлетворяет двум основным требованиям. Во-первых, каждый файл на диске имеет имя, которое тоже хранится на диске. На самом деле вся информация, которая требуется CP/M для считывания этих файлов, хранится на диске вместе с самими файлами. Во-вторых, файлы не обязательно должны занимать последовательные сектора. Часто при создании и удалении файлов разного размера свободное место на диске становится фрагментированным. Так что способность файловой системы хранить большой объем информации в несмежных секторах оказывается полезной.
Сектора на 75 дорожках, используемые для хранения файлов, сгруппированы в блоки выделения памяти. Каждый блок содержит восемь секторов, или 1024 байта. Всего на диске 243 блока выделения памяти, пронумерованных от 0 до 242.
Первые два блока выделения памяти (всего 2048 байт) отведены под каталог. Каталог — область диска, содержащая имена и некоторую важную информацию о каждом хранящемся файле. Каждому файлу на диске соответствует элемент каталога длиной 32 байта. Поскольку общий объем каталога всего 2048 байт, дискета может хранить 64 файла (2048 / 32).
Каждая 32-байтная запись каталога содержит следующую информацию.
Байты
Значение
0
Обычно равен 0
1–8
Имя файла
9–11
Тип файла
12
Экстент
13–14
Зарезервированы (равны 0)
15
Количество секторов в последнем блоке
16–31
Карта диска
Первый байт элемента каталога применяется только в том случае, когда с файловой системой работают два человека и более. В операционной системе CP/M этот байт обычно равен 0, как и байты тринадцатый и четырнадцатый.
В CP/M каждому файлу присваивается имя, состоящее из двух частей. Первая часть — имя файла — может содержать до восьми символов, хранящихся в байтах с первого по восьмой элемент каталога; вторая часть — тип файла — может содержать до трех символов, хранящихся в байтах с девятого по одиннадцатый. Существует несколько стандартных типов файлов. Например, TXT говорит о том, что файл является текстовым (содержит только коды ASCII), а COM (от command — «команда») указывает, что файл содержит машинные инструкции для процессора 8080, то есть программу. При указании конкретного файла эти две части разделяются точкой.
MYLETTER.TXT
CALC.COM
Этот метод наименования файлов известен как формат 8.3 («восемь точка три»), допускающий максимум восемь букв до точки и три буквы после.
Карта диска в элементе каталога указывает блоки выделения памяти, где хранится файл. Предположим, что значениями первых четырех байтов карты диска являются 14h, 15h, 07h и 23h, а значениями остальных — нули. Значит, файл занимает четыре блока, или четыре килобайта дискового пространства. Объем файла может быть немного меньше. Пятнадцатый байт в элементе каталога указывает, сколько 128-байтовых секторов фактически занято в последнем блоке.
Длина карты диска — 16 байт, и их достаточно для указания местоположения файла объемом до 16 384 байт. Для файла объемом более 16 килобайт необходимо использовать несколько элементов каталога, которые называются экстентами. В этом случае двенадцатый байт будет равен 0 в первом элементе каталога, 1 — во втором и т. д.
Ранее я упомянул текстовые файлы, которые также называются ASCII-файлами и содержат коды ASCII (включая коды возврата каретки и перевода строки), которые соответствуют понятным людям текстовым символам. Файл, который не является текстовым, называется двоичным. Файл СP/M типа COM — двоичный, поскольку содержит машинный код для процессора 8080.
Предположим, нам нужно сохранить в файле (очень маленького объема) три 16-битных числа, например 5A48h, 78BFh и F510h. Двоичный файл с этими тремя числами имеет длину всего шесть байт.
48 5A BF 78 10 F5
Разумеется, это формат хранения многобайтовых чисел для процессоров Intel. Первым указывается младший байт. Программа, написанная для процессоров Motorola, сохранила бы эти числа следующим образом.
5A 48 78 BF F5 10
В текстовом файле ASCII эти же четыре 16-битных значения были бы записаны, как показано ниже.
35 41 34 38 68 0D0A 37 38 42 46 68 0D0A 46 35 31 30 68 0D0A
Эти байты — коды ASCII для цифр и букв, а сами числа разделяются кодами возврата каретки (0Dh) и перевода строки (0A). Текстовый файл удобнее отображать не в виде строки кодов ASCII, а в виде соответствующих им символов.
5A48h
78BFh
F510h
Текстовый файл ASCII, в котором хранятся эти три числа, также может содержать следующие байты.
32 33 31 31 32 0D0A 33 30 39 31 31 0D0A 36 32 37 33 36 0D0A
Коды ASCII для десятичных эквивалентов трех чисел следующие.
23112
30911
62736
Поскольку текстовые файлы призваны упростить людям процесс чтения их содержимого, нет причин для отказа от использования десятичных чисел вместо шестнадцатеричных.
Как я уже упоминал, сама CP/M записана на первых двух дорожках диска. Для запуска системы ее необходимо загрузить с диска в память. Объем ПЗУ в компьютере, использующем CP/M, не обязательно будет большим. В ПЗУ должен содержаться небольшой фрагмент кода, известный как загрузчик программы. Этот загрузчик считывает самый первый 128-байтовый сектор с дискеты в память и запускает его. Этот сектор содержит код для загрузки в память остальной части CP/M. Весь процесс называется загрузкой операционной системы.
В результате система CP/M размещается в оперативной памяти с самыми старшими адресами. После загрузки CP/M память будет организована так.
Эта схема не отражает реального масштаба. Три компонента CP/M: базовая система ввода/вывода (Basic Input/Output System, BIOS), базовая дисковая операционная система (Basic Disk Operating System, BDOS) и консольный командный процессор (Command and Control Processor, CCP) — занимают в общей сложности около шести килобайт памяти. Область нерезидентных программ — около 58 килобайт памяти на компьютере с оперативной памятью 64 килобайта — изначально не содержит ничего.
Консольный командный процессор эквивалентен командному процессору, созданному нами ранее. Словом, консоль обозначает совокупность клавиатуры и дисплея. Консольный процессор отображает на дисплее следующее приглашение.
A>
Приглашение — это сигнал, означающий возможность ввести некую команду. На компьютерах с несколькими дисками буква A указывает на первый диск, с которого была загружена система CP/M. Вы вводите команды после приглашения и нажимаете клавишу Enter. Затем процессор CCP выполняет эти команды, в результате чего на экране обычно отображается некоторая информация. После завершения консольный процессор снова отобразит приглашение.
Процессор CCP распознает лишь несколько команд. Вероятно, наиболее важна следующая команда.
DIR
Эта команда отображает на экране содержимое каталога диска, то есть список всех хранящихся на диске файлов. Вы можете использовать специальные символы «?» и «*», чтобы отобразить только файлы с определенным именем или типом. Следующая команда, например, отображает текстовые файлы.
DIR *.TXT
Список всех файлов с именами из пяти символов, в которых первый символ — буква A, а последний — B, передает такая команда.
DIR A??? B.*
Еще одна важная команда — ERA (Erase, «Удалить»). Она используется для удаления файла с диска.
ERA MYLETTER.TXT
Следующая команда удаляет все текстовые файлы.
ERA *.TXT
Удаление файла означает освобождение соответствующего элемента каталога и дискового пространства.
Команда REN (Rename, «Переименовать») используется для изменения имени файла. Команда TYPE («Напечатать») показывает содержимое текстового файла. Поскольку текстовый файл содержит только ASCII-коды, эта команда позволяет читать файл прямо с экрана.
TYPE MYLETTER.TXT
Команда SAVE («Сохранить») сохраняет один или несколько 256-байтовых блоков памяти, расположенных в области временного хранения программ, в файл с указанным именем на диске.
Если вы введете команду, которую CP/M не сможет распознать, система будет интерпретировать данные в качестве имени программы, которая хранится на диске в виде файла. Файлы программ всегда имеют тип COM. Процессор CCP ищет файл с таким именем на диске. Если он существует, система CP/M загрузит файл с диска в область временного хранения программ, которая начинается с адреса памяти 0100h. Так запускаются программы, хранящиеся на диске. Например, если вы наберете
CALC
в ответ на приглашение CP/M, то если на диске присутствует файл с именем CALC.COM, процессор CCP загрузит этот файл в память начиная с адреса 0100h, а затем выполнит программу, перейдя к машинной инструкции, расположенной по адресу 0100h.
Ранее я объяснил, как можно вставить машинные инструкции в любую область памяти и выполнить их, однако в случае CP/M программы, которые хранятся в файлах на диске, должны предусматривать загрузку в память, начиная с определенного адреса — 0100h.
Система CP/M поставляется с несколькими полезными программами, включая PIP (Peripheral Interchange Program — программа взаимодействия с периферией), которая позволяет копировать файлы. Программа ED — текстовый редактор, который помогает создавать и изменять текстовые файлы. Программы вроде PIP и ED, имеющие небольшой объем и предназначенные для решения простых задач, часто называются служебными, или утилитами. Будучи пользователем системы CP/M, вы, вероятно, приобрели бы более крупные программы-приложения, например текстовые процессоры, электронные таблицы, или написали бы их самостоятельно. Все эти программы также хранятся в файлах типа COM.
Итак, мы разобрались с командами и утилитами CP/M, которые (как и в большинстве операционных систем) позволяют осуществлять элементарное управление файлами. Мы также поняли, как CP/M загружает программные файлы в память и выполняет их. Однако у операционной системы есть еще одна важная функция.
Программе, работающей под управлением CP/M, часто требуется вывести что-то на экран, считать то, что вы набрали на клавиатуре, прочитать файл с диска или записать его на диск. Однако в большинстве случаев программа не записывает свои выходные данные непосредственно в видеопамять, не может получить доступ к аппаратному обеспечению клавиатуры, чтобы узнать, что вы набрали, и, конечно, не имеет доступа к оборудованию жесткого диска для чтения и записи его секторов.
Вместо этого программа, работающая под управлением CP/M, использует набор подпрограмм, встроенных в ОС для решения этих распространенных задач. Подобные подпрограммы были специально разработаны так, чтобы программы могли легко получить доступ ко всему оборудованию компьютера, включая монитор, клавиатуру и диск, не заставляя программистов беспокоиться, как эти периферийные устройства соединены. Главное, что программе, работающей под управлением CP/M, необязательно знать о дисковых секторах и дорожках. Это работа системы CP/M. Вместо этого она может сохранять целые файлы на диске, а затем считывать их.
Третья основная функция операционной системы — это предоставление программе легкого доступа к аппаратным средствам компьютера, то есть ее обеспечение интерфейсом прикладного программирования (Application Programming Interface, API).
Программа, работающая под управлением CP/M, использует API, сохраняя в регистре C определенное значение (называемое номером функции) и выполняя следующую команду.
CALL 5
Например, программа получает ASCII-код нажатой на клавиатуре клавиши путем выполнения представленных ниже команд.
MVI C, 01h
CALL 5
В результате ASCII-код нажатой клавиши будет содержаться в аккумуляторе A. Аналогично команды, указанные ниже, выводят на экран символ, соответствующий ASCII-коду, содержащемуся в аккумуляторе A, сдвигая курсор на одну позицию.
MVI C, 02h
CALL 5
Если программе требуется создать файл, она сохраняет в паре регистров DE адрес области памяти, которая содержит имя файла, а затем выполняет код.
MVI C, 16h
CALL 5
В данном случае в ответ на команду CALL 5 CP/M создает на диске пустой файл. Затем программа может использовать другие функции для того, чтобы записать в этот файл новые данные и закрыть его, или закончить работу. Эта же или другая программа может позднее открыть данный файл и прочитать его содержимое.
Что же делает команда CALL 5? В CP/M в ячейке памяти по адресу 0005h хранится инструкция JMP (Jump), которая осуществляет переход в область памяти, выделенной для базовой дисковой операционной системы (BDOS). В этой области содержится множество подпрограмм, которые выполняют каждую из функций CP/M. Базовая дисковая операционная система, как следует из ее названия, в первую очередь отвечает за поддержание работы файловой системы. Часто BDOS использует подпрограммы, находящиеся в базовой системе ввода/вывода (BIOS) — области, которая фактически обращается к аппаратным средствам клавиатуры, монитора и дисков. На самом деле BIOS — это единственный раздел системы CP/M, которому требуется информация об аппаратном обеспечении компьютера. Консольный командный процессор, а также служебные программы, поставляемые с CP/M, осуществляют работу, используя функции BDOS.
API является независимым от устройства интерфейсом, а это значит, что программе, написанной для системы CP/M, не обязательно «знать» механику работы клавиатуры или монитора конкретного компьютера, а также чтения и записи секторов диска. Она просто использует функции CP/M для решения задач, связанных с клавиатурой, монитором и диском. Приятное дополнение: программа CP/M способна работать на разных компьютерах, которые могут использовать различные аппаратные средства для доступа к этим периферийным устройствам. Тем не менее всем программам CP/M требуется микропроцессор Intel 8080 или процессор, понимающий инструкции 8080, например Intel 8085 или Zilog Z-80. Пока на компьютере работает CP/M, программа использует функции этой системы для опосредованного доступа к аппаратному обеспечению. Без стандартных API-интерфейсов программы нужно было бы специально подстраивать под разные типы компьютеров.
Когда-то CP/M была популярной операционной системой для микропроцессоров 8080, и ее важность для истории несомненна. Эта система существенно повлияла на 16-битную операционную систему под названием QDOS (Quick and Dirty Operating System — операционная система «на скорую руку»), написанную Тимом Патерсоном из Seattle Computer Products для 16-разрядных микропроцессоров 8086 и 8088 компании Intel. В итоге система QDOS была переименована в 86-DOS и куплена корпорацией Microsoft. MS-DOS (Microsoft Disk Operating System — дисковая операционная система Microsoft) устанавливалась на первых персональных компьютерах IBM, выпущенных в 1981 году. Несмотря на то что 16-разрядная версия CP/M (под названием CP/M-86) также была доступна для IBM PC, стандартом быстро стала именно система MS-DOS. Лицензии на установку MS-DOS (которая называлась PC-DOS на компьютерах IBM) также продавались другим производителям IBM-совместимых компьютеров.
МS-DOS не унаследовала файловую систему CP/M, а использовала схему, названную таблицей размещения файлов (File Allocation Table, FAT), которую изобрели в Microsoft в 1977 году. Суть этой схемы в том, что дисковое пространство разделено на кластеры, размер которых в зависимости от емкости диска может варьироваться от 512 до 16 384 байт. Каждый файл — это набор кластеров. В соответствующем файлу элементе каталога указывается только его начальный кластер. В самой таблице FAT для каждого кластера на диске указывается, где находится продолжение файла.
Элементы каталога на диске MS-DOS имеют длину 32 байта и используют ту же систему наименования файлов 8.3, что и CP/M. Однако терминология здесь несколько иная: последние три буквы называются расширением, а не типом файла. В элементе каталога MS-DOS нет списка блоков выделения памяти. Вместо этого каталог содержит такую полезную информацию, как дата и время последнего изменения файла, а также его размер.
Ранние версии MS-DOS структурно напоминали CP/M. Однако система MS-DOS не нуждалась в BIOS, поскольку она уже содержалась в ПЗУ компьютера. Командный процессор MS-DOS — это файл с именем COMMAND.COM. Программы MS-DOS выпускаются в двух вариантах. Размер программ с расширением COM ограничен 64 килобайтами, более крупные имеют расширение EXE.
Несмотря на то что изначально система MS-DOS поддерживала интерфейс CALL 5 для функций API, для новых программ был рекомендован обновленный интерфейс, использующий механизм программных прерываний, который напоминает вызов подпрограммы, за исключением того, что этой программе необязательно знать фактический адрес, к которому она обращается. Программа вызывает функцию API-интерфейса MS-DOS, выполняя команду INT 21h.
Теоретически прикладные программы должны получать доступ к аппаратному обеспечению компьютера только через интерфейсы, предоставляемые операционной системой. Однако многие программисты, которые создавали прикладные программы для небольших компьютеров 1970-х годов и начала 1980-х, часто обходили эту операционную систему, особенно в плане работы с дисплеем. Программы, которые непосредственно записывали байты в видеопамять, выполнялись быстрее, чем программы, которые этого не делали. Действительно, для некоторых приложений, особенно для тех, которым необходимо отображать на экране графику, эта операционная система была совершенно неприемлемой. В MS-DOS многим программистам больше всего нравилось, что она «не путалась под ногами» и давала возможность писать настолько быстрые программы, насколько позволяло аппаратное обеспечение.
По этой причине популярное программное обеспечение, работающее на компьютере IBM PC, часто опиралось на особенности его оборудования. Производители компьютеров, желавшие конкурировать с IBM, были вынуждены копировать эти особенности, в противном случае некоторые популярные программы на их компьютерах могли работать неэффективно или не работать вообще. Требования к оборудованию для таких программ часто включали пункт «IBM PC или 100%-совместимый компьютер».
В версию MS-DOS 2.0, выпущенную в марте 1983 года, была добавлена поддержка жестких дисков, в то время небольших (по сегодняшним меркам), однако их емкость стремительно увеличивалась. Чем больше емкость диска, тем больше файлов на нем можно хранить. А чем больше файлов может вместить диск, тем сложнее найти конкретный файл или использовать какой-либо метод их организации.
Решением этой проблемы в MS-DOS 2.0 стала иерархическая файловая система, которая была добавлена в уже существующую файловую систему с минимальным количеством изменений. Как вы помните, на диске есть область, называемая каталогом, который представляет собой список файлов и содержит информацию о том, где они хранятся. В иерархической файловой системе некоторые из этих файлов сами могут быть каталогами, то есть файлами, содержащими список других файлов. Некоторые из этих файлов также могут быть каталогами. Обычный каталог на диске называется корневым каталогом. Каталоги, содержащиеся в других каталогах, называются подкаталогами. Каталоги (иногда называемые папками) позволяют группировать связанные между собой файлы.
Иерархическая файловая система и некоторые другие функции MS-DOS 2.0 были позаимствованы из операционной системы UNIX, которая была разработана в начале 1970-х годов в Bell Telephone Laboratories. Ее основные авторы — Кен Томпсон (род. 1943) и Деннис Ритчи (1941–2011). UNIX изначально создавалась в качестве облегченной версии более ранней операционной системы Multics (Multiplexed Information and Computing Services), которую корпорация Bell Labs разрабатывала совместно с Массачусетским технологическим институтом и General Electric.
UNIX — излюбленная операционная система олдскульных программистов. В то время как большая часть операционных систем создается для конкретных компьютеров, UNIX разрабатывалась как переносимая операционная система, то есть способная адаптироваться под различные компьютеры.
Во времена разработки UNIX Bell Labs принадлежала компании American Telephone & Telegraph, поэтому на нее распространялись судебные постановления, призванные ограничить монопольное положение AT&T в телефонной отрасли. Первоначально AT&T было запрещено продавать UNIX; компания была вынуждена выдавать лицензии на ее использование другим организациям. Так что начиная с 1973 года такие лицензии были выданы многим университетам, корпорациям и правительственным организациям. В 1983 году AT&T наконец вернулась в компьютерный бизнес, выпустив собственную версию UNIX.
Именно поэтому единой модификации UNIX не существует. Есть различные версии под разными названиями, которые работают на различных компьютерах и продаются разными поставщиками. Многие люди внесли свой вклад в разработку UNIX. Те, кто добавляет новые элементы в данную систему, по-видимому, руководствуются преобладающей философией UNIX. Часть этой философии — широкое использование текстовых файлов. Многие служебные программы UNIX читают текстовые файлы, что-то с ними делают, а затем создают другой текстовый файл. Утилиты UNIX можно объединить в цепочки для выполнения разнообразных действий над этими текстовыми файлами.
UNIX изначально писалась для компьютеров, которые были слишком большими и дорогими для одного пользователя. С такими компьютерами могут одновременно взаимодействовать несколько пользователей благодаря технологии под названием «разделение времени». Ее суть следующая: к компьютеру подключается несколько дисплеев с клавиатурами, которые называются терминалами. Быстро переключаясь между всеми терминалами, операционная система может создать впечатление, будто компьютер одновременно обслуживает всех пользователей.
Операционная система, которая способна одновременно выполнять несколько программ, называется многозадачной. Очевидно, что сложность такой ОС значительно превышает сложность однозадачных CP/M и MS-DOS. Многозадачность усложняет файловую систему, поскольку несколько пользователей могут попытаться одновременно использовать одни и те же файлы. Кроме того, многозадачность влияет на то, как компьютер выделяет память различным программам, поэтому такой операционной системе требуется механизм управления памятью. Поскольку нескольким работающим одновременно программам необходимо больше памяти, существует вероятность, что у компьютера возникнет ее дефицит. Для решения этой проблемы в операционной системе можно реализовать технологию под названием виртуальная память: ненужные в данный момент блоки хранятся во временных файлах на диске, а затем возвращаются в память, когда в них возникает необходимость (для этого используется так называемый файл подкачки, хранящийся на жестком диске).
Наиболее интересными явлениями в мире UNIX в последние годы стали Фонд свободного программного обеспечения (Free Software Foundation, FSF) и проект GNU, основанные Ричардом Столлманом. Аббревиатура GNU является акронимом выражения GNU’s Not UNIX («GNU не UNIX»), что, разумеется, правда. Вместо этого программы, разработанные в рамках проекта GNU, являются совместимыми с операционной системой UNIX, однако распространяются так, что не могут стать чьей-либо собственностью. Благодаря проекту GNU появилось множество UNIX-совместимых служебных программ и инструментов, а также Linux — ядро операционной системы, совместимой с UNIX. Главный создатель ставшего в последние годы популярным ядра Linux — Линус Торвальдс, американский программист из Финляндии.
Однако главная тенденция в развитии ОС, зародившаяся в середине 1980-х, — это разработка таких крупных и сложных систем, как Apple Macintosh и Microsoft Windows, где графические пользовательские интерфейсы и широкие возможности видеосистем применяются для упрощения работы с приложениями. Эту тенденцию я опишу в главе 25.