X.10. П о р т ы в в о д а - в ы в о д а И я надеюсь, что наши потомки будут благодарны мне не только за то, что я здесь разъяснил, но и за то, что мною было добровольно опущено с целью предоста- вить им удовольствие самим найти это. Pене Декарт. Геометрия П о р т ввода-вывода - многоразрядный вход или выход компьютера,через который процессор обменивается данными с внешними устройствами (клавиату- рой, принтером, дисководом, видеопамятью и видеопроцессором, игровыми ма- нипуляторами). Часто говорят, что порты представляют собой "интерфейсные схемы компьютера". Порт ввода-вывода напоминает морской порт, через который ввозят и выво- зят товары. В нашем случае через порты вводятся и выводятся данные. Порты принимают данные от периферийных устройств и направляют их в эти устройст- ва. Используя прямой доступ к портам ввода-вывода,Вы более полно использу- ете возможности компьютера. Процессор "работает" с портами по адресам, которые не следует путать с адресами ROM или RAM: 1) порты с адресами &H00÷&H7F. Вы не можете и з м е н и т ь их содер- жимоe (сравните с ROM!); 2) порты с адресами &H80÷&HFF. Их содержимое изменять можно (сравните с RAM!); 3) порты с адресами &H100÷&HFFFF зарезервированы(пока не используются). Некоторые порты, их функции и адреса перечислены ниже: ┌────────────────┬───────────────┬─────────────────────────────────────┐ │ А д р е с │ Чтение(Запись)│ Н а з н а ч е н и е │ │────────────────┴───────────────┴─────────────────────────────────────┤ │ Порты, отвечающие за работу с локальной сетью КУВТ YAMAHA MSX-1 │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &h00 │ Чтение(Запись)│ Посылаемые данные │ │ &h01 │ Чтение │ Статус │ ├────────────────┼───────────────┼─────────────────────────────────────┤ │ &H02 │ Чтение │ Номер компьютера в локальной сети │ │ │ │ (только для компьютеров MSX-1) │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ Порты, отвечающие за работу с локальной сетью КУВТ YAMAHA MSX2 │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &H09 │ │ Командный порт (передача или прием) │ │ &H0C │ │ Порт состояния │ │ &H0E │ │ Порт данных │ ├─ ─ ─ ─ ─ ─ ─ ─ ┼─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┤ │ &H0A │ │ Используются при │ │ &H0B │ │ инициализации │ │ &H0D │ │ сетевого ОЗУ │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ П р и н т е р │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &H90 │ Чтение │ Ввод сигнала занятости принтера │ │ &H91 │ Запись │ Kод выводимого символа │ │ &H92 │ Запись │ ? │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ В и д е о п р о ц е с с о р (VDP) │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &H98 │ Чтение(Запись)│ Обращение к видеопамяти │ │ &H99 │ Чтение(Запись)│ Чтение (запись) в регистр VDP │ │ &H9A │ Запись │ Запись в регистр палитры │ │ &H9B │ Запись │ Косвенная запись в регистры VDP │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ З в у к о г е н е р а т о р (PSG) │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &HA0 │ Запись │ Ввод в порт номера регистра │ │ &HA1 │ Запись │ Ввод в порт информации для установ- │ │ │ │ ленного регистра │ │ &HA2 │ Чтение │ Последнее число, записанное в PSG │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ Программируемый п а р а л л е л ь н ы й и н т е р ф е й с (PPI) │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &HA8 │ Чтение(Запись)│ Запись (чтение) данных в порт A │ │ &HA9 │ Чтение(Запись)│ Запись (чтение) данных в порт B │ │ &HAA │ Чтение(Запись)│ Запись (чтение) данных в порт C │ │ &HAB │ Чтение(Запись)│ Запись (чтение) режимов PPI │ ├────────────────┴───────────────┴─────────────────────────────────────┤ │ Порты, отвечающие за работу с д и с к о в о д о м │ ├────────────────┬───────────────┬─────────────────────────────────────┤ │ &HB4 │ Запись │ ? │ │ &HB5 │ Чтение(Запись)│ ? │ ├────────────────┼───────────────┼─────────────────────────────────────┤ │ &HFC │ Чтение(Запись)│ Регистры распределения │ │ &HFD │ Чтение(Запись)│ с л о т о в │ │ &HFE │ Чтение(Запись)│ (расширений памяти) │ │ &HFF │ Чтение(Запись)│ для компьютеров серии MSX-2 │ └────────────────┴───────────────┴─────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────┐ │ Для работы с портами ввода-вывода используются: │ │ функция INP и операторы OUT и WAIT │ └─────────────────────────────────────────────────────────┘ Формат оператора OUT: ┌──────────────────────────────────┐ │ OUT а д р е с, д а н н о е │, └──────────────────────────────────┘ где: OUT ("OUTput"-"вывод") - служебное слово; а д р е с - арифметическое выражение, целая часть значения которого принадлежит отрезку [128,255] (128=&H80, 255=&HFF); д а н н о е - арифметическое выражение, целая часть значения которо- го принадлежит отрезку [0,255]. Оператор OUT "посылает" заданное операндом д а н н о е значение в порт, номер которого задан значением параметра а д р е с . В н и м а н и е ! На компьютерах серии MSX-2 прежде, чем использовать оператор OUT, необходимо в непосредственном режиме выполнить команду CALL NETEND (отключить Ваш компьютер от локальной сети) Опишем синтаксис функции INP: ┌────────────────────────┐ │ INP (а д р е с) │, └────────────────────────┘ где: INP ("INPut"-"ввод") - служебное слово; а д р е с - арифметическое выражение, целая часть значения которого принадлежит отрезку [0,255]. Функция INP возвращает целочисленное значение, "прочитанное" из порта, имеющего указанный адрес. Видна ли Вам аналогия между операторами POKE и OUT , PEEK и INP ?! При помощи функции INP Вы можете использовать в своих расчетах номер Вашего компьютера. Чтобы поместить в переменную А номер компьютера, на ко- тором Вы работаете в локальной сети MSX-1, примените оператор: ┌────────────────────┐ │ A=INP(&H02) AND 15 │. └────────────────────┘ Объясним роль логической операции AND. Значением, возвращаемым функци- ей INP(&H02), является двоичное число, записанное в одном байте. "Содержи- мое" четырех старших битов байта нас не интересует. Заметим, что число 15 = &b00001111. Как Вы уже, наверное, догадались, логическая операция AND позволяет выделить нужные нам четыре младших бита. X.10.1. П р о г р а м м и р у е м ы й п а р а л л е л ь н ы й и н т е р ф е й с (PPI) Теперь мы перейдем к рассказу о работе с портами Параллельного Програм- мируемого Интерфейса (PPI - "Parallel Programming Interface"). Напомним Вам, что и н т е р ф е й с (англ. "interface"-"сопряжение" - способ и средства установления и поддержания информационного обмена между исполнительными устройствами автоматической или человеко-машинной системы. В п а р а л л е л ь н о м интерфейсе порция двоичной информации, со- стоящая из n битов, передается одновременно по n каналам. ┌───────────────────────────────────────────────────────────────┐ 1. │ Порт А используется для выбора с л о т о в, осуществляющих │ │ управление расширенной памятью компьютера. │ └───────────────────────────────────────────────────────────────┘ ┌───────────────────────────────────────────────────────────────┐ │ Порты PPI B и C применяются для "работы" с матрицей клавиа- │ │ туры, причем номер строки матрицы клавиатуры "посылается" в │ │ порт C, а номер столбца "читается" в порту B . │ └───────────────────────────────────────────────────────────────┘ П р и м е р 1. О б н а р у ж е н и е нажатия клавиши "GRAPH". ───────────── Отметим, что клавиша "GRAPH" находится в строке 6 и столбце 2 матрицы клавиатуры (и строки, и столбцы матрицы нумеруются, на- чиная с 0). Тогда: 1) номер строки матрицы клавиатуры "посылаем" в порт C : OUT &HAA,6 2) "извлекаем" номер столбца из порта B: X=INP(&HA9) До нажатия клавиш значением Х является число 255 = &b11111111.В момент нажатия какой-либо клавиши соответствующий бит порта B (в нашем случае - второй) на мгновение обнуляется. Таким образом, нажатие клавиши "GRAPH" легко обнаружить, если выделить значение интересующего нас бита командой: IF (X AND &b00000100)=0 THEN PRINT"GRAPH" Программа, позволяющая обнаружить нажатие клавиши "GRAPH",выглядит так: 10 OUT &HAA,6:X=INP(&HA9) 20 IF (X AND 4)=0 THEN PRINT "GRAPH":END 30 GOTO 10 Надеемся, что Вы обратили внимание на недостаток этой программы: после ее запуска неожиданно включается индикатор "CAPS" (но это не означает,что Вам удалось смоделировать нажатие клавиши "CAPS"!). Разберемся, почему так происходит. Взгляните на приведенную ниже таблицу, в которой описаны назначения би- тов порта C: ┌──────────┬──────────────────────────────────────────┐ │ Биты 0÷3 │ Строка клавиатуры │ │ Бит 4 │ Если 0, то запускается кассетная лента │ │ Бит 5 │ Сигнал записи на ленту │ │ Бит 6 │ Если 0, то включается индикатор "CAPS" │ │ Бит 7 │ Управление звуковым сигналом │ └──────────┴──────────────────────────────────────────┘ Все ясно! Индикатор "CAPS" включается потому, что в порт C записывает- ся значение 6 = &b00000110, а значит, шестой бит порта C "опрокинулся" в нуль. ▲ ─────┬──── └───────────────────────┘ Фактически только четыре м л а д ш и х бита порта C определяют номер строки матрицы клавиатуры. Для "маскирования" (игнорирования) значений че- тырех старших битов достаточно вместо команды OUT &HAA,6 выполнить ко- манду: OUT &HAA,6 OR (INP(&HAA) AND &HF0) │ │ │ ┌── !!! ▼ ▼ ▼ ▼ &B00000110 OR (&B∗1∗∗∗∗∗∗ AND &B11110000) = &B∗1∗∗ 0110 (символом "∗" отмечены биты, состояние которых в данном случае роли не иг- рает). П р и м е р 2. Включение индикатора "CAPS" (если он выключен!) можно ───────────── осуществить следующей командой: OUT &HAA, INP(&HAA) XOR &B01000000 │ │ ┌─ !!! ▼ ▼ ▼ &B∗1∗∗∗∗∗∗ XOR &B01000000 = &B∗0∗∗∗∗∗∗ П р и м е р 3. ───────────── 10 OUT &HAA,6 OR (INP(&HAA) AND &HF0):B=INP(&HA9) 20 IF (B AND 1)=0 THEN PRINT "Нажата клавиша SHIFT" 30 IF (B AND 2)=0 THEN PRINT "Нажата клавиша CTRL" 40 IF (B AND 4)=0 THEN PRINT "Нажата клавиша GRAPH":GOTO 10 ELSE 10 В ходе работы программы индикатор "CAPS" сохранит состояние, в котором он находился до пуска программы! П р и м е р 4. Получим матрицу клавиатуры при помощи оператора OUT! ───────────── ┌────────────────────────────────────────────┐ │ 10 INPUT "Номер строки";N │ │ 20 INPUT "Номер столбца";T │ │ 30 OUT &HAA,INP(&HAA) AND &HF0 OR N │ │ 40 B=((INP(&HA9) AND 2^T)=0) │ │ 50 IF B THEN PRINT "Клавиша нажата":END │ │ 60 GOTO 30 │ └────────────────────────────────────────────┘ П р и м е р 5. Включение и выключение кассетной ленты. Операторы MOTOR ───────────── ON и MOTOR OFF могут быть имитированы с помощью команды: OUT &HAA, INP(&HAA) XOR &B00010000 X.10.2. П р о г р а м м и р у е м ы й з в у к о в о й г е н е р а т о р (PSG) Вначале приведем два примера записи информации в PSG при помощи портов ввода-вывода. П р и м е р 6. ───────────── 10 SOUND 7,8 'Шум из канала A 10 OUT &HA0,7:OUT &HA1,8: A=INP(&HA2) 20 SOUND 8,15 'Громкость 20 OUT &HA0,8:OUT &HA1,15:B=INP(&HA2) 30 SOUND 6,26 'Частота звука 30 OUT &HA0,6:OUT &HA1,26:C=INP(&HA2) 40 END 40 PRINT A;B;C run 8 15 26 Ok П р и м е р 7. Представьте, что Вы находитесь на берегу Черного моря ───────────── в районе Ялты. Закройте глаза и ... 10 FOR I=0 TO 13:READ V 20 OUT &HA0,I:OUT &HA1,V 'Имитация действия оператора SOUND I,V 30 NEXT:END 100 DATA 0,0,0,0,0,0,30,&HB7,16,0,0,0,90,14 А теперь мы расскажем Вам, как можно "музицировать" при помощи н е п о- с р е д с т в е н н о й записи в регистры звукового генератора. Взгляни- те на следующую небольшую табличку: ┌─────────────┬───────────────────┬──────────────────┐ │ Исполняемая │ Содержимое │ Содержимое │ │ нота │ нулевого регистра │ первого регистра │ ├─────────────┼───────────────────┼──────────────────┤ │ PLAY "O4C" │ 172 │ 1 │ │ PLAY "O4C#" │ 148 │ 1 │ │ PLAY "O4D" │ 125 │ 1 │ │ PLAY "O4D#" │ 104 │ 1 │ │ PLAY "O4E" │ 83 │ 1 │ │ PLAY "O4F │ 64 │ 1 │ │ PLAY "O4F#" │ 46 │ 1 │ │ PLAY "O4G" │ 29 │ 1 │ │ PLAY "O4G#" │ 13 │ 1 │ │ PLAY "O4A" │ 254 │ 0 │ │ PLAY "O4A#" │ 240 │ 0 │ │ PLAY "O4B" │ 227 │ 0 │ │ PLAY "O5C" │ 214 │ 0 │ └─────────────┴───────────────────┴──────────────────┘ П р и м е р 8. Гамма "до-мажор". ───────────── 10 DATA 1,172,1,125,1,83,1,64,1,29,0,254,0,227,0,214 20 OUT &HA0,8:OUT &HA1,15 'Установим громкость канала A 30 FOR T=1 TO 8:READ I1,I2 40 OUT &HA0,1:OUT &HA1,I1:OUT &HA0,0:OUT &HA1,I2 45 FOR K=1 TO 100:NEXT 'Если Вам захочется "озвучить", например, "выст рел", достаточно убрать из программы эту строку 50 NEXT 60 OUT &HA0,8:OUT &HA1,0 'Сбросим громкость канала A П р и м е р 10. "В траве сидел кузнечик!" ────────────── 10 'DEFINTA-Z:BEEP 20 OUT &HA0,8:OUT&HA1,15:OUT &HA0,1:OUT &HA1,0:OUT &HA0,0:OUT &HA1,254 30 RESTORE 240:S=S+1:IF S=1 THEN K=14 ELSE K=12 40 FOR I=1 TO K:READ S1,S0,T1 50 OUT &HA0,8:OUT &HA1,15 60 OUT &HA0,1:OUT &HA1,S1:OUT &HA0,0:OUT &HA1,S0 70 TIME=0 80 T=TIME:IF T