Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содеожание] [Дальше]

Аппаратное обеспечение IBM PC

© Александр Фролов, Григорий Фролов
Том 2, книга 1, М.: Диалог-МИФИ, 1992.

9. КОНТРОЛЛЕР ПРЯМОГО ДОСТУПА К ПАМЯТИ

  • 9.1. Контроллер прямого доступа для IBM PC/XT
  • 9.2. Контроллер прямого доступа для IBM AT
  • Прямой доступ к памяти (Direct Memory Access - DMA) используется для выполнения операций передачи данных непосредственно между оперативной памятью и устройствами ввода/вывода. Обычно это такие устройства, как НГМД, НМД, кассетные накопители на магнитной ленте КНМЛ (стримеры).

    При использовании DMA процессор не участвует в операциях ввода/вывода, контроллер прямого доступа сам формирует все сигналы, необходимые для обмена данными с устройством. Скорость такого непосредственного обмена значительно выше, чем при традиционном вводе/выводе с использованием центрального процессора и команд INP, OUT.

    Мы уже немного рассказывали о контроллере прямого доступа к памяти в третьей книге первого тома, в разделе, посвященном работе с НГМД на уровне команд ввода/вывода. Была приведена программа, использующая DMA для чтения секторов дискеты. В этом разделе мы подробнее рассмотрим порты контроллера DMA.

    Распространены два типа контроллеров DMA - контроллеры для IBM PC/XT и контроллеры для IBM AT. Вначале мы расскажем о первом типе контроллеров, затем займемся контроллером DMA компьютера IBM AT.

    9.1. Контроллер прямого доступа для IBM PC/XT

    Контроллер прямого доступа для IBM PC/XT реализован на базе микросхемы Intel 8237A и содержит четыре канала. Эти каналы используются следующим образом:

    0 обновление содержимого динамической памяти компьютера, этот канал имеет наивысший приоритет;
    1 не используется;
    2 адаптер накопителя на гибком магнитном диске (НГМД);
    3 адаптер накопителя на магнитном диске (НМД) - этот канал имеет низший приоритет.

    9.1.1. Регистры каналов DMA

    Каждый канал содержит 16-разрядные регистры:

    • регистр текущего адреса CAR, содержит текущий адрес ячейки памяти при выполнении операции обмена данными с использованием DMA;
    • регистр циклов прямого доступа к памяти CWR, содержит число слов, предназначенных для передачи минус единица; при выполнении обмена данными регистр работает в режиме вычитания;
    • регистр хранения базового адреса BAR, используется для хранения базового адреса памяти, используемого при передачи данных; в процессе работы канала DMA содержимое этого регистра не изменяется;
    • регистр хранения базового числа циклов прямого доступа к памяти WCR; он хранит число циклов DMA, его содержимое также не изменяестя;
    • регистр режима MR, определяющий режим работы канала.

    Приведем адреса регистров и их форматы для компьютеров IBM PC/XT.

    Порты 00h - 07h

    Эти регистры содержат базовые адреса и счетчики передаваемых данных каналов 0 - 3. Их назначение приводится в следующей таблице:

    00h Запись: Базовый адрес канала 0
    Чтение: Текущий адрес
    01h Запись: Счетчик канала 0
    Чтение: Текущий адрес
    02h Запись: Базовый адрес канала 1
    Чтение: Текущий адрес
    03h Запись: Счетчик канала 1
    Чтение: Текущий адрес
    04h Запись: Базовый адрес канала 2
    Чтение: Текущий адрес
    05h Запись: Счетчик канала 2
    Чтение: Текущий адрес
    06h Запись: Базовый адрес канала 3
    Чтение: Текущий адрес
    07h Запись: Счетчик канала 3
    Чтение: Текущий адрес

    Порт 08h.

    Этот порт используется при записи в качестве управляющего регистра и при чтении как регистр состояния.

    Формат управляющего регистра:

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦
    LT+T+T+T+T+T+T+T-
     ¦ ¦ ¦ ¦ ¦ ¦ ¦ L= 1 - использование режима память-память;
     ¦ ¦ ¦ ¦ ¦ ¦ ¦    0 - обычный режим работы;
     ¦ ¦ ¦ ¦ ¦ ¦ ¦
     ¦ ¦ ¦ ¦ ¦ ¦ L=== если используется режим память-память,
     ¦ ¦ ¦ ¦ ¦ ¦      то 1 в этом разряде разрешает захват 
     ¦ ¦ ¦ ¦ ¦ ¦      канала, 0 - запрещает;
     ¦ ¦ ¦ ¦ ¦ ¦      в обычном режиме работы состояние этого
     ¦ ¦ ¦ ¦ ¦ ¦      бита безразлично;
     ¦ ¦ ¦ ¦ ¦ ¦
     ¦ ¦ ¦ ¦ ¦ L===== 1 - запрет работы DMA;
     ¦ ¦ ¦ ¦ ¦        0 - разрешение работы DMA;
     ¦ ¦ ¦ ¦ ¦
     ¦ ¦ ¦ ¦ L======= 1 - использование сжатия во времени, если
     ¦ ¦ ¦ ¦              установлен бит обычного режима работы;
     ¦ ¦ ¦ ¦          0 - обычный режим работы;
     ¦ ¦ ¦ ¦
     ¦ ¦ ¦ L========= 1 - вращение приоритетов;
     ¦ ¦ ¦            0 - фиксированные приоритеты;
     ¦ ¦ ¦
     ¦ ¦ L=========== 1 - удлиненный цикл записи;
     ¦ ¦              0 - нормальный цикл записи;
     ¦ ¦
     ¦ L============= 1 - используется низкий уровень для
     ¦                    сигнала запроса на DMA DREQ;
     ¦                0 - используется высокий уровень;
     ¦
     L=============== 1 - используется высокий уровень для
                      сигнала подтверждения DMA DACK;
                      0 - используется низкий уровень;
    
    
    

    Обычно этот регистр инициализируется BIOS в процессе тестирования системы и впоследствии изменять режим работы контроллера DMA не требуется. Ошибки при инициализации этого порта могут привести к "зависанию" системы.

    При чтении из порта 08h программа получает слово состояния контроллера DMA:

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦       ¦       ¦
    LT+-+-+T+T+-+-+T-
     L==T==- L=====¦= биты 0-3 устанавливаются в 1 при
        ¦             достижении счетчиками каналов 0-3
        ¦             конечных значений;
        ¦
        L============ биты 4-7 установлены в 1, если
                      имеется разрешение на DMA
                      соответственно, каналов 0-3.
    
    
    

    Порт 09h.

    Регистр запроса. Предназначен для организации программного (а не аппаратного) запроса на DMA. Для использования программного запроса канал должен быть запрограммирован в режиме блочной передачи.

    Формат регистра:

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦         ¦ ¦   ¦
    LT+-+-+-+T+T+T+T-
     L===T===- ¦ L=¦= номер используемого канала:
         ¦     ¦        00 - канал 0;
         ¦     ¦        01 - канал 1;
         ¦     ¦        10 - канал 2;
         ¦     ¦        11 - канал 3;
         ¦     ¦
         ¦     L===== 0 - установить запрос;
         ¦            1 - сбросить запрос;
         ¦
         L=========== не используются.
    
    
    

    Порт 0Ah

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

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦         ¦ ¦   ¦
    LT+-+-+-+T+T+T+T-
     L===T===- ¦ L=¦= номер канала:
         ¦     ¦        00 - канал 0;
         ¦     ¦        01 - канал 1;
         ¦     ¦        10 - канал 2;
         ¦     ¦        11 - канал 3;
         ¦     ¦
         ¦     L===== 0 - установить маску;
         ¦            1 - сбросить маску;
         ¦
         L=========== не используются.
    
    
    

    Порт 0Bh

    Регистр режима. Служит для определения режимов работы каналов контроллера DMA:

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦   ¦ ¦ ¦   ¦   ¦
    LT+T+T+T+T+T+T+T-
     L=¦ ¦ ¦ L=¦ L=¦= номер канала:
       ¦ ¦ ¦   ¦        00 - канал 0;
       ¦ ¦ ¦   ¦        01 - канал 1;
       ¦ ¦ ¦   ¦        10 - канал 2;
       ¦ ¦ ¦   ¦        11 - канал 3;
       ¦ ¦ ¦   ¦
       ¦ ¦ ¦   L===== тип цикла DMA:
       ¦ ¦ ¦            00 - цикл проверки;
       ¦ ¦ ¦            01 - цикл записи;
       ¦ ¦ ¦            10 - цикл чтения;
       ¦ ¦ ¦            11 - запрещенная комбинация;
       ¦ ¦ ¦
       ¦ ¦ L========= 1 - режим автоинициализации;
       ¦ ¦
       ¦ L=========== приращение адреса:
       ¦                0 - инкрементирование;
       ¦                1 - декрементирование;
       ¦
       L============= режим обслуживания:
                        00 - передача по требованию;
                        01 -    одиночная передача;
                        10 -    блочная передача;
                        11 -    каскадироание.
    
    
    

    Порт 0Ch

    Сброс триггера байтов. Для загрузки внутренних 16-разрядных регистров контроллера используется последовательный вывод младшего, затем старшего байтов слова. После сброса триггера байтов можно начинать загрузку 16-разрядных регистров.

    Порт 0Dh

    Запись в этот порт вызывает сброс контроллера. Для дальнейшего использования контроллер должен быть заново проинициализирован.

    Порт 0Eh

    Сброс регистра маски. После записи в этот регистр любого значения разрешается работа всех четырех каналов прямого доступа.

    Порт 0Fh

    Маскирование/размаскирование каналов. С помощью этого порта можно выполнить одновременное маскирование или размаскирование нескольких каналов:

    7 6 5 4 3 2 1 0
    T-T-T-T-T-T-T-¬
    ¦       ¦ ¦ ¦ ¦ ¦
    LT+-+-+T+T+T+T+T-
     L==T==- ¦ ¦ ¦ L= 1 - маскирование канала 0;
        ¦    ¦ ¦ ¦    0 - разрешение канала 0;
        ¦    ¦ ¦ ¦
        ¦    ¦ ¦ L=== 1 - маскирование канала 1;
        ¦    ¦ ¦      0 - разрешение канала 1;
        ¦    ¦ ¦
        ¦    ¦ L===== 1 - маскирование канала 2;
        ¦    ¦        0 - разрешение канала 2;
        ¦    ¦
        ¦    L======= 1 - маскирование канала 3;
        ¦             0 - разрешение канала 3;
        ¦
        L============ не используются.
    
    
    
    

    Порты 81h-8Fh

    Это порты регистров страниц.

    Для работы с памятью контроллер прямого доступа использует 20-разрядные физические адреса. Шестнадцать младших битов адреса необходимо записать в регистр базового адреса канала. Старшие четыре бита - биты 16-19 - должны быть записаны в соответствующие порты регистров страниц.

    При инициализации регистров базового адреса и регистра страниц необходимо следить за тем, чтобы в процессе передачи данных не происходил переход за границу 64 килобайта.

    Для адресации регистров страниц можно использовать следующие порты:

    81h Регистр страниц канала 2
    82h Регистр страниц канала 3
    83h Регистр страниц канала 1

    9.1.2. Инициализация канала DMA

    Для инициализации канала программа должна выполнить следующие шаги:

    • сбросить триггер байтов командой записи в регистр 0Ch;
    • задать режим работы канала, выполнив запись по адресу 0Bh в регистр режима MR;
    • заслать младшие 16 битов 20-битового адреса области памяти, которая будет использована для передачи данных, в регистр базового адеса (адрес порта зависит от номера канала: 0 канал использует адрес 00h, 1 канал - 02h, 2 канал - 04h, 3 канал - 06h);
    • заслать номер страницы (старшие 4 бита 20-битового адреса) в регистр страниц 81h;
    • загрузить регистр циклов прямого доступа к памяти CWR значением, на 1 меньше требуемого количества передаваемых байтов (адреса этих портов для каналов 0...3, соответственно, 01h, 03h, 05h, 07h;
    • разрешить работу канала, выполнив запись в регистр маски каналов по адресу 0Ah.

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

    9.2. Контроллер прямого доступа для IBM AT

    Контроллер DMA компьютера IBM AT совместим снизу вверх с контролером IBM PC/XT. Он состоит из двух каскадно включенных микросхем Intel 8237A-5. Второй контроллер обслуживает каналы DMA с номерами 4-7.

    Приведем назначение каналов DMA для IBM AT:

    0 зарезервировано;
    1 управление синхронной передачей данных SDLC (Synchronous Data Link Control);
    2 адаптер накопителя на гибком магнитном диске (НГМД);
    3 адаптер накопителя на магнитном диске (НМД);
    4 используется для каскадного соединения с первым контроллером DMA;
    5-6 зарезервировано.

    Другое отличие - это разрядность каналов. Каналы 0-3 являются каналами 8-битовой передачи данных, а каналы 4-7 обеспечивают 16-битовую передачу данных. В связи с этим используются все 8 битов регистров страниц. Формируется 24-битовый адрес из 16-ти младших битов адреса, записываемых в базовые регистры и 8-ми старших битов адреса, записываемых в регистры страниц.

    Размер страницы составляет 128 килобайт, поэтому при передаче данных с использованием DMA не должна пересекаться граница 128 килобайт.

    Приведем назначение и адреса регистров страниц контроллера для IBM AT:

    81h Регистр страниц канала 2
    82h Регистр страниц канала 3
    83h Регистр страниц канала 1
    87h Регистр страниц канала 0
    89h Регистр страниц канала 6
    8Bh Регистр страниц канала 5
    8Ah Регистр страниц канала 7
    8Fh Регенерация динамической памяти

    Для 16-битовых каналов 4-7 передача данных начинается с границы слова и все адреса относятся к 16-битовым словам.

    Порты 0C0h - 0DFh

    Эти регистры содержат базовые адреса и счетчики передаваемых данных каналов 4-7. Их назначение приводится в следующей таблице:

    0C0h Запись: Базовый адрес канала 4
    Чтение: Текущий адрес
    0C2h Запись: Счетчик канала 4
    Чтение: Текущий адрес
    0C4h Запись: Базовый адрес канала 5
    Чтение: Текущий адрес
    0C6h Запись: Счетчик канала 5
    Чтение: Текущий адрес
    0C8h Запись: Базовый адрес канала 6
    Чтение: Текущий адрес
    0CAh Запись: Счетчик канала 6
    Чтение: Текущий адрес
    0CCh Запись: Базовый адрес канала 7
    Чтение: Текущий адрес
    0CEh Запись: Счетчик канала 7
    Чтение: Текущий адрес

    Порты 0D0h-0DFh

    Это управляющие порты и порты состояния второй микросхемы 8237A-5. По формату и назначению они соответствуют рассмотренным ранее для контроллера DMA компьютеров IBM PC/XT:

    0D0h Управляющий регистр / регистр состояния
    0D2h Регистр запроса
    0D4h Регистр маски
    0D6h Регистр режима
    0D8h Сброс триггера байтов
    0DAh Сброс контроллера
    0DCh Сброс регистра маски
    0DEh Маскирование/размаскирование каналов

    В качестве примера использования контроллера прямого доступа к памяти приведем программу чтения сектора флоппи-диска. Мы уже описывали ее в предыдущем томе. Поэтому здесь мы не будем описывать команды контроллера НГМД и другие тонкости, имеющие отношение к работе с флоппи-дисками.

    Перед началом инициализации КПДП программа должна послать в порты 0Bh и 0Ch код операции, которая будет выполняться КПДП - 46h для операции чтения и 4Ah для операции записи.

    В процессе инициализации программа должна сообщить КПДП адрес буфера, куда ему следует поместить данные или откуда надо взять данные, и длину передаваемых данных в байтах.

    Адрес необходимо представить в виде номера страницы и смещения. Для КПДП машины AT используется восьмибитовый номер страницы и 16-битовое смещение. Например, для адреса 23456 номер страницы - 2, смещение - 3456.

    Для программирования канала 2 КПДП программа должна сначала вывести младший байт смещения в порт с адресом 4, затем вывести в этот же порт старший байт смещения и, наконец, вывести байт номера страницы в порт с адресом 81h.

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

    После определения режима работы канала, адреса буфера и длины передаваемых данных, программа должна разрешить работу КПДП, выдав в порт с адресом 0Ch байт 2. Теперь канал прямого доступа готов к работе и будет ждать данных от контроллера НГМД.

    Приведенная ниже демонстрационная программа использует несколько наиболее характерных команд контроллера НГМД. Она предназначена для работы на машине AT. Для того, чтобы она правильно работала и на машинах PC/XT, ее надо немного изменить. Изменения касаются программирования контроллера ПДП и программирования скорости передачи контроллера НГМД.

    Контроллер КПДП PC/XT использует 4-битовый номер страницы буфера вместо 8-битового. Скорость передачи контроллера НГМД в машинах PC/XT не программируется, вам надо убрать соответствующие строки из программы. Еще надо обратить внимание на различное быстродействие машин AT и PC/XT и скорректировать константы в строках программы, выполняющих задержку.

    Программа не проверяет, установлен ли флоппи-диск в приемный карман дисковода, поэтому перед запуском не забудьте установить диск.

    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <dos.h>
    #include "sysp.h"
    
    #define CYL 0
    
    void main(void);
    void fdc_out(unsigned char byte);
    int  fdc_inp(void);
    void int_wait(void);
    void dma_init(char *);
    
    void main(void) {
    
            unsigned i;
            long l;
            char buffer[512];
            char status[7], main_status;
            DPT _far *fdpt;
            FILE *sect;
    
            printf("\n"
                     "\nРабота с контроллером НГМД"
                     "\n  ©Фролов А., 1991"
                     "\n");
    
    
    // Эта программа предназначена только для IBM AT
    
            if(pc_model() != 0xfc) {
                    printf("Эта программа предназначена только для IBM AT\n");
                    exit(-1);
            }
    
    // Открываем файл, в который будем записывать
    // содержимое самого первого сектора на дискете
    
            sect = fopen("!sector.dat","wb+");
    
    // Устанавливаем указатель на таблицу
    // параметров дискеты
    
            fdpt = get_dpt();
    
    // Включаем мотор дисковода А:
    // Перед этим разрешаем прерывания
    
         _enable();
            outp(0x3F2, 0x1C);
    
    // Выполняем задержку для разгона двигателя
    
            for(l=0;l<200000;l++);
    
    // Показываем содержимое регистра основного
    // состояния контроллера
    
            printf("Мотор включен.\t\t");
            printf("Основное состояние: %02.2X\n",inp(0x3F4));
    
    // Перед чтением сектора необходимо установить
    // головку на нужную дорожку, в нашем случае это
    // дорожка с номером CYL.
    
    // Выдаем контроллеру команду "Поиск"
    
            fdc_out(0xf);
    
    // Для команды "Поиск" требуется два байта параметров:
    // номер головки/номер накопителя и номер дорожки.
    // Мы работаем с нулевой головкой накопителя А:,
    // поэтому первый параметр равен 0, второй - CYL
    
            fdc_out(0);
            fdc_out(CYL);
    
    // Показываем содержимое регистра основного
    // состояния контроллера
    
            printf("\n<<<Поиск>>> \t\t");
            printf("Основное состояние: %02.2X\n",inp(0x3F4));
    
    // Ожидаем прерывание по завершению операции
    
            int_wait();
    
    // Задержка для позиционирования головки
    
            for(l=0;l<20000;l++);
    
    // Для проверки результата выполнения команды
    // "Поиск" выдаем контроллеру команду
    // "Чтение состояния прерывания"
    
    // Выводим содержимое регистра состояния
    // ST0  и номер дорожки после выполнения команды
    // "Поиск" PCN
    
            fdc_out(0x8);
            printf("Состояние прерывания:\t");
            printf(" ST0: %02.2X, \t", fdc_inp());
            printf("PCN: %02.2X\n", fdc_inp());
    
    // Для более глубокой диагностики состояния
    // контроллера выдаем контроллеру команду
    // "Чтение состояния накопителя", выводим
    // содержимое регистра состояния ST3
    
            fdc_out(4);
            fdc_out(0);
            printf("Состояние накопителя:\t ST3: %02.2X\n",fdc_inp());
    
    // Устанавливаем скорость передачи данных 500 Кбайтов/с,
    // это значение может различаться для разных типов дискет
    
            outp(0x3F7, 0);
    
    // Инициализация канала прямого
    // доступа к памяти
    
            dma_init(buffer);
    
    // Выдаем команду "Чтение данных"
    
            fdc_out(0x66);
            fdc_out(0x0);     // накопитель 0, головка 0
    
            fdc_out(CYL);     // цилиндр CYL
            fdc_out(0);       // головка 0
            fdc_out(1);       // номер сектора - 1
    
    // Передаем контроллеру технические параметры
    // дисковода, берем их из таблицы параметров дискеты.
    // Это такие параметры:
    //    - размер сектора;
    //    - номер последнего сектора на дорожке;
    //    - размер промежутка;
    //    - число считываемых/записываемых байтов
    
            fdc_out(fdpt->sec_size);
            fdc_out(fdpt->eot);
            fdc_out(fdpt->gap_rw);
            fdc_out(fdpt->dtl);
    
    // Ожидаем прерывание по завершению операции
    
            int_wait();
    
    // Считываем и выводим на экран байты результата
    // операции "Чтение данных"
    
            printf("\n<<<Чтение сектора>>> \n");
            printf("   Байты состояния (ST0,ST1,ST2,C,H,R,N):\n");
    
            for(i=0; i<7; i++) printf("%02.2X\t", (char) fdc_inp());
            printf("\n");
    
    // Выводим содержимое считанного сектора в файл
    
            for(i=0; i<512; i++) fputc(buffer[i],sect);
            fclose(sect);
    
    // Выключаем мотор
    
            outp(0x3F2, 0xC);
    }
    
    
    // Вывод байта в контроллер дисковода
    
    void fdc_out(unsigned char parm) {
    
            _asm {
                    mov   dx,3F4h     // Порт основного состояния
    loop_fdc_out:
    
                    in    al,dx
                    test  al,80h      // Проверяем готовность
                    jz loop_fdc_out   //   контроллера
    
                    inc   dx          // Выводим байт в порт данных
                    mov   al, parm    //   контроллера
                    out   dx, al
            }
    }
    
    // Ввод байта из порта данных контроллера дисковода
    
    int fdc_inp(void) {
    
            _asm {
                    mov   dx,3F4h     // Порт основного состояния
    loop_fdc_inp:
                    in    al,dx
                    test  al,80h      // Проверяем готовность
                    jz loop_fdc_inp   //   контроллера
    
                    inc   dx          // Введенный байт записываем
                    in    al, dx      // в регистр AX
            }
    }
    
    // Ожидание прерывания от контроллера
    
    void int_wait(void) {
    
    // Разрешаем прерывания
    
            _enable();
            _asm {
                    mov   ax,40h         // После прихода прерывания
                    mov   es,ax          // программа обработки прерывания
                    mov   bx,3Eh         // устанавливает в 1 старший бит
    wait_loop:                     // байта в области данных BIOS
                    mov   dl,es:[bx]     // по адресу 0040:003E.
                    test  dl,80h         // Мы ждем, когда этот бит будет
                    jz    wait_loop      // установлен в 1, а затем
                                                     // сбрасываем его.
                    and   dl,01111111b
                    mov   es:[bx],dl
            }
    }
    
    // Инициализация канала прямого доступа к памяти
    
    void dma_init(char *buf) {
    
            unsigned long f_adr;
            unsigned sg, of;
    
    // Вычисляем 24-разрядный адрес буфера для данных
    
            f_adr = ((unsigned long)_psp << 4)
                                    + (((unsigned long)buf) & 0xffff);
    
    // Расщепляем адрес на номер страницы
    // и смещение
    
            sg = (f_adr >> 16) & 0xff;
            of = f_adr & 0xffff;
    
    // На время программирования контроллера прямого
    // доступа запрещаем прерывания
    
            _disable();
    
            _asm {
                    mov   al,46h   // Команда чтения данных от
                                            // контроллера НГМД.
    
                    out   12,al    // Сброс триггера-указателя байта
                                            // для работы с 16-разрядными портами.
                                            // Следующий байт, выводимый в 16-разрядный
                                            // порт будет интерпретироваться
                                            // как младший.
    
                    out   11,al    // Установка режима контроллера ПДП
    
                    mov   ax,of    // Смещение буфера, младший байт
                    out   4,al
                    mov   al,ah    // Смещение буфера, старший байт
                    out   4,al
    
                    mov   ax,sg    // Номер страницы
                    out   81h,al
    
                    mov   ax,511   // Длина передаваемых данных
                    out   5,al
                    mov   al,ah
                    out   5,al
    
                    mov   al,2     // Разблокировка канала 2 контроллера ПДП
                    out   10,al
            }
    
    // Инициализация контроллера закончена,
    // разрешаем прерывания.
    
            _enable();
    }
    
    
    

    Остальные команды вы можете попробовать сами. Для получения дополнительной информации по контроллеру НГМД обратитесь к техническому руководству по IBM PC. Многое можно почерпнуть из описания микросхем дискового контроллера 765 фирмы NEC и аналогов этой микросхемы - Intel 8272A и отечественной КР1810ВГ72А.

    На этом мы завершим обсуждение контроллера DMA. Советуем вам еще раз посмотреть программу, читающую сектора диска с использованием канала прямого доступа в памяти, которую мы приводили в третьей книге первого тома. Вы можете самостоятельно внести в нее некоторые усовершенствования, например, проверку перехода адреса в процессе работы канала прямого доступа через границу 128 килобайтов.

    [Назад] [Содеожание] [Дальше]