В общем-то это не так просто, но понять можно. Вот, выполняется программа пользователя, естественно, в режиме "задача". Вот ей понадобилось прочитать что-то с диска. Для этого она исполняет макрокоманду .READ, .READW или .READC. То есть, формирует из аргументов макрокоманды таблицу в памяти, заносит в R0 адрес этой таблицы и исполняет машинную команду EMT с соответствующим кодом. Эта команда вызывает прервыание с вектором 030, включается состояние "система", соответствующие компоненты резидентного монитора выполнят кучку действий, в конце которых поместят этот запрос в очередь к соответствующему драйверу.
Когда подойдет очередь этого запроса (или сразу, если очередь была пуста) запускается драйвер. Он подготавливает операцию. Для дисков, допустим, надо переместить головки, дождаться нужного сектора и т.д. Все это требует времени, но устройство способно сделать это самостоятельно. Поэтому драйвер выдает устройству команду на эти действия и вынужден ждать. Классический вариант - сообщить устройству, что по выполнении этих действий надо будет сделать прерывание, после чего выйти назад в систему. Система продолжит исполнение текущей задачи (если макрокоманда была .READ или .READC) или запустит другую задачу, если была макрокоманда .READW.
Когда механика отработает, аппаратура контроллера пошлет сигнал прерывания, исполняемая задача будет приостановлена, включится состояние "система" и начнется передача данных. Когда все данные будут переданы, драйвер вернет управление системе специальным образом, сигналя "операция завершена". По этому сигналу будет взобновлено исполнение ожидающей задачи. Это, конечно, сильно упрощено, но где-то так. Примерно таким образом работает, допустим, драйвер DW. Есть и другие варианты, но это для другой аппаратуры, об этом я умолчу.
Так вот, все это имеет смысл (1) для относительно медленных устройств и (2) для реальной многозадачной работы. Тот же винчестер - у него перемещение головок занимает не один десяток мс, прямой смысл отдать это время исполнению других задач. SD-карточка - устройство быстрое, время от выдачи команды чтения до готовности передавать данные имеет порядок 200 мкс, за это время выполнится, дай бог, сотни полторы команд, то есть не факт, что система успеет хотя бы переключить задачи (там довольно много действий). При записи оно чуть хуже, но тоже, максимум, 1-2 мс. Поэтому я первый вариант драйвера сделал по-простому: выдал команду "читать сектор" и в цикле жду, когда появится бит "сделано", не возвращая управление системе. Вот это самое ожидание путём многократного опроса бита готовности (пока он не появится) и называют "Polling", а на жаргоне - "прополка".
Я сделал драйвера с "прополкой", в основном, потому, что у меня еще не был готов тот кусок фирмвари, который обслуживает прерывания со стороны STM32. Как только я его сочинил, так сразу сделал и вариант драйверов с ожиданием посредством прерываний, но, в общем-то, особой разницы не обнаружилось, не считая того, что драйвера с прерываниями по размеру больше - естественно, для обработки прерываний нужен и дополнительный код, и дополнительные поля...
А на УКНЦ, к тому-же, практически, не имеет смысла пускать многозадачную ОС - нормальным многозадачкам нужен диспетчер памяти и не менее 248К этой памяти. Те меньшие цифры, которые называют для "больших" ОС - это только чтобы эта ОСь кое-как запустилась, для нормальной работы минимум - 248К. Единственная многозадачка, которая более-менее нормально работает на УКНЦ - это RT11FB, но что под ней гонять на УКНЦ - непонятно. На ДВК оперативным заданием изредка гоняли спулер - вывалил большой листинг в файл, пустил QUEUE.REL, она печатает этот листинг на принтер, а ты в фоне делаешь что-то другое. Сейчас ни на УКНЦ, ни на ДВК никто этого делать не будет, а, значит, и RT11FB загружать бесполезно...




Ответить с цитированием