Организация ввода-вывода
Каждое устройство ввода-вывода, каждое системное устройство имеют один или несколько регистров, доступ к которым осуществляется через адресное пространство ввода-вывода. Эти регистры имеют разрядность 8, 16 или 32 бит. Адресное пространство ввода-вывода физически независимо от пространства оперативной памяти и имеет ограниченный объем, составляющий 216 или 65536 адресов ввода-вывода. Таким образом, понятие порта ввода-вывода можно определить как 8-, 16- или 32-разрядный аппаратный регистр, имеющий определенный адрес в адресном пространстве ввода-вывода. Вся работа системы с устройствами на самом низком уровне выполняется с использованием портов ввода-вывода.
Самым нижним уровнем программного управления оборудованием является уровень BIOS, на котором работа с устройствами ведется напрямую через порты. Тем самым реализуется концепция независимости от оборудования.
Принципиально управлять устройствами напрямую через порты несложно. Сведения о номерах портов, их разрядности, формате управляющих команд и алгоритме работы приводятся в техническом описании на устройство. То есть, фактически, важно знать, что и в какой последовательности нужно послать в порт или считать из него и как следует трактовать полученную информацию. Для этого достаточно всего двух команд микропроцессора:
in <аккумулятор>, <nnn> – ввод в аккумулятор из порта с номером nnn;
out <аккумулятор>, <nnn> – вывод содержимого аккумулятора в порт с номером nnn.
Команда in применяется для прямого управления оборудованием компьютера посредством портов. Номер порта задается вторым операндом в виде непосредственного значения или значения в регистре dx. Непосредственным значением можно задать порт с номером в диапазоне 0-255. При использовании порта с большим номером используется регистр dx. Размер данных определяется размерностью первого операнда и может быть байтом, словом, двойным словом. В качестве примера применения рассмотрим фрагмент обработчика прерывания №9 от клавиатуры. Это прерывание вызывается всякий раз при нажатии любой клавиши на клавиатуре.
Обработчик этого прерывания должен прочитать скан-код клавиши, подтвердить микропроцессору клавиатуры факт приема скан-кода, преобразовать этот код в соответствии с клавишами-переключателями и поместить преобразованный код в буфер клавиатуры, находящийся в области BIOS.
Пример 8.1. Вариант чтения клавиатуры.
in al,60h ;читаем скан-код
push ax ;сохраним его на время
in al,61h ;читаем порт 61h
or al,80h ;старший бит байта из порта 61h в 1
out 61h,al ;подтверждаем факт приема скан-кода
pop ax ;восстановили ax из стека
out 61h,al ;восстановили байт в порту 61h
AH Сервис
▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
00H читать (ожидать) следующую нажатую клавишу
Выход: AL = ASCII символ (если AL=0, AH содержит Расширенный код ASCII )
AH = Сканкод или Расширенный код ASCII
▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
01H Проверить готовность символа (и показать его, если так)
Выход: ZF = 1 если символ не готов.
ZF = 0 если символ готов.
AX = как для подфункции 00H (но символ здесь не
удаляется из очереди).
▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
02H Читать состояние shift-клавиш. Определить, какие shift-клавиши нажаты в
данный момент, находится ли клавиатура в состоянии NumLock, и т.п.
Выход: AL = статус клавиатуры -- см. Флаги клавиатуры
───────────────────────────────────────────────────────────────────────────────
╓7┬6┬5┬4┬3┬2┬1┬0╖
║i│c│n│s│A│C│ │ ║ извлеките байт по адресу 0:0417
╙╥┴╥┴╥┴╥┴╥┴╥┴╥┴╥╜ бит
║ ║ ║ ║ ║ ║ ║ ╚═► 0: правая клавиша Shift (AL & 01H) 01H=нажата
║ ║ ║ ║ ║ ║ ╚═══► 1: левая клавиша Shift (AL & 02H) 02H=нажата
║ ║ ║ ║ ║ ╚═════► 2: Ctrl (AL & 04H) 04H=[Ctrl] нажата
║ ║ ║ ║ ╚═══════► 3: Alt (AL & 08H) 08H=[Alt] нажата
║ ║ ║ ╚═════════► 4: ScrollLock (AL & 10H) 10H=режим ScrollLock
║ ║ ╚═══════════► 5: NumLock (AL & 20H) 20H=режим NumLock
║ ╚═════════════► 6: CapsLock (AL & 40H) 40H=режим CapsLock
╚═══════════════► 7: Insert (AL & 80H) 80H=режим Insert
╓7┬6┬5┬4┬3┬2┬1┬0╖
║I│C│N│S│ │ │ │ ║ извлеките байт по адресу 0:0418
╙╥┴╥┴╥┴╥┴╥┴╥┴╥┴╥╜ бит
║ ║ ║ ║ ║ ║ ║ ╚═► 0: Ctrl (левая клавиша Ctrl) (AL & 01H) 01H=нажата
║ ║ ║ ║ ║ ║ ╚═══► 1: Alt (левая клавиша Alt) (AL & 02H) 02H=нажата
║ ║ ║ ║ ║ ╚═════► 2: SysReq (AL & 04H) 40H=SysReq нажата
║ ║ ║ ║ ╚═══════► 3: задержка (AL & 08H) 08H Ctrl-NumLock (пауза)
║ ║ ║ ╚═════════► 4: ScrollLock (AL & 10H) 10H=[ScrollLock] нажата
║ ║ ╚═══════════► 5: NumLock (AL & 20H) 20H=[NumLock] нажата
║ ╚═════════════► 6: CapsLock (AL & 40H) 40H=[CapsLock] нажата
╚═══════════════► 7: Insert (AL & 80H) 80H=[Ins] нажата
Команда INS/INSB/INSW/INSD (OUTS/OUTSB/OUTSW/OUTSD) вводит данные из порта ввода-вывода, номер которого загружен в регистр dx, в память по адресу es:edi/di. Сегментная составляющая адреса должна быть обязательно в регистре es. Замена сегментного регистра недопустима. Непосредственное задание порта в команде также недопустимо - для этого используется регистр dx. Размеры вводимых элементов зависят от применяемой команды. Команда ins может работать с элементами размером в байт, слово, двойное слово. В качестве операндов в команде указывается символическое имя ячейки памяти, в которую вводятся элементы из порта ввода-вывода. Реально это символическое имя используется лишь для получения типа элемента последовательности, а его адрес должен быть предварительно загружен в пару регистров es:edi/di. Транслятор, обработав команду ins и выяснив тип операнда, генерирует одну из машинных команд insb, insw или insd. Машинного аналога для команды ins нет. Для того чтобы эти команды можно было использовать для ввода последовательности элементов, имеющих размерность байт, слово, двойное слово, необходимо использовать префикс rep. Префикс rep заставляет циклически выполняться команду ввода до тех пор, пока содержимое регистра ecx/cx не станет равным нулю:
Алгоритм работы:
· передать данные из порта ввода-вывода, номер которого загружен в регистр dx, в память по адресу es:edi/di;
· в зависимости от состояния флага df изменить значение регистров edi/di:
o если df=0, то увеличить содержимое этих регистров на длину структурного элемента последовательности;
o если df=1, то уменьшить содержимое этих регистров на длину структурного элемента последовательности;
· при наличии префикса выполнить определяемые им действия (см. команду rep).
Пример 8.2. Ввод 10 байт из порта 300h в цепочку байт в памяти
.286
str_10 db 10 dup(0)
adr_str dd str_10
les di,adr_str
mov dx,300h
rep insb
...
В качестве примера рассмотрим, как на уровне аппаратуры заставить компьютер издавать звук сирены через динамик. Специальной схемы генерации звука у компьютера нет. Сигнал для управления динамиком формируется в результате совместной работы следующих микросхем:
§ программируемого периферийного интерфейса (ППИ) i8255;
§ таймера i8253.
Основная работа по генерации звука производится микросхемой таймера (см. рис.8.1.). Микросхема таймера (далее, таймер) имеет три канала с одинаковой структурой и принципом работы. Каждый канал имеет два входа и один выход. Выход канала 0 замкнут на контроллер прерываний и является источником аппаратного прерывания от таймера, которое возникает 18,2 раз в секунду. Канал 1 связан с микросхемой прямого доступа к памяти (DMA). Канал 2 выходит на динамик компьютера.
Рис. 8.1. Схема формирования звука для встроенного динамика.
Основу каждого канала составляют три регистра: регистр ввода-вывода разрядностью 8 бит, регистр-защелка (latch register) и регистр-счетчик, оба по 16 бит. Принцип их работы: в регистр ввода-вывода извне помещается некоторое значение. Источником этого значения может быть либо системное программное обеспечение, либо программа пользователя. Регистр ввода-вывода канала 2 имеет номер порта ввода-вывода 42h. Помещаемые в него значения немедленно попадают в регистр-защелку (регистр-фиксатор), где его значение сохраняется до тех пор, пока в регистр ввода-вывода не будет записано новое значение. Регистр управления, который является частью механизма управления всей микросхемой таймера, является согласующей частью 8-ми и 16-ти разрядных регистров каналов. В нем содержится слово состояния, с помощью которого производится выбор канала, задание режима работы канала и тип операции передачи значения в канал.
Слово состояния имеет следующую структуру:
1. бит 0 определяет тип константы пересчета: 0 – константа задана двоичным числом; 1 – BCD-числом. Константа пересчета – значение, загружаемое извне в регистр-защелку.
2. биты 1-3 определяют режим работы таймера. Всего можно определить шесть режимов работы, но обычно используется третий: 011.
3. биты 4-5 определяют тип операции:
00 – передать значение счетчика в регистр-защелку,
10 – записать в регистр-защелку только старший байт;
01 – записать в регистр-защелку только младший байт;
11 – записать в регистр-защелку сначала старший байт, затем младший байт.
4. биты 6-7 определяют номер программируемого канала.
После того, как значение из регистра ввода-вывода попало в регистр-защелку, оно сразу попадает в регистр-счетчик, где оно уменьшается каждый раз на единицу с приходом нового импульса от системных часов. Когда значение в регистре-счетчике становится равным 0, на соответствующем входе схемы & формируется единица. Если при этом на втором входе также единица (бит 0 порта 61h), то импульс от системных часов проходит на выход канала 2. Одновременно со срабатыванием импульса в канале 2 производится загрузка содержимого регистра-защелки, если оно не изменилось, в регистр-счетчик. Процесс уменьшения счетчика повторяется заново. Таким образом, чем меньшее число загружено в регистр защелку, тем чаще будет обнуление регистра-защелки, и тем чаще импульсы будут проходить на выход канала 2. А это означает, что частота звука будет выше. Понятно, что максимальное значение на входе 1 динамика – 1,19 МГц, а минимальное – 18,2 Гц (1,19 МГц / 65536). Импульс с выхода канала 2 порождает звук, если на динамик подан ток. Подачей тока на динамик управляет бит 1 порта 61h.
Алгоритм управления
1. Посредством порта 43h выбрать канал, задать режим работы и тип операции передачи значения в канал. (10 11 011 0=0b6h)
2. Подать ток на динамик, установив бит 1 порта 61h.
3. Используя регистр ax, поместить нужное значение в порт 42h, определив тем самым частоту тона.
Ниже в листинге приведена программа, реализующая звук сирены. Вот ее описание по строкам:
7 – 21.... макрокоманда delay, осуществляющая задержку счетчиком
28 – 29.. настройка сегментного регистра
33 – 34.. настройка канала 2, которая заключается в записи в регистр управления байта состояния 0B6h;
35 – 37.. установка битов 0 и 1 порта 61h без изменения остальных битов;
39 – 49.. цикл повышения высоты звука;
51 – 58.. цикл понижения тона;
Оба цикла повторяются пять раз, согласно переменной cnt.
Пример 8.3 (Листинг программы)
1. ;Программа, имитирующая звук сирены. Изменение высоты звука от 450 Гц до 2100 Гц.
2. Используется макрос delay (задержка).
3. При необходимости можно поменять значение задержки (по умолчанию - для процессора Pentium).
4. masm
5. model small
6. stack 100h
7. delay macro time
8. local ext, iter
9. ;макрос задержки, его текст ограничивается директивами macro и endm.
10. ;На входе - значение задержки (в мкс)
11. push cx
12. mov cx,time
13. ext:
14. push cx
15. mov cx,5000
16. iter:
17. loop iter
18. pop cx
19. loop ext
20. pop cx
21. endm
22. .data ;сегмент данных
23. tonelow dw 2651 ;нижняя граница звучания = 450 Гц
24. cnt db 0 ;счётчик для выхода из программы
25. temp dw ? ;верхняя граница звучания
26. .code ;сегмент кода
27. main: ;точка входа в программу
28. mov ax,@data ;связываем регистр ds с сегментом
29. mov ds,ax ;данных через регистр ax
30. xor ax,ax ;очищаем ax
31. go:
32. ;заносим слово состояния 10110110b в командный регистр (порт 43h)
33. mov al,0B6h
34. out 43h,al
35. in al,61h ;получим значение порта 61h в al
36. or al,3 ;инициализируем динамик и подаем ток в порт 61h
37. out 61h,al
38. mov cx,2083 ;количество шагов ступенчатого изменения тона
39. musicup:
40. ;в ax значение нижней границы частоты
41. mov ax,tonelow
42. out 42h,al ;в порт 42h младшее слово ax :al
43. xchg al,ah ;обмен между al и ah
44. out 42h,al ;в порт 42h старшее слово ax:ah
45. add tonelow,1 ;повышаем тон
46. delay 1 ;задержка на 1 мкс
47. mov dx,tonelow ;в dx текущее значение высоты
48. mov temp,dx ;temp - верхнее значение высоты
49. loop musicup ;повторить цикл повышения
50. mov cx,2083 ; восстановить счетчик цикла
51. musicdown:
52. mov ax,temp ;в ax верхнее значение высоты
53. out 42h,al ;в порт 42h младшее слово ax :al
54. mov al,ah ;обмен между al и ah
55. out 42h,al ;в порт 42h старшее слово ax :ah
56. sub temp,1 ;понижаем высоту
57. delay 1 ;задержка на 1 мкс
58. loop musicdown ;повторить цикл понижения
59. nosound:
60. in al,61h ;получим значение порта 61h в AL
61. and al,0FCh ;выключить динамик
62. out 61h,al ;в порт 61h
63. mov dx,2651 ;для последующих циклов
64. mov tonelow,dx
65. inc cnt ;увеличиваем счётчик проходов, то есть
66. ;количество звучаний сирены
67. cmp cnt,5 ;5 раз ?
68. jne go ;если нет, идти на метку go
69. exit:
70. mov ax,4c00h ;стандартный выход
71. int 21h
72. end main ;конец программы
<== предыдущая лекция | | | следующая лекция ==> |
Арифметические команды | | | Последовательный интерфейс – COM-порт |
Дата добавления: 2020-02-05; просмотров: 537;