Программирование в машинных кодах и на языке ассемблера 1993 г.

Каналы и потоки - стандартные каналы. Прочие каналы. Область информации о каналах. Подключение потоков. Практические приемы работы с каналами и потоками.


5 . КАНАЛЫ И ПОТОКИ

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

Работая в БЕЙСИКе, Вы можете и не задумываться о потоках и каналах, а вот программируя в машинных кодах, без них не обойтись .

Можете представить себе, что канал - это некоторое техническое устройство, используемое для ввода/вывода информации. Надо, правда,оговориться, что канал - не всегда техническое устройство. Каналом, например, может быть файл на диске или, скажем, в памяти Вашего компьютера. В файл ведь тоже можно заносить информацию и можно ее оттуда считывать.

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

выводим на экран литеру.

которые в них впадают - это потоки, подключенные к каналам.

5.1 Стандартные каналы.

Стандартными каналами "Спектрума" для вывода информации являются каналы "К" - нижние две строки экрана (системное окно), "S" - главная часть экрана и "P" - стандартный "ZX-прин-тер".

К этим каналам стандартно подключены потоки:

- поток #0 - к каналу "К";

- поток #1 - тоже подключен к каналу "K";

- поток #2 - подключен к каналу "S";

- поток #3 - к каналу "P".

Таким образом, оказываются идентичными следующие команды ввода/вывода:

PRINT #0 "Hello"; A$ - то же самое, что и INPUT "Hello"; A$ PRINT "Hello" - то же самое, что и PRINT #2 "Hello" LPRINT "Hello" - то же самое, что и PRINT #3 "Hello" Номер, стоящий после знака # в вышеприведенных примерах, является номером потока. Поскольку эти потоки подключены стандартно и переподключены быть не могут, мы программируем на БЕЙСИКе и используем операторы INPUT, PRINT, LPRINT без указания номера потока.

В "Спектруме" каждый канал имеет имя, которое выражено одной буквой алфавита. Так, канал "S" - это экран, потому, что по-английски слово экран звучит, как "Screen".

Оператор OPEN# служит для того, чтобы подключить поток к каналу. Так, Вы можете в БЕЙСИКе дать команду OPEN#6,"S" и тем самым подключите шестой поток к экрану и тогда команда PRINT #6 будет печатать текст на экране точно так же, как это делает обычная команда PRINT.

Аналогично, Вы можете представить, что клавиатура - это устройство, предназначенное для ввода информации и потому это тоже канал. Он имеет имя "К" (Keyboard - клавиатура) . К нему можно подключить поток точно так же, как мы это делали с экраном. Например, OPEN #n,"K" - подключает к каналу клавиатуры поток номер n.

Всего Вы можете иметь не более шестнадцати потоков с номерами от 0 до 15. Потока с номером 16 не существует и, если Вы попробуете его использовать, то получите сообщение об ошибке.

Мы уже сказали о том, что потоки от 0 до 3 являются стандартными и организованы без нашего участия. Они стандартно подключены к стандартным каналам.

Каналы "S" и "P" предназначены только для вывода информации, поэтому например PRINT #2 или PRINT #3 - возможны, а INPUT #2 или INPUT #3 - невозможны.

В отличие от них, канал "К" может использоваться и для ввода и для вывода.

INPUT #0 - самая обычная команда INPUT, а PRINT #0 -выполняет печать Вашего сообщения в нижние две строки экрана, которые выполняют роль "системного окна". Это те самые строки, в которых появляется информация при работе команды INPUT.

5.2 Прочие каналы.

После подключения дополнительной периферии, располагающей своим ПЗУ, к стандартным каналам могут добавляться дополнительные. Так, например, подключение ИНТЕРФЕЙСа-1 (ZX-INTERFACE 1) создает для пользователя несколько новых каналов:

- "M" - канал микродрайва;

- "N" - канал локальной сети;

- "T" - канал принтера для печати программ (коды выше 165

интерпретируются, как токены ключевых слов "Спектрума").

- "B" - канал принтера для печати данных (все коды

интерпретируются по своему значению).

Дисковые интерфейсы могут добавлять дополнительно свои каналы, например, канал "D" и т. п. Но у Вас есть возможность и для создания собственных каналов. Вы можете создавать их в оперативной памяти и эффективно использовать. Такие каналы мы будем называть пользовательскими, но для того, чтобы научиться их создавать, нам надо ознакомиться с ОБЛАСТЬЮ ИНФОРМАЦИИ О КАНАЛАХ.

Вся концепция каналов и потоков базируется на существовании в оперативной памяти компьютера области, называемой "Областью информации о каналах". Эта область лежит непосредственно перед БЕЙСИК-областью, чуть ниже ее. То есть, она лежит между системными переменными и БЕЙСИКом. Начинается она с адреса, на который указывает системная переменная CHANS, расположенная по адресу 5C4FH (23631) и заканчивается байтом, в котором стоит маркер 8 0H. Далее уже идет Ваша БЕЙСИК-программа, на начало которой, как известно, указывает системная переменная PROG, расположенная по адресу 5C53H (23635) .

Для того, чтобы создать свой канал, Вам практически надо переорганизовать данные в этой области, может быть и раздвинуть эту область, переместив вверх маркер и поменяв значение PROG, а также разместить в памяти две процедуры. Одну - для обеспечения ввода в Ваш канал (INPUT) и вторую - для обеспечения вывода -(PRINT) .

Каждый канал должен иметь блок информации о канале -CHANNEL INFORMATION BLOCK (CIB) . Он и располагается в области информации о каналах. В этом блоке содержится вся информация, необходимая для того, чтобы канал мог функционировать. Аан-дартные каналы "K", "S", "P" имеют каждый по пятибайтному блоку, но это исключение. Все остальные каналы, в том числе и те, которые создадите Вы, должны иметь в этом блоке не менее, чем по 11 байтов.

Блок CIB для стандартного канала.

Байты 0 и 1 - адрес процедуры вывода (PRINT # ) ;

Байты 2 и 3 - адрес процедуры ввода (INPUT # ) ;

Байт 4 - имя канала (код одной буквы - "K", "S" и т.п.) .

Блок CIB для канала, создаваемого стандартной периферией

Если при подключении стандартных периферийных устройств создаются новые каналы, то блок информации имеет длину в 11 байтов и более. Обычно адресуются к данным, имеющимся в этом

блоке путем индексной адресации, поместив в регистр IX базовый адрес начала блока. Так, например, при подключении ИНТЕРФЕЙСа-1 блоки дополнительных каналов имеют следующий формат:

IX+0

2

байта)

- адрес

процедуры

обработки

ошибок 000

IX+2

2

байта)

- адрес

процедуры

обработки

ошибок 000

IX+4

1

байт) -

имя канала.

IX+5

2

байта)

- адрес

процедуры

PRINT#.

IX+7

2

байта)

- адрес

процедуры

INPUT#.

IX+9

2

байта)

- длина

данного блока (не менее 0 0 0BH)

IX+0B

(длина любая) -

любая дополнительная

информация

Блок

CIB для

канала,

создаваемого пользователем.

IX+0

(2

байта)

- адрес процедуры вывода (PRINT#) .

IX+2

(2

байта)

- адрес процедуры ввода (INPUT#) .

IX+4

(1

байт)

- имя канала.

IX+5

(2

байта)

- число "1234" - оно свидетельствует о том, что канал - пользовательский.

IX+7

(2

байта)

- адрес закрывающей процедуры CLOSE#.

IX+9

(2

байта)

- длина данного блока (не менее 000BH)

IX+0B (длина любая) - любая дополнительная информация, 5.4 Подключение потоков.

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

Среди системных переменных компьютера, есть переменная STRMS. Ее адрес - 5C10H (23568) . Ее назначение - указание на адреса каналов, подключенных к потокам. Длина этой переменной - 38 байтов и, если говорить откровенно, то никакая это не переменная, а самая настоящая указательная таблица, в которой каждому потоку отдано по 2 байта для того, чтобы хранить в них адрес канала, к которому подключен данный поток.

Внимательный читатель, конечно заметил, что 16 потоков по 2 байта на поток составляет 32 байта, а системная переменная

STRMS имеет почему-то 38 байтов. Дело в том, что есть еще три системных потока, занимающиеся своими "внутренними" делами при работе ПЗУ. Это "минус третий" поток (FD) , "минус второй" (FE) и "минус первый" (FF) . Таким образом, таблицу STRMS можно представить, как 19 двухбайтных системных переменных:

STRMS_FD 5C10 (23568) STRMS FE 5C12 (23570)

STRMS_0F 5C3 6 (23606)

Поток FD подключен к каналу "К" и не должен переподключаться. Аналогично поток FE подключен к каналу "S". Интересен поток FF, который подключен к "внутреннему" каналу "R" (мы о нем не упоминали, поскольку маловероятно, чтобы им пришлось кому-либо пользоваться) , который занимается организацией

динамического копирования информации из одних областей памяти в другие, производя при этом "раздвигание" информации для вставки новой в середину имеющейся.

Итак, с помощью таблицы переменных STRMS выполняется привязка потоков к каналам. Если какая-либо переменная из набора STRMS содержит 0000, то это означает, что к данному потоку не подключен ни один канал, иначе коворя, канал закрыт. Если же там не ноль, значит канал открыт и этот поток подключен к этому каналу. Фактически же поток подключен к тому каналу, информационный блок CIB которого находится по адресу, на который указывает системная переменная CHANS плюс величина, содержащаяся в STRMS для данного потока минус единица:

(CHANS) + (STRMS_n) -1

5.5.Практические приемы работы с каналами и потоками.

Итак, мы знаем, что информация о каналах хранится в ОЗУ, в ОБЛАСТИ ИНФОРМАЦИИ О КАНАЛАХ в виде блоков информации о канале. Конечно, при включении компьютера там ничего пока нет, а информация эта содержится только в ПЗУ и при инициализации системы копируется в ОЗУ. Такое двойное хранение информации сделано в качестве шага навстречу пользователю, ведь в ОЗУ он может менять информацию так, как ему необходимо. Рассмотрим, например, как выглядит в ОЗУ блок информации по каналу "S" (он

Адрес Содержимое Комментарий

23739 244 9*256 + 244 = 2548 - адрес процедуры

23740 9 обслуживания канала при выводе.

23741 196 21*256 + 196 = 5572 - адрес процедуры

23742 21 обслуживания канала при вводе.

23743 83 Код литеры "S"

Во многих фирменных программах для того, чтобы не искажать изображение на экране, полученное после загрузки фирменной экранной заставки, меняют адрес процедуры обслуживания канала "S" при выводе. Это делают подачей команд:

POKE 2 3739, 82 POKE 2 3740,0

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

Так происходит потому, что в ПЗУ по адресу 82 (0052H) записана команда RET (код C9H) и обращение туда в момент вывода информации на экран приводит просто к возврату и все. В ПЗУ имеются сотни адресов, в которых записана команда RET и использовать здесь можно было бы любую.

Использование же для этих целей команды CLOSE#2 - неприем-

лимо .

После загрузки всех блоков программы адрес процедуры вывода восстанавливается.

POKE 23739,244 POKE 2 3740,0

Этот нехитрый прием пользователи могут применять и в своих целях.

Другое, не менее интересное применение концепции каналов и потоков для практических целей - для защиты своей программы от несанкционированного вмешательства. Это делается изменением информации о канале "R", который используется системой

компьютера при работе внутреннего редактора. Достаточно

записать:

POKE 23744,124 POKE 2 3745,0

- и редактирование Вашей программы станет невозможным.

Аналогичные эффекты можно получить, манипулируя не с данными в области информации о каналах, а с данными в системной переменной STRMS (23568) . Так как каналы связаны с определенными потоками, то переподключая потоки к другим каналам, получим новые эффекты. Например, чтобы запретить вывод на экран информации о программе при загрузке ее с магнитофона, достаточно записать в ячейку 23570 через команду POKE вместо числа 6 число 16, переподключив поток-2, связанный с каналом "S" на канал "P", обеспечивающий вывод на "ZX-принтер".

Переподключать стандартные каналы к потокам можно и из БЕЙСИКа с помощью символа "хэш" - "#". Попробуйте ввести программу и запустить ее:

10 PRINT #0; "Текст в нижней части экрана": PAUSE 0

20 LPRINT #2 ; " Те кст в в е рхне й части экрана" : PAUS E 0

30 L PRINT #3: "Текст на принтере": PAUSE 0

40 LIST #1

Вы убедитесь, что знакомые Вам операторы БЕЙСИКа работают несколько необычно.

Кроме системных переменных CHANS (23 631/2) и STRMS (23568), хранящих информацию о каналах и потоках, существует еще системная переменная CURCHL (5C51H - 23633), в которой записан адрес активизированного в данный момент канала. Именно значение этой переменной и используется командой вывода на печать RST 10H.

При работе со стандартными каналами компьютера, Вам может потребоваться еще и информация о некоторых флаговых системных переменных: FLAGS (5C3BH = 23611), FLAGS2 (5C6AH=2 3 658) и TVFLAG ( 5C3CH = 2 3 612) .

Нулевой бит переменной TVFLAG информирует систему о том, используется ли верхняя часть экрана (бит равен 0) или нижняя (бит равен 1) .

Первый бит переменной FLAGS указывает на то, должен ли символ выводиться на принтер (бит равен 1) или на экран (бит равен нулю).

Четвертый бит системной переменной FLAGS2 определяет, является ли канал "K" рабочим (бит включен) или нерабочим (бит выключен) в текущий момент.

Выше мы говорили о том, что информация о каналах в компьютера записана дважды - в ПЗУ и затем скопирована в ОЗУ. Этим можно воспользоваться, например для того, чтобы вообще убрать из ОЗУ информацию о каналах и оставить ее только в ПЗУ. А за счет освободившегося при этом места можно увеличить БЕЙСИК-область компьютера на 21 байт. Это, конечно, немного, но зато интересен сам подход:

10

POKE

23635,

PEEK

23631

20

POKE

23636,

PEEK

23632

30

POKE

23631,

175

40

POKE

23632,

21

Здесь в строках 10 и 20 меняется значение системной переменной PROG, указывающей на начало БЕЙСИК-программы. Теперь она будет начинаться не с адреса 23755, а с адреса 23734. В строках

же 3 0 и 4 0 в системную переменную CHANS записывается начальный адрес области информации о каналах, находящейся в ПЗУ.

Весьма полезной, особенно для создателей обучающих программ, может быть следующая процедура, которая несколько меняет действие команды PRINT. При использовании этой процедуры по команде PRINT информация на экран будет выводиться с временной паузой между отдельными символами и с генерацией короткого звукового сигнала после вывода каждого символа. Причем величиной паузы можно регулировать какой-то обучающий момент программы, например в программах, развивающих чтение или скорочтение. Эффект имитации телетайпа, кроме того, вносит разнообразие в работу программы (вспомните, например, игровую программу Black Hawk) .

10 BEEP

2 0 CURCHL

30 TIME

40

50 PRINT

60 START

70 80

EQU 949 EQU 63 633 EQU 65300 ORG 65301 DEFW 2548 PUSH AF LD A, I

JR PO,NOPAUSE

90

LD A, (TIME)

100

LD B, A

110

PAUSE

HALT

120

DJNZ,PAUSE

130

NOPAUSE

POP AF

140

CP 33

150

JR C,NOBEEP

160

PUSH AF

170

PUSH IX

180

LD DE,50

190

LD HL, 10 0

200

CALL BEEP

210

POP IX

220

POP AF

230

NOBEEP

LD HL,(PRINT)

240

CALL 111,

250

LD HL,(CURCHL

260

LD BC,START

270

LD E, (HL)

280

LD (HL),C

290

INC HL

300

LD D, (HL)

310

LD (HL),B

320

LD A, B

330

CP D

340

JR NZ,CHNG

350

LD A, C

360

CP E

370

RET Z

380

LD (PRINT),DE

390

RET

Запуск этой процедуры может показаться несколько необычным. Для ее вызова не надо давать ни традиционную команду RANDOMIZE USR, ни похожие на нее PRINT USR, RESTORE USR и т.п. Для того, чтобы эта процедура выполнялась, достаточно записать в области информации о каналах в ячейках, отведенных для хранения адреса вызова процедуры, обслуживающей канал "S",

адрес начала этой процедуры. Стандартно там записан адрес 2548, а мы с помощью POKE запишем туда адрес 65303.

POKE 23739, 23 POKE 23740,255

Теперь по команде процессора RST 10H (вывод символа на экран) будет вызываться не процедура ПЗУ, а созданная нами

процедура из адреса 65303. Временная пауза между выводимыми символами задается путем записи с помощью команды POKE соответствующего числа от 1 до 10 в ячейку 65300.

Пояснения к процедуре:

В строках 50...80 выполняется проверка на разрешение прерываний. Если прерывания запрещены, то выполняется переход на метку NOPAUSE, иначе программа может зависнуть на команде HALT в строке 110.

В строках 90...120 организуется цикл, длина которого берется из ячейки 65300 и устанавливается в регистре A, а затем B. В этом цикле находится команда HALT, которая и обеспечивает необходимую задержку по времени при печати символов.

В строках 130. . .150 проверяется код вводимого символа. Если его код менее 33, то это не печатаемый символ, а управляющий код или пробел и при его выдаче не надо давать звуковой сигнал. Поэтому выполняется переход к NOBEEP, обходя выдачу звукового сигнала.

Поскольку обработка управляющих кодов происходит с использованием других процедур, то прямой вызов CALL 2548 может привести к ошибке или потере управляющего кода. Поэтому

выполняется CALL 111. По адресу 111 в ПЗУ записана команда JP(HL). Таким образом мы реализуем несуществующую в АССЕМБЛЕРе процессора Z-8 0 команду CALL (HL) и выполняем переход по адресу, записанному в регистровой паре HL (строка 230) .

Внутри процедур обработки управляющих кодов имеются команды, которые меняют содержимое байтов области информации о каналах. Поэтому в строках 250. . .310 выполняется проверка записанного для канала "S" адреса процедуры вывода и восстановление адреса 65303, а затем восстановление, при необходимости, переменной PRINT (строки 320...390) .

Данная процедура прекрасно работает только до момента, пока не будет выполнена команда CLS. Эта команда восстанавливает в области информации о каналах стандартные адреса процедур вывода. Чтобы вернуть прежнее действие команде PRINT, необходимо опять же с помощью команды POKE записать в ячейки 23739/40 адрес 65303. И так поступать после каждой команды CLS или нажатия клавиши ENTER.

Естественно, это не совсем удобно, поэтому лучшим решением будет открытие нового пользовательского канала, адреса процедур ввода-вывода которого будут оставаться незыблемыми все время, пока включен компьютер. Для этого необходимо расширить область информации о каналах на 5 байтов, в которых записать адреса соответствующих процедур ввода и вывода и имя нового канала. Выполняется это с помощью процедуры ПЗУ MAKE_ROOM, находящейся по адресу 5717 (1655H) . При этом перед вызовом этой процедуры в регистровую пару HL необходимо записать начальный адрес резервируемой области, а в регистровую пару BC - количество байтов. При использовании этой процедуры автоматически изменяются системные переменные, определяющие адреса отдельных блоков БЕЙСИК-области. Ниже представлена программа, позволяющая создать нужный нам канал:

10 FOR n = 2 3 2 9 6 TO 2330 4: READ a: POKE n,a: NEXT n 20 DATA 1,5,0,33,202,92,195,85,22 30 RANDOMIZE USR 23296 40 RESTORE 60

5 0 FOR n=2 3 7 5 4 TO 23758: READ b: POKE n,b: NEXT n 60 DATA 23, 255, 196, 21, 83 70 STOP

После выполнения этой программы Вам остается только подключить новый канал к потоку_2 командой POKE 23578,21. Теперь можно не заботиться о необходимости восстановления адреса созданной процедуры в области данных о каналах.




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
For Coderz - Программирование под DNA_OS ZET-9, пакет утилит для работы с устройствами хранения данных.
Раскрутка - Описание адвентюрных и стратегических игр: Appolo и Чужой, Lord of Chaos, War Game 1, Страна Мифов, Sorcerer Lord.
Букашка - нова рубрика газеты.
Анкета - Неаvеn Aеrорlаnе.
Реклама - Реклама и объявления ...

В этот день...   19 марта