BAULA1 (1110624), страница 24
Текст из файла (страница 24)
При использовании шины устройствами может возникать конфликт, когда два или более устройств захотят одновременно обмениваться данными. Для разрешения таких конфликтов предназначен арбитр шины – специальныя электронная схема, которая обычно располагается на одном из концов шины. Разрешение конфликтов производится по принципу приоритетов устройств, – устройству с большим приоритетом арбитром отдаётся предпочтение при конфликте. В простейшем случае приоритеты устройствам явно не назначаются, просто считается, что из двух устройств то имеет больший приоритет, которое расположено на шине ближе к арбитру. Исходя из этого, более "важные" устройства стараются подключить к шине поближе к арбитру.
Разберём схему обмена данными между двумя устройствами с помощью общей шины. Сначала ведущее устройство (инициатор обмена) делает так называемый запрос шины, т.е. посылает арбитру сигнал о желании начать обмен данными (или же читает из специального регистра флаг-признак занятости шины). Если шина занята, то устройство вынуждено ждать её освобождения, а если шина свободна, то устройство производит операцию захвата шины в своё монопольное использование.
После захвата шины ведущее устройство определяет, готово ли ведомое устройство для обмена данными. Для этого ведущее устройство посылает ведомому устройству специальный сигнал, или же читает из порта ведомого устройства его флаг готовности. Определив готовность ведомого устройства, ведущее устройство начинает обмен данными. Каждая порция данных (в простейшем случае это один байт или одно слово) снабжается номером порта устройства-получателя.
Окончив обмен данными, ведущее устройство производит освобождение шины. На этом операция обмена данными между двумя устройствами по общей шине считается завершённой. Разумеется, арбитр следит, чтобы ни одно из устройств не захватывало шину на длительное время (например, устройство может сломаться, и оно поэтому "забудет" освободить шину).
Рассмотрим теперь, как видит общую шину программист. Как уже было сказано, у каждого периферийного устройства обязательно есть один или несколько портов с закреплёнными за этим устройством номерами. Программист может обмениваться с портами байтами или словами (в зависимости от вида порта). Для записи в некоторый порт используется команда
out op1,op2
Здесь операнд op1 определяет номер нужного порта и может иметь формат i8 (если номер порта небольшой и известен заранее) или быть регистром dx (если номер большой или становится известным только в процессе счёта программы). Второй операнд op2 должен задаваться регистрами al (если производится обмен байтом) или ax (если производится обмен словом).
Для чтения данных из порта служит команда
in op1,op2
Здесь уже второй операнд op2 определяет номер нужного порта и может иметь, как и в предыдущей команде, формат i8 или быть регистром dx. Первый операнд op1 должен задаваться регистрами al (если производится обмен байтом) или ax (если производится обмен словом). Далее мы рассмотрим небольшой пример использования этих команд.
Рассмотрим теперь общую архитектуру связи центрального процессора и периферийных устройств с точки зрения пользователей разного уровня.
-
Конечный пользователь. Пользователь-непрограммист бухгалтер Иванов уверен, что в компьютере есть команда "Распечатать ведомость", так как именно это происходит каждый раз, когда он нажимает на кнопку меню "Печать ведомости".
-
Прикладной программист. Программист Петров, который написал бухгалтерскую программу на языке Паскаль, только улыбнётся наивности Иванова. Уж он то точно знает, что даже для того, чтобы вывести только один, например, символ 'A', надо написать оператор стандартной процедуры Write('A') . Правда Петрову известно, что на самом деле его программа сначала переводится (транслируется) на машинный язык, поэтому он из любопытства поинтересовался у программиста на Ассемблере Сидорова, что тот напишет, чтобы вывести символ 'A'. Сидоров ответил, что обычно для этой цели он пишет предложение Ассемблера outch 'A' . Разница между этими двумя способами вывода символа показалась Петрову несущественной, например он читал о том, что, например, в языке С для этой же цели надо вызвать библиотечную функцию printf("%c",'A'); .1
-
Программист на Ассемблере. Сидоров, однако, знает, что предложение outch 'A' является не командой машины, а макрокомандой, на её место макропроцессор подставит макрорасширение, например, такого вида
mov dl,'A'
mov ah,02h
int 21h
Вот этот, как говорят, системный вызов и будет, с точки зрения Сидорова, выводить символ 'A' на стандартное устройство вывода.
-
Системный программист. Системный программист (раньше иногда говорили системный аналитик) Антонов, однако снисходительно пояснит Сидорову, что системный вызов – это просто переход на служебную процедуру-обработчик прерывания с номером 21h. А уж эта процедура и произведёт на самом деле вывод символа, используя, в частности, специальные команды обмена с внешними устройствами in и out.
-
Инженер-электронщик. Инженер Попов, внимательно прослушав разговор пользователей, скажет, что всё это неверно. На самом деле центральный процессор выводит символ на экран или печатающее устройство путём сложной последовательности действий, которая включает в себя такие операции с общей шиной, как запрос, захват, передача данных и освобождение этой шины. И только после этого символ, наконец, прибывает по назначению.
Как Вы догадываетесь, нельзя сказать, кто же из этих людей прав, и бессмысленно спрашивать, как всё происходит "на самом деле". Каждый из них прав со своего уровня видения архитектуры компьютера. И, как мы уже говорили, опускаться на более низкий уровень рассмотрения архитектуры следует только тогда, когда это абсолютно необходимо для дела.
Разберём теперь простой пример реализации операции ввода/вывода на уровне системного программиста. Оставим в стороне пользователя-непрограммиста (он нам сейчас неинтересен) и рассмотрим, например, операцию позицирования курсора на экране компьютера в позицию (X,Y).
Для прикладного программиста, как Вы знаете, для этой цели надо выполнить, например, оператор стандартный процедуры Турбо-Паскаля GotoXY(X,Y) . Для программиста на Ассемблере позицирование курсора можно выполнить с использованием такого системного вызова:
mov ah,2
mov bl,0
mov dl,X
mov dh,Y
int 10h
Как видим, параметры позицирования X и Y передаются в регистрах dl и dh. Системный вызов int 10h может выполнять различные операции с экраном компьютера, в зависимости от своих параметров, передаваемых ему на регистрах. Рассмотрим (в сильно упрощённом виде) тот фрагмент процедуры-обработчика системного вызова, который выполняет запрос на позицирование курсора.1
Во-первых, нам необходимо понять, а как вообще дисплей (точнее, электронная схема – контроллер дисплея) "знает", куда необходимо в каждый момент времени поставить курсор. Оказывается, что у контроллера дисплея, как, впрочем, и у любого другого периферийного устройства, есть свои регистры. Нас будут интересовать регистры дисплея с номерами 14 и 15 (обозначим их R14 и R15), каждый из них имеет размер 8 бит, но их совокупность может хранить длинное целое число, как показано ниже
16 бит | |
R14 | R15 |
Далее, дисплей "считает",2 что его экран имеет не 25 строк и 80 столбцов, как думают программисты, а 25*80 знакомест, в каждое из которых можно вывести один символ и поставить курсор. Знакоместа в первой строке экрана нумеруются не от 1 до 80, а от 0 до 79, во второй – от 80 до 159 и т.д. Другими словами, все позиции экрана расмматриваются как одномерный массив. Так вот, чтобы курсор переместился в нужную нам позицию (X,Y) в пару регистров <R14,R15> необходимо записать число
80*(Y-1)+(X-1)
Следовательно, сначала прецедуре-обработчику прерывания необходимо вычислить это число, используя параметры X и Y из системного вызова:
mov al,80
dec dh; Y-1
mul dh; ax:=80*(Y-1)
dec dl; X-1
add al,dh
adc ah,0; ax:=80*(Y-1)+(X-1)
mov bx,ax; Спасём на bx
Теперь необходимо переслать содержимое регистров bl и bh соответственно в регистры R15 и R14 дисплея. Для этого мы будем использовать два порта дисплея (в каждый можно записывать для передачи дисплею операнд размером в байт). Порт с шестнадцатеричным номером 3D4h позволяет выбрать номер регистра дисплея, в который будет производиться очередная запись данных. Для этого в этот порт необходимо записать номер соответствующего регистра (у нас это номера 15 и 14). После выбора номера регистра запись в него нового значения производится посредством посылки байта в "транспортировочный" порт дисплея с номером 3D5h. В итоге получается следующий фрагмент программы:
mov dx,3D4h; Порт выбора регистра
mov al,15
out dx,al; Выбираем R15
inc dx; Порт записи в регистр
mov al,bl; младший байт BX
out dx,al; Запись в R15
dec dx; Порт выбора регистра
mov al,14
out dx,al; Выбираем R14
inc dx; Порт записи в регистр
mov al,bh; старший байт BX
out dx,al; Запись в R14
Вот теперь курсор будет установлен в нужное место экрана, и можно возвращаться на команду, следующую за системным вызовом int 10h . Разумеется, наш алгоритм весьма примитивен. Например, после записи в 15-й регистр дисплея и до записи в 14-й регистр курсор прыгнет в непредсказуемое место экрана, так что по-хорошему надо было бы на время работы нашего фрагмента заблокировать для контроллера чтение данных из регистров дисплея. Это, разумеется, делается записью некоторого значения в определённый управляющий регистр дисплея, для чего понадобятся и другие команды in и out. Кроме того, хорошо бы предварительно убедиться, что дисплей вообще включён и работает в нужном нам режиме, для чего потребуется, например, считать некоторые флаги состояния дисплея .
Надеюсь, что этот простенький фрагмент реализации системного вызова не отобьёт у Вас охоту быть системным программистом и заниматься написанием драйверов внешних устройств .
15.2.2. Достоинства и недостатки архитектуры с общей шиной.
Из рассмотренной схемы связи всех устройств компьютера с помощью общей шины легко увидеть как достоинства, так и недостатки этой архитектуры. Несомненным достоинством этой архитектуры является её простота и возможность лёгкого подключения к шине новых устройств. Для подключения нового устройства необходимо оборудовать его соответстсвующими портами, присвоив им свободные номера, благо этих номеров много – 216.
Главный недостаток этой архитектуры тоже очевиден: пока два устройства обмениваются данными, остальные должны простаивать. Можно сказать, что компьютер в какие-то периоды времени вынужнен соизмерять скорость своей работы со скоростью самого медленного устройства на общей шине. Этот недостаток давно осознан конструкторами ЭВМ и с ним пытаются бороться. Например, наряду с главной шиной, соединяющей все устройства, вводят в архитектуру вспомогательные шины, соединяющие избранные самые быстрые устройства (например, центральный процессор и оперативную память). Ясно, однако, что невозможно соединить своими шинами всевозможные пары устройств, это просто экономически нецелесообразно, не говоря уже о том, что такую архитектуру практически невозможно реализовать.
Исходя из таких очевидных недостатков архитектуры с общей шиной была разработана и другая архитектура связи устройств компьютера между собой. Обычно она называется архитектурой с каналами ввода/вывода.
15.2.3. Архитектура ЭВМ с каналами ввода/вывода.
Архитектура ЭВМ с каналами ввода/вывода предполагает возможность параллельной работы нескольких устройств. Поймём сначала, какие же работы нам надо производить параллельно. Оказывается, что нужно обеспечить параллельный обмен данными нескольких устройств с оперативной памятью. Действительно, когда мы рассматривали мультипрограммный режим работы ЭВМ, мы говорили, что для эффективного использования ресурсов необходимо обеспечить как можно более полную загрузку всех устройств компьютера.
Например, одна программа может выполнять свои команды на центральном процессоре, другая – читать массив данных с диска в оперативную память, третья – выводить результаты работы из оперативной памяти на печать и т.д. Как видим, здесь оперативная память параллельно работает с несколькими устройствами: центральным процессором (он читает из памяти команды и данные, а записывает в память результат выполнения некоторых команд), диском, печатающим устройством и т.д. Скорость работы оперативной памяти должна быть достаточна для такого параллельного обслуживания нескольких устройств (здесь, как мы уже говорили, сильно помогает расслоение оперативной памяти и использование кэша).
Как мы знаем, центральный процессор выполняет обращения к оперативной памяти, подчиняясь командам выполняемой программы. Ясно, что и все другие обмены данными с оперативной памятью должны выполняться под управлением достаточно "интеллектуальных" устройств ЭВМ. Вот эти устройства и называются каналами ввода/вывода, так как они управляют обменом данными между оперативной памятью и, как говорят, периферией. По-существу, канал ввода/вывода является специализированным процессором со своей системой команд (своим машинным языком).