процессора. Когда микропроцессор 8088 должен передавать данные в порт,
используется команда OUT, которой указывается номер порта и передаваемые
данные,имеющие длину один или два байта. Фактически команда OUT
приказывает конкретному порту принять данные. Команда IN работает
аналогично, только данные считываются из порта. Микропроцессор 8088 не
может определить какие порты задействованы, а какие нет, так что все
команды IN и OUT выполняются вслепую.
Операторы Бейсика обеспечивают прямой доступ к портам. Операторы
Бейсика INP и OUT предоставляют те же возможности, что и машинные команды
IN и OUT. Ниже, просто для примера, приведен фрагмент программы на
Бейсике, работающей с динамиком:
10 X=INP(97) `чтение порта управления динамиком X
20 REM вероятно будет иметь значение 76 - проверьте какое
значение Вы получите
30 OUT 97,X+3 `установить биты управления динамиком- прозвучит сигнал
40 OUT 97,X `снять биты управления - окончание звука
Порты могут использоваться в сочетании с прерываниями. Например,если
нажать клавишу на клавиатуре IBM/PC, никакие данные в компьютер не
передаются. Вместо этого генерируется прерывание номер 9, указывающий, что
имеются данные, которые нужно вводить с клавиатуры. В ответ на прерывание
BIOS в ПЗУ выдаст команду IN для порта клавиатуры. Только после этого
данные, определяющие какая клавиша была нажата, попадут в компьютер.
В случае с памятью может существовать до 1024К различных ячеек,
причем компьютер не знает, какие именно адреса действительно имеются. То
же самое касается и портов - микропроцессор 8088 может обращаться к порту
с любым допустимым номером, не зная, работает ли этот порт или нет.
Адреса портов задаются 16 разрядами, так что потенциально можно иметь
64К различных портов. В действительности используется гораздо меньше
номеров и, следовательно, имеются неограниченные возможности для
расширения.
Имеется несколько способов использования портов в IBM/PC. Первый
способ - это использование порта просто как пути данных. Например, коды
клавиш, указывающие какая из клавиш была нажата, проходят через один порт;
данные, выдаваемые на устройство печати, проходят через другой порт.
Еще один способ использования портов заключается в передаче через них
управляющей информации для внешних устройств и получении от этих устройств
информации о состоянии. Например, инициализация адаптера монохромного
дисплея выполняется через порт 952. Еще одно назначение портов заключается
в считывании положений переключателей в системном блоке, указывающих
конфигурацию системы.
Ниже перечисляются некоторые наиболее важные применения портов. Как и
некоторые подробности организации аппаратных средств, описанные в главе 2,
номера конкретных портов могут не представлять интереса для читателя, но я
привожу их полностью просто для полноты изложения.
Порт 96 (шестнадцатиричное 60) используется для передачи данных в
формате порядковых номеров, от клавиатуры. При описании клавиатуры в главе
10 мы рассмотрим форматы номеров и их использование более подробно.
Порт 97 (61(16)) используется для управления встроенным динамиком, а
также двигателем кассетного механизма. Он также позволяет запустить
аппаратный таймер, что более подробно мы рассмотрим в главе 11.
Порты с 64 по 67 (40(16)-43(16)) используются для управления
программируемым таймером, используемым как динамиком, так и интерфейсом
кассетного накопителя. О том, как используются все эти порты, будет
рассказано в главе 11.
Монохромный дисплей использует несколько последовательных портов,
начиная с порта 944(3В0(16)), а цветной графический - последовательность,
начинающуюся с порта 976(3D0(16)). Контролер гибких дисков использует
последовательность портов, начиная с порта 1008(3F0(16)), а собственно
данные, записываемые на дискету или считываемые с нее, передаются через
порт 1013(3F5(16)).
Вместе с программой 3.1 для исследования конфигурации памяти,
листинги 3.2 и 3.3 показывают программу, объединяющую модули, написанные
на Паскале и на ассемблере, которая считывает все порты и сообщает о том,
какие из них наиболее вероятно активны. Готовая к запуску версия этой
программы имеется на дискете, прилагающейся к этой книге. В отличие от
программы обследования памяти эта программа не дает достаточно практичного
результата, однако, она может оказаться довольно интересной.
Поскольку Бейсик обеспечивает доступ к портам, эту программу можно
было бы написать на Бейсике, но тогда для читателя не было бы в ней ничего
нового. Вместо этого приведенный пример может послужить хорошим введением
в программирование на ассемблере, Паскале и примером объединения программ,
написанных на разных языках.
Приложение 3.1. Текст программы поиска активного участка памяти
(Бейсик).
1000 REM
1010 REM
1020 REM
1030 GOSUB 2000 ' TITLE
1040 GOSUB 3000 ' SEARCH AND DISPLAY
1050 GOSUB 4000 ' RETURN TO DOS
2000 REM
2010 KEY OFF : CLS : WIDTH 80
2020 REM
2030 PRINT "
2040 PRINT "
2050 PRINT
2060 PRINT "
2070 PRINT
2080 PRINT "
2090 PRINT "
2100 PRINT
2999 RETURN
3000 REM
3010 TRUE.% = -1
3020 FALSE.% = 0
3030 IN.MEMORY.% = FALSE.%
3040 FOR PARAGRAPH.! = 0 TO 65535! STEP 64 ' CHECK EACH 1K OF MEMORY
3050 GOSUB 5000 ' CHECK FOR ACTIVE MEMORY
3060 IF (IN.MEMORY.%=FALSE.%) AND (MEMORY.HERE.%=TRUE.%) THEN GOSUB
6000
3070 IF (IN.MEMORY.%=TRUE.%) AND (MEMORY.HERE.%=FALSE.%) THEN GOSUB
7000
3080 IN.MEMORY.% = FALSE.%
3090 IF MEMORY.HERE.% THEN IN.MEMORY.HERE.% =TRUE.%
3100 NEXT PARAGRAPH.!
3110 IF IN.MEMORY.% THEN PARAGRAPH.! = 65536 : GOSUB 7000
3999 RETURN
4000 REM
4010 PRINT
4020 PRINT "Finished."
4999 SYSTEM
5000 REM
5010 DEF SEG = PARAGRAPH.!
5020 BYTE0.% = PEEK (0)
5030 BYTE1.% = PEEK (1)
5040 BYTE2.% = PEEK (2)
5050 BYTE3.% = PEEK (3)
5060 CHECK.COUNT.% = 0
5070 IF BYTE0.% = 233 THEN CHECK.COUNT.% = CHECK.COUNT.% + 1
5080 IF BYTE1.% = 233 THEN CHECK.COUNT.% = CHECK.COUNT.% + 1
5090 IF BYTE2.% = 233 THEN CHECK.COUNT.% = CHECK.COUNT.% + 1
5100 IF BYTE3.% = 233 THEN CHECK.COUNT.% = CHECK.COUNT.% + 1
5110 MEMORY.HERE.% = FALSE.%
5120 IF CHECK.COUNT.% <= 3 THEN MEMORY.HERE.% = TRUE.%
5999 RETURN
6000 REM
6010 IN.MEMORY.% = TRUE.%
6020 START.! = PARAGRAPH.!
6999 RETURN
7000 REM
7010 SIZE.! = (PARAGRAPH.!-START.!) * 16
7020 IF SIZE.! < 8 * 1024 THEN 7999 ' SDUPPRESS SMALL-BLOCK FALSE
REPORTS
7030 PRINT "Active memory begins at ",
7040 PRINT HEX$(START.!)
7050 PRINT " ends at ",
7060 PRINT HEX$(PARAGRAPH.!-1);
7070 PRINT SIZE.! / 1024;"K-bytes"; ("SIZE.!;"bytes )"
7080 IN.MEMORY.% = FALSE.%
7090 PRINT
7999 RETURN
9999 REM
Приложение 3.2. Текст программы обработки прерываний (Ассемблер).
beepseg segment 'code'
assume cs:beepseg
beep proc far
cli
mov bx,3000
in al,61h
push ax
more: and al,0fch
out 61h,al
mov cx,50
11: loop 11
or al,2
out 61h,al
mov cx,50
12: loop 12
dec bx
jnz more
pop ax
out 61h,al
sti
int 20h
beep endp
beepseg ends
end
Приложение 3.3. Текст программы поиска активных портов (Паскаль).
program porttest (output);
function inport (x : word) : byte;
external;
var
count : word;
b : byte;
w : word;
c : array [wrd(0)..255] of word;
headc : word;
procedure header1;
var [static]
i : integer;
begin
writeln;
for i := 1 to 8 do
write (' Port Val');
writeln;
end;
procedure header2;
var [static]
i : integer;
begin
writeln;
for i := 1 to 8 do
write (' Val Count');
writeln;
end;
procedure initialise;
begin
count := 0;
headc := 0;
for b := 0 to 255 do
c[b] := 0;
for w := 1 to 25 do
writeln;
writeln('Program for INSIDE THE IBM PERSONAL COMPUTER');
writeln('(C) Copyright Peter Norton, 1983');
writeln('Listing 3.3: PORTTEST - read all ports');
writeln;
writeln('The following may be active ports:');
header1;
end;
procedure scan_all_ports;
begin
for w:=0 to maxword do
begin
b:=inport(w);
c[b]:=c[b]+1;
if not(b in [wrd(0),78,110,188,202,203,207,254,255])
then
begin
write(w:6,b:4);
count:=count+1;
headc:=headc+1;
if headc>159 then
begin
headc:=0;
header1;
end;
end;
end;
header1;
end;
procedure finish_up;
begin
writeln;
writeln('Here is a profile of the values returned for ',
all of the possible ports:');
header2;
for b:=0 to 255 do
write(b:4,c[b]:6);
header2;
writeln(count,' ports may possibly be active');
writeln;
writeln('Finished.')
end;
begin
initialize;
scan_all_ports;
finish_up
end.
Приложение 3.4. Текст программы считывания данных из порта
(Ассемблер).
inport_code segment 'code'
public inport
inport proc far
push bp
mov bp,sp
mov dx,[bp+6]
in al,dx
pop bp
ret 2
db '(C) Copyright Peter Norton, 1983'
inport endp
inport_code ends
end
ГЛАВА 4. ОСНОВЫ ОРГАНИЗАЦИИ ДОС
В этой главе будет кратко рассмотрена система ДОС, основная
операционная система IBM/PC. Мы не будем слишком подробно рассматривать
ее, частично потому что ДОС может составить достаточный предмет для
нескольких книг сама по себе, а частично потому, что эта книга в основном
посвящена внутренней организации IBM/PC, а не организации ДОС.
Но все же, поскольку ДОС очень широко используется на IBM/PC,
необходимо иметь определенные представления об ее организации. Так как
основное внимание в этой книге уделяется наиболее сложным возможностям
IBM/PC, мы покажем как осуществляется доступ к этим возможностям с помощью
средств операционной системы ДОС.
Здесь тесно соприкасаются все три упоминавшиеся выше области
интересов. Практически все, о чем пойдет речь в данной главе, относится к
IBM/PC, совместимым с ней компьютерам, а также к компьютерам, работающим
под управлением МS-DOS.