ежиме умеренного разрешения цепочка битов 10000011 описывает 4 точки, первая из которых имеет цвет 2, сле- дующие 2 - фоновый цвет, а последняя - цвет 3. Эта цепочка соот- ветствует числу 131 или &H83 (см. приложение Б, в котором обсуж- даются битовые операции в Бейсике). Обращение этой цепочки в 11000010 даст 193 (&HC1). Они могут быть объединены в элемент орнамента шириной в 4 точки и высотой в 2 строкой CHR$(&H83) + CHR$(&HC1). В такую строку могут включаться до 8 байтов, доводя высоту до 8 точек. Такая строка используется в операторе PAINT вместо цвета. Вот вывод квадрата, заполненного описанным орнамен- том: 100 LINE (100,110)-(150,150),1,B 'рисуем рамку 110 PAINT (125,125),CHR$(&H83)+CHR$(&HC1),1 'заполняем ее Отметим, что нерегулярности элемента орнамента могут приводить к тому, что процедура PAINT завершается, не закончив заполнения области. Бейсик решает эту проблему указанием параметра фона для оператора PAINT. Если у Вас возникнут проблемы, обращайтесь к руководству по Бейсику за деталями. Оператор DRAW, позволяющий рисовать сложные линии, также может заполнять области. Он обсуждается в [4.4.5]. "Текущая точка" (из которой будет рисоваться следующий сегмент линии) должна быть помещена внутрь области, ограниченной границей указанного цвета. В строку оператора DRAW надо поместить кодовую букву P, за кото- рой должен следовать код цвета закраски и код цвета границы. Для вывода рамки цветом 1 палетты, а затем ее заполнения цветом 3 напишите DRAW "U10R10D10L10BH1P3,1". Здесь первые четыре кода рисуют границы рамки, затем код 'BH' перемещает текущую точку внутрь рамки, не рисуя линии, а затем код 'P' приводит к заполне- нию рамки. Таким образом могут быть заполнены и более сложные формы. Отметим, что необязательно при перемещении точки внутрь области отменять рисование линии вдоль этого пути. Однако, в этом случае надо использовать для этого сегмента код цвета, отличный от цвета заполняемой границы. Бейсик имеет также возможность заполнения областей экрана заранее подготовленным изображением. Изображение может быть любо- го размера, может быть выведено в любой позиции экрана и хранится в массиве. Обычно, изображение создается с помощью всех доступных средств, а затем запоминается в массиве оператором GET. Массив может быть помещен в последовательный файл [5.4.3], из которого программа может загрузить его и вывести изображение. Оператор GET перечисляет координаты левого верхнего и правого нижнего угла рамки, содержащей изображение, причем сначала идет номер столбца, а затем номер строки для каждой пары координат. Затем должно следовать имя массива, которое не заключается в кавычки. Напри- мер, GET (80,40)-(120,60),ARRAY3 помещает все точки, находящиеся внутри указанной области в массив с именем ARRAY3. Одномерные массивы, как и все остальные, должны быть предвари- тельно описаны оператором DIM. Массив может содержать элементы любой точности. Для вычисления требуемых размеров массива надо сначала определить сколько байтов потребуется для хранения изоб- ражения. Это можно вычислить по формуле 4 + INT ((x*битовнаточку + 7)/8)* y. Здесь "битовнаточку" равно 1 для высокого разрешения и 2 - для умеренного разрешения. Буквы x и y относятся к числу точек вдоль горизонтальной и вертикальной сторон блока изображе- ния. INT обозначает целую часть числа. Наконец, надо определить сколько элементов массива требуется для хранения данного числа байтов. Каждый элемент занимает 2 байта в целом массиве, но 4 - для чисел с обычной точностью и 8 - для чисел с двойной точно- стью. Для получения изображения из массива и вывода его на экран используйте оператор PUT. Этот оператор требует только координаты левого верхнего угла области экрана, в которую будет выводиться изображение. За координатами должно быть указано имя массива. Например, PUT (40,30),ARRAY1 помещает изображение, левый верхний угол которого будет находиться в столбце 40 и строке 30. Оператор PUT может иметь еще и необязательный параметр, определяющий цвет, которым будет выводиться изображение. Если этот параметр опущен, то изображение будет выводиться точно в том виде, в котором оно было записано оператором GET. Это эквивалентно записи PUT (40,30),ARRAY1,PSET. В противном случае имеются некоторые другие возможности. Если Вы вместо PSET укажете PRESET, то цвет 0 палет- ты будет заменен на цвет 3 и наоборот, а цвет 1 палетты - на цвет 2 и наоборот. Имеются еще три случая, использующие логические операции AND, OR или XOR. Как и PRESET эти слова могут заменять PSET в приве- денном примере. Обсуждение этих трех операций смотрите в приложе- нии Б. Каждая операция включает сравнение битов существующей точки на экране с битами точки накладываемого изображения. В режиме высокого разрешения, когда на точку отводится только 1 бит операция простая. Но в режиме умеренного разрешения, в котором на каждую точку отводится 2 бита, могут происходить различные транс- формации цветов. AND устанавливает бит только если он был установлен и у точки экрана и у точки изображения (взятой из массива). В режиме высо- кого разрешения это означает, что точка изображения появится на экране только если соответствующая точка экрана уже "включена". Все остальные точки области будут выключены. В режиме умеренного разрешения операция производится над обоими битами. Если для точки экрана установка битов 01, а для соответствующей точки изображения - 10, то оба бита будут сброшены и точка экрана полу- чит код 00, что соответствует фоновому цвету. OR устанавливает бит, если он был установлен либо для точки экрана, либо для точки изображения. В черно-белом режиме OR нак- ладывает изображение на существующее изображение на экране. В цветном режиме для определения эффекта Вы опять должны прибегнуть к вычислениям. Комбинация кодов палетты 1(01) и 2(10) дает 3(11), также как и комбинация 0(00) и 3(11). И, наконец, XOR устанавливает бит, если из двух сравниваемых только один был установлен. Применение этой операции для чер- но-белого экрана с массивом единиц дает негативное изображение (1 и 1 дает 0, а 1 и 0 - дает 1). В режиме умеренного разрешения эта операция меняет все цвета. В результате получаем наложение двух изображений. Но более важно, что при повторении этой операции экран принимает в точности такой же вид, который он имел первона- чально. При этом изображение стирается. Эта техника полезна для мультипликации, когда над изображением дважды производится опера- ция XOR в одной позиции, затем в соседней и т.д. Низкий уровень. Имеется много подходов к написанию процедур заполнения графи- ческих объектов. Ни один из них не является идеальным, поскольку всегда имеется конфликт между скоростью работы процедуры и слож- ностью фигур, которые она может обрабатывать. Любая процедура, которая заполняет область точку за точкой будет медленной, неза- висимо от того, насколько элегантно она реализована. Имейте вви- ду, что почти каждая модифицируемая точка расположена в байте, все точки которого будут изменяться в тот же самый цвет. Получе- ние доступа к одному и тому же байту с использованием сложных процедур требует существенно больше времени, чем установка целого байта за один доступ к ячейке видеобуфера. Например, поточечная очистка экрана требует на IBM PC нескольких секунд при использо- вании функции BIOS, в то время как прямой доступ в память произ- водит эту операцию мгновенно: MOV AX,0B800H ;ES указывает на буфер экрана MOV ES,AX ; MOV CX,8192 ;заполняем все байты MOV AX,0 ;в каждый байт пишем 0 MOV DI,0 ;DI поочередно указывает на все байты REP STOSW ;повторяем запись 8192 раза Многие процедуры заполняют по одной горизонтальной строке, проверяя на цвет границы справа и слева. Поскольку строки состоят из смежных байтов данных, то надо поочередно брать байты из ви- деобуфера и проверять присутствует ли в них цвет границы. Если цвет границы отсутствует, то можно заменить сразу весь байт на цвет заполнения. В противном случае к данному байту применяется поточечный подход. Имеется очень быстрый способ определения присутствует ли гра- ничный цвет в данном байте видеобуфера. Предположим, что процеду- ра ищет цвет 1 палетты в режиме умеренного разрешения с четырьмя цветами. Этому цвету соответствует код 01, поэтому сначала запол- ним весь байт этим кодом: 01010101. Затем используем операцию NOT для обращения каждого бита, после чего байт примет вид 10101010. Проделаем операцию XOR со значением взятым из видеобуфера; в результате получим байт, у которого оба бита, относящиеся к одной точке равны 1 только для точек, имеющих граничный цвет. Затем снова используем операцию NOT с тем, чтобы пара битов, относящих- ся к точке граничного цвета имела код 00. После этого используем операцию TEST для нахождения полей со значением 00. Если такое поле найдено, то граничный цвет обнаружен и процедура переходит к обычному поточечному анализу данного байта. Эту процедуру можно еще убыстрить, если использовать словные данные. MOV AL,ES:[BX] ;берем байт из видеобуфера XOR AL,10101010B ;устанавливаем биты для цвета границы NOT AL ;обращаем биты TEST AL,11000000B ;проверяем биты 7-6 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00110000B ;проверяем биты 5-4 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00001100B ;проверяем биты 3-2 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00000011B ;проверяем биты 1-0 JZ FOUND_BOUND ;переход если граничный цвет MOV AL,FILL_COLOR ;граничного цвета нет, заполняем байт MOV ES:[BX],AL ;возвращаем байт в видеобуфер . . FOUND_BOUND: Когда это возможно, постарайтесь, чтобы границы прямоугольных областей Ваших картинок были выравнены на границу двух, четырех или восьми точек, с тем чтобы прямое отображение в память имело дело с целыми байтами. Другая возможность, хотя и не столь быст- рая, состоит в создании определяемых пользователем псевдографи- ческих символов [4.3.4] и выводе их на границе области заполне- ния. Короче, в данной области Вы имеете все возможности проявить сообразительность, а зачастую стоит подумать, а нужна ли Вам столь сложная графика в данной задаче. 4.4.7 Графический вывод с использованием символов псевдографики. Когда Вы выводите изображение точка за точкой, то это отнимает очень много времени, особенно когда создаются эффекты мультипли- кации. Один из способов экономии времени состоит в сведении всех или части выводимых форм к фигурам, которые могут быть построены на матрице точек 8*8. Такие фигуры могут быть созданы, как опре- деляемые пользователем символы, как показано в [4.3.4]. После того, как эти символы определены они выводятся на экран очень быстро и просто. Эти символы могут выводиться вперемешку с пото- чечными графиками, как обычные буквы. Один из способов быстрого заполнения фигуры состоит в последовательном выводе внутри фигуры полностью закрашенного блока. Отметим, что эти символы всегда располагаются в стандартных позициях курсора. Средний уровень. В этом примере рисуется фигура человека, занимающая 2 символа в высоту и 2 символа в ширину. Как объяснено в [4.3.4] вектор прерывания 1FH указывает на начало области данных, определяющих символы. Четыре символа могут быть выведены обычными процедурами DOS или BIOS. Легко создать другой набор символов, для вывода фигуры с руками и ногами в другом месте экрана. Два набора симво- лов могут поочередно меняться в соседних позициях курсора, созда- вая иллюзию человека, идущего по экрану. ;---в сегменте данных CHARACTER_DATA DB 00110000B ;левый верхний квадрант DB 01100111B DB 01100111B DB 00110011B DB 00011111B DB 00001111B DB 00001111B DB 00000111B DB 00000011B ;правый верхний квадрант DB 10001100B DB 10011000B DB 00110000B DB 11100000B DB 11000000B DB 11000000B DB 10000000B DB 00001111B ;левый нижний квадрант DB 00011111B DB 00011100B DB 00011000B DB 00011000B DB 00110000B DB 01100000B DB 00010000B DB 11000000B ;правый нижний квадрант DB 11000000B DB 11000000B DB 11000000B DB 01100000B DB 01100000B DB 00010000B DB 00011110B DB 00000000B ;---установка вектора прерывания PUSH DS ;сохраняем DS MOV DX,OFFSET CHAR_DATA ;смещение для данных в DX MOV AX,SEG CHAR_DATA ;сегмент для данных в DS MOV DS,AX ; MOV AH,25H ;функция установки вектора MOV AL,1FH ;номер вектора INT 21H ;устанавливаем вектор POP DS ;восстанавливаем DS ;---рисуем фигуру ;---позиционируем курсор на верхний ряд MOV AH,2 ;функция установки курсора MOV DH,13 ;строка 13 MOV DL,20 ;столбец 20 MOV BH,0 ;страница 0 INT 10H ;установка курсора ;---рисуем верхние два символа MOV DL,128 ;берем символ 128 MOV AH,2 ;функция вывода/курсор вперед INT 21H ;вывод символа MOV DL,129 ;берем символ 129 INT 21H ;выводим его ;---позиционируем курсор на нижнюю строку MOV DH,14 ;строка 14 MOV DL,20 ;столбец 20 MOV AH,2 ;функция установки курсора INT 10H ;устанавливаем курсор ;---рисуем нижние два символа MOV DL,130 ;берем символ 130 MOV AH,2 ;функция вывода/курсор вперед INT 21H ;вывод символа MOV DL,131 ;берем символ 131 INT 21H ;выводим его Раздел 5. Сдвиг экрана и страницы. Сдвиг экрана и разбиение на страницы - это два способа перено- са блока информации из памяти на экран. При сдвиге одна из границ экрана сдвигается внутрь, стирая информацию на противоположной стороне. Затем освободившаяся область заполняется из памяти. Повторение этого действия строка за строкой создает иллюзию сдви- га экрана. С другой стороны, разбиение на страницы основано на одновре- менном хранении нескольких экранов информации в видеобуфере и переключении вывода с одной страницы на другую. Использование дисплейных страниц невозможно на монохромном адапторе, поскольку его памяти хватает только для одного символьного экрана. Другие видеосистемы в большинстве экранных режимов могут работать с несколькими страницами. Использование страниц дисплея особенно полезно при построении сложных картин "за кулисами"; после того как эта работа завершена, новый экран выводится моментально. Процедура, имитирующая работу со страницами для монохромного адаптора приведена в [4.5.3]. Она особенно полезна, когда Вы имеете дело с медленным выводом на экран в Бейсике. 4.5.1 Вертикальный сдвиг текстового экрана. Когда текстовый экран сдвигается вверх, то строки со 2-й по 25-ю переписываются на строки с 1-й по 24-ю, а следующая строка данных выводится в 25-й строке. При этом верхняя строка, поверх которой осуществлется вывод теряется, хотя она продолжает су- ществовать в памяти. Сдвиг вниз устроен аналогично. Высокий уровень. Бейсик утомительно медлителен при своих манипуляциях с экра- ном. Для быстрого сдвига Вы можете пожелать использовать процеду- ру на машинном языке, которая не делает ничего другого, кроме как использует прерывание 10H, как описано ниже в пункте средний уровень. Процедура позволяет сдвигать весь экран или любое окно в нем. Приложение Г показывает как включать подпрограммы на машин- ном языке в Ваши программы. Ваша программа на Бейсике должна указывать координаты верхнего левого и нижнего правого углов окна, которые могут лежать в диапазоне от 0 до 24 и от 0 до 79. Требуется также параметр, указывающий направление сдвига: вверх или вниз (6 и 7, соответственно), число строк на которое нужно сдвинуть (если 0, то окно очищается) и значение байта атрибутов для очищаемых строк (для "нормальных" - 7). Используйте для них целые переменные. В нижеприведенно примере экран сдвигается вниз на одну строку, а затем освободившаяся строка освобождается. 100 '''данные для подпрограммы 110 DATA &H55, &H8B, &HEC, &H8B, &H76, &H12, &H8A 120 DATA &H24, &H8B, &H76, &H10, &H8A, &H04, &H8B 130 DATA &H76, &H0E, &H8A, &H2C, &H8B, &H76, &H0C 140 DATA &H8A, &H0C, &H8B, &H76, &H0A, &H8A, &H34 150 DATA &H8B, &H76, &H08, &H8A, &H14, &H8B, &H76 160 DATA &H06, &H8A, &H3C, &HCD, &H10, &H5D, &HCA 170 DATA &H0E, &H00 180 '''помещаем данные в сегмент &H2000 190 DEF SEG = &H2000 'помещаем данные начиная с &H2000 200 FOR N = 0 TO 43 '44 байта 210 READ Q 'читаем один байт 220 POKE N,Q 'помещаем его в память 230 NEXT 'следующий 300 '''в программе 310 GOSUB 500 'сдвигаем на строку 320 LOCATE 1,1: PRINT TEXT$(LINEPTR); 'выводим строку текста 500 '''подпрограмма сдвига 510 DEFINT A-Z 'используем целые переменные 520 TLR = 0 'левая верхняя строка 530 TLC = 0 'левый верхний столбец 540 BRR = 24 'нижняя правая строка 550 BRC = 79 'нижний правый столбец 560 NUMROWS = 1 'число строк сдвига 570 DIR = 7 'направление сдвига вниз 580 FILL = 7 'заполнение обычным атрибутом 590 DEF SEG = &H2000 'указываем на подпрограмму 600 SCROLL = 0 'начинаем с 1-го байта 610 CALL SCROLL(DIR,NUMROWS,TLR,TLC,BRR,BRC,FILL) 620 RETURN 'все сделано Средний уровень. Функция 6 прерывания 10H сдвигает любую часть экрана вверх, а функция 7 - вниз. В обоих случаях AL содержит число строк сдвига, а когда AL = 0, то весь экран чистится, а не сдвигается. CH:CL содержат строку и столбец левого верхнего угла, а DH:DL - содер- жат координаты правого нижнего угла. Появлящиеся из-за сдвига строки чистые и они выводятся с кодом атрибутов из BH. ;---сдвиг вверх на одну строку MOV AH,6 ;номер функции сдвига вверх MOV AL,1 ;число строк сдвига MOV CH,0 ;строка левого верхнего угла MOV CL,0 ;столбец левого верхнего угла MOV DH,24 ;строка правого нижнего угла MOV DL,79 ;столбец правого нижнего угла MOV BH,7 ;атрибуты очищаемой строки INT 10H ;делаем сдвиг Низкий уровень. Вертикальный сдвиг всего экрана это тривиальная задача, пос- кольку правая граница одной строки в памяти продолжается левой границей следующей строки. Сдвиг всего содержимого видеобуфера на 160 байт вверх по памяти (80 символов в строке * 2 байта на сим- вол) приводит к сдвигу экрана вниз на одну строку. Если Вы пишете свою собственную процедуру сдвига экрана, использующую прямое отображение в память, то не забывайте об интерференции, которая возникает на цветном дисплее и PCjr. Эта проблема обсуждается в [4.3.1]. Обычное решение этой проблемы состоит в проверке статус- ного байта, ожидая пока он разрешит запись в видеобуфер. Вам придется поэкспериментировать, чтобы определить сколько данных Вы можете записать за один цикл. Другое решение этой проблемы состоит в выключении экрана на время операции сдвига, а затем в его восстановлении. "Выключение экрана" подразумевает, что вывод содержащихся в видеобуфере дан- ных запрещен, но сам буфер при этом не изменяется. Этот процесс используется функцией сдвига BIOS, использованной выше. Хотя это не очень приятно для глаз, но все-таки не так плохо, как уже упоминавшаяся интерференция. Для выключения экрана у цветного графического дисплея надо сбросить бит 3 порта с адресом 3D8H. Изменение бита назад на 1 моментально включает экран обратно. Этот адрес порта соответст- вует регистру выбора режима цветного графического адаптора. Этот однобайтный регистр только для записи, поэтому программа не может просто прочитать его, изменить значение бита 3 и вернуть прочи- танный байт. Вместо этого Вам необходимо определить также пра- вильную установку всех остальных битов (перечисленных в [4.1.2]). Для PCjr этот бит расположен в регистре управления режимом 1 массива ворот дисплея. В [4.1.1] объяснено как получить доступ и запрограммировать этот регистр. 4.5.2 Сдвиг текстового экрана горизонтально. Горизонтальный сдвиг иногда требуется в специальных программах обработки текста, таких как текстовые редакторы. Операционная система не имеет для этого специальных средств. По этой причине данная задача немного сложнее чем вертикальный сдвиг - но несу- щественно. Рассмотрим случай, когда Вы хотите, чтобы экран сдви- гался влево на 5 позиций. При этом левые 5 столбцов исчезнут, весь остальной текст сдвигается влево, а самые правые 5 столбцов должны быть очищены. Поскольку видеобуфер представляет из себя одну длинную строку, то если каждый символ буфера сдвинуть на 10 байтов вниз, то суммарный эффект будет состоять в том, что самые левые 5 символов каждой строки будут передвинуты в последние 5 позиций предыдущей строки. Таким образом, весь экран будет сдви- нут влево на 5 позиций, передвигая 5 ненужных столбцов в правую часть экрана. Все что после остается - это очистить правые 5 столбцов. Это легко делается с помощью процедуры вертикального сдвига [4.5.1], которая может выполняться для любой части экрана и которая очищает указанную область если указать сдвиг на 0 строк. Рисунок 4-6 иллюстрирует этот метод. Низкий уровень. В этом примере осуществляется сдвиг на 5 позиций влево. Легко изменить его для сдвига вправо или для другого значения позиций сдвига. При использовании прямого отображения в память этот метод дает практически моментальный сдвиг экрана. ;---сдвигаем все вниз на 10 байтов MOV AX,0B000H ;указываем на буфер монохромного MOV ES,AX ;дисплея MOV DS,AX ; MOV SI,10 ;сдвигаем из SI ... MOV DI,0 ;... в DI MOV CX,1995 ;сдвигаем все кроме последних 5 байт REP MOVSW ;осуществляем сдвиг ;---очищаем правый край MOV AH,6 ;функция вертикального сдвига MOV AL,0 ;сдвиг на 0 строк чистит окно MOV CH,0 ;строка левого верхнего угла MOV CL,75 ;столбец левого верхнего угла MOV DH,24 ;строка правого нижнего угла MOV DL,79 ;столбец правого нижнего угла MOV BH,7 ;атрибут для очищаемых позиций INT 10H ;чистим окно 4.5.3 Переключение между текстовыми страницами. Поскольку все видеосистемы, кроме монохромного дисплея, имеют достаточно памяти для нескольких видеобуферов, то одновременно могут быть сконструированы несколько экранов, каждый из которых может быть выведен в нужный момент. Вместо того, чтобы передви- гать данные в видеопамяти, монитор посылает данные из другой области видеопамяти. Число доступных страниц может меняться в зависимости от видеосистемы и режима дисплея. Приводим краткую сводку: Режим Тип Число страниц Начало буфера 0 алфавитноцифровой 8 B800 1 алфавитноцифровой 8 B800 2 алфавитноцифровой 8 B800 3 алфавитноцифровой 8 B800 4 графический 1 B800 5 графический 1 B800 6 графический 1 B800 7 алфавитноцифровой 1/8 B800 8 графический переменное B800 9 графический переменное B800 A графический переменное B800 D графический 2/4/8 A000 E графический 1/2/4 A000 F графический 1/2 A000 10 графический 1/2 A000 Режимы 8-A - графические режимы PCjr; число страниц для них ме- няется в зависимости от того, сколько оперативной памяти отведено под видеобуфер. Размер страницы равен 2K или 4K для алфавитноциф- ровых режимов, 32K - для четырех цветов при высоком разрешении или 16 цветов при умеренном разрешении и 16K - для всех остальных режимов. Режимы D-10 поддерживаются EGA. Количество страниц ме- няется в зависимости от установленной памяти. Режимы F и 10 тре- буют наличия не менее 128K памяти. Режим 7 разрешает одну страни- цу для монохромного адаптора и 8 страниц для EGA. Монохромный адаптор не имеет памяти для дополнительных стра- ниц. Однако нет никаких причин, по которым часть основной памяти нельзя было бы использовать как буфер дисплея. В этом случае страничная организация осуществляется за счет быстрого обмена всего содержимого буфера в памяти с видеобуфером (адрес которого B000:0000). Буфер в основной памяти можно рассматривать как "псевдостраницу". Хотя это и не настоящее разбиение на страницы, но результат будет почти такой же, если для пересылки данных Вы будете использовать ассемблерную процедуру. При использовании страниц надо позаботиться о том, чтобы опе- рации вывода на экран направлялись на нужную страницу. Программа не обязана выводить данные на ту страницу, которая в данный мо- мент изображается на экране. На самом деле, часто наоборот жела- тельно конструировать экран "за кулисами", а затем моментально выводить уже готовое изображение. Этот метод особенно полезен, когда необходимо конструировать сложный вывод в Бейсике, у кото- рого вывод очень медленный. BIOS хранит в своей области данных однобайтную переменную, указывающую, какая из страниц выводится в данный момент. Диапазон значений этой переменной от 0 до 7. Она расположена по адресу 0040:0062. Высокий уровень. Бейсик использует команду SCREEN для установки страницы, на которую будет идти вывод (активной страницы) и выводимой страницы (видимой страницы). Страницы нумеруются от 0 до 3 для текстов с 80 символами в строке и от 0 до 7 для 40-символьных. Третий пара- метр за командой SCREEN устанавливает активную страницу. SCREEN,,2 приводит к тому, что все операторы PRINT будут работать со страницей 2. Четвертый параметр устанавливает видимую страни- цу. SCREEN,,,1 приводит к тому, что на экран будет выводиться страница 1. Когда видимая страница не указывается, то автомати- чески принимается, что она совпадает с активной. Для выделения памяти под страницы на PCjr используется опера- тор CLEAR. Этот оператор устанавливает общее количество памяти, отводимое под буфер экрана, которое при старте равно 16384 байта. Чтобы добавить вторую страницу размером 16K, напишите CLEAR,,,32768. Добавочные текстовые страницы требуют 4096 байтов каждая. При условии, что таким образом была отведена память, команды оператора SCREEN для работы со страницами работают опи- санным образом. Только PCjr имеет добавочный параметр оператора SCREEN, который стирает страницу (т.е. переводит ее в цвет фона). Детали описаны в руководстве по Бейсику. Оператор PCOPY также уникален для PCjr. Он копирует изображение из одной страницы в другую. Например, PCOPY 2,1 целиком копирует страницу 2 на стра- ницу 1. Хотя монохромный адаптор не имеет памяти для страниц дисплея, однако имеется способ устроить своего рода "псевдостраницы". Нижеприведенная процедура на машинном языке рассматривает блок памяти как дисплейную страницу. При вызове этой процедуры она обменивает содержимое видеобуфера с содержимым этой области памя- ти. В результате мы имеем как бы две дисплейные страницы. (В приложении Г объясняется как включать подпрограммы на машинном языке в программы на Бейсике.) Вы должны отвести блок памяти размером 4000 байт для псевдост- раницы, помимо памяти, содержащей программу на машинном языке. В примере блок начинается с адреса сегмента &H2000, а процедура помещена по адресу &H2200. Сегментный адрес блока содержится в 9-м и 10-м байтах машинного кода и Вы легко можете изменить его. Видно, что адрес &H2000 представлен как &H00, &H20 в операторе DATA. Это следствие того, что младшие цифры всегда размещаются в младших ячейках памяти. Если Вы хотите разместить блок, скажем по адресу 1234:0000, то надо изменить байты 9 и 10 на &H34, &H12. Вам может потребоваться очистить псевдостарницу от всякой ерунды, оставшейся от других программ. В строках 230-260 это достигается за счет засылки символа пробела (ASCII 32) в каждый байт (32 служит "нормальным" байтом атрибутов). Программа может осуществлять вывод на экран обычным образом, а затем переносить содержимое на псевдостраницу. Но если хотите, то Вы можете осу- ществлять вывод прямо на псевдостраницу, используя прямое отобра- жение в память. 100 '''машинный код 110 DATA &H1E, &H06, &HB8, &H00, &HB0, &H8E, &HC0 120 DATA &HB8, (3&H00, &H20), &H8E, &HD8, &HBF, &H00 130 DATA &H00, &HBE, &H00, &H00, &HFC, &HB9, &HD0 140 DATA &H07, &H26, &H8B, &H1D, &HAD, &HAB, &H89 150 DATA &H5D, &HFE, &HE2, &HF6, &H07, &H1F, &HCB 160 '''помещаем код в память 170 DEF SEG = &H2200 'указываем адрес процедуры 180 FOR N = 0 TO 34 'начинаем с первого байта 190 READ Q 'читаем байт процедуры 200 POKE N,Q 'пишем его в память 210 NEXT ' 220 '''чистим псведостраницу 230 DEF SEG = &H2000 'адрес начала псевдостраницы 240 FOR N = 0 TO 3999 'для каждого символа и атрибута 250 POKE N,32 'помещаем код 32 260 NEXT 'пока не очистим весь буфер 500 '''пишем прямо в псевдостраницу 510 DEF SEG = &H2000 'указываем на ее адрес 520 S$ = "PSEUDOPAGE" 'выводим слово посреди страницы 530 M = LEN(S$) 'получаем длину строки 540 FOR N = 1 TO M 'для каждого символа строки 550 POKE N*2+2000, ASC(MID$(S$,N,1)) 'помещаем его в буфер 560 NEXT ' 600 '''теперь используем процедуру 610 PRINT "SCRREN 1" 'печатаем сообшение на экран 620 DEF SEG = &H2200 'указываем на процедуру 630 PSEUDOPAGE = 0 'начинаем с начала процедуры 640 CALL PSEUDOPAGE 'обмениваем страницы 650 CALL PSEUDOPAGE 'повторяем обмен 660 ... Средний уровень. Функция 5 прерывания 10H выбирает текущую страницу дисплея для вывода. Надо просто поместить номер страницы в AL: ;---установка видимой страницы MOV AH,5 ;номер функции MOV AL,2 ;номер страницы (начиная с 0) INT 10H ;устанавливаем страницу Однако эта функция не устанавливает страницу, на которую будет идти вывод. Любое из прерываний BIOS, которые выводят на экран (функции прерывания 10H), требует чтобы номер страницы был указан в качестве входного параметра в одном из регистров. Однако все прерывания вывода на экран MS DOS пишут на текущую видимую стра- ницу. Таким образом, для "закулисных" операций Вам необходимо пользоваться прерыванием 10H. Для получения информации о текущей странице надо выполнить функцию F прерывания 10H, которая возвращает статус дисплея. Номер страницы при этом возвращается в BH. Низкий уровень. Дисплейные страницы выбираются за счет изменения точки видео- памяти, начиная с которой монитор принимает данные. Эта точка памяти устанавливается регистрами 12 (старший байт) и 13 (младший байт) микросхемы 6845, которые называются регистрами стартового адреса. Значения адресов раздела страниц для буфера, начинающего- ся с B800 такие: 40 символов 80 символов страница 0 0000H 0000H 1 0400H 0800H 2 0800H 1000H 3 0C00H 1800H 4 1000H 5 1400H 6 1800H 7 1C00H В [4.1.1] объясняется как программировать регистры микросхемы 6845, а в [4.5.4] содержится пример программирования стартового адреса. В последнем примере надо просто присвоить BX одно из значений вышеприведенной таблицы. Конечно, при этом устанавли- вается только выводимая страница. Для записи в определенную стра- ницу на низком уровне надо использовать одно из значений таблицы в качестве смещения в видеобуфере при прямом отображении в па- мять. Поскольку прямое отображение в память работает очень быстро, то иллюзия страниц может быть легко создана на монохромном дисп- лее. Выделите блок размером 4000 байтов для хранения страницы. Хотя монохромный адаптор не может непосредственно читать из обыч- ной памяти, содержимое этого буфера и видеобуфера можно обменять настолько быстро, что никто не зметит разницы. Следующая процеду- ра обменивает содержимое этих двух областей. ;---в сегменте данных PPAGE DW 2000 DUP(720H) ;заполняем буфер пробелами ;---пересылка между псевдостраницей и видеобуфером MOV AX,0B000H ;указываем на видеобуфер MOV ES,AX ; MOV AX,SEG PPAGE ;указываем на псевдостраницу MOV DS,AX ; REPEAT: MOV DI,0 ;DI на начало видеобуфера MOV SI,OFFSET PPAGE ;SI на начало псевдостраницы CLD ;направление вперед MOV CX,2000 ;будем пересылать 2000 слов NEXT_WORD: MOV BX,ES:[DI] ;берем слово из видеобуфера в BX LODSW ;слово из псевдостраницы в AX STOSW ;слово из AX в видеобуфер MOV DS:[DI]-2,BX ;слово из BX в псевдостраницу LOOP NEXT_WORD ; PCjr хранит регистр страницы в порте с адресом 3DFH. Значение битов этого регистра следующее: биты 2-0 какая страница выводится (от 0 до 7) 5-3 какая страница пишется (от 0 до 7) при выводе по адресу сегмента B800H 7-6 = 00 для всех текстовых режимов = 01 для графических режимов с 16K = 11 для графических режимов с 32K 4.5.4 Сдвиг между страницами текста. Поскольку страницы текста прилегают друг к другу в видеобуфе- ре, то небольшой текстовый массив может целиком помещаться в этой памяти. В этом случае текст сдвигаться вверх и вниз по экрану не передвигаясь реально в буфере. Вместо этого экран начинает пока- зывать содержимое буфера, начиная с различных точек и тем самым создавая иллюзию сдвига. Этот метод называется аппаратным сдви- гом. Аппаратный сдвиг достигается за счет изменения стартового адреса дисплея, который является числом, указывающим на символ в видеобуфере, который будет выводиться в левом верхнем углу экра- на. Добавление 80 к этому числу "сдвигает" весь экран на одну строку вверх, а вычитание 80 - на одну строку вниз. В режиме с 40 символами в строке надо вместо 80 прибавлять или вычитать 40. На рис. 4-7 приведена диаграмма аппаратного сдвига. Отметим, что регистр стартового адреса не считает байты атри- бутов, поэтому Вы должны вычислять адреса памяти по-другому, чем при прямом отображении в память. Имейте также ввиду, что несмотря на наличие разрывов памяти между границами страниц (96 байтов между 80-символьными страницами и 48 байтов между 40-символьными страницами) микросхема 6845 пропускает эти области и сдвиг непре- рывно происходит с одной страницы на следующую. Аппаратный сдвиг происходит настолько быстро, что Вам может оказаться необходимым вставить процедуру задержки, чтобы пользователь имел возможность увидеть насколько сдвинулся экран. BIOS хранит текущее значение регистра стартового адреса в переменной в своей области данных. Эта двухбайтная переменная расположена по адресу 0040:004EH. Низкий уровень. Стартовый адрес содержится в регистрах 12 (старший байт) и 13 (младший байт) микросхемы 6845. В [4.1.1] объясняется работа этой микросхемы. Прежде чем адресуемый байт направляется в порт с адресом 3D5H, необходимо послать номер адресуемого регистра в порт 3D4H. В данном примере экран сдвигается вверх на одну стро- ку. Переменная START_ADDRESS содержит адрес первого символа теку- щей верхней строки экрана. MOV BX,START_ADDRESS ;начинаем с начала буфера ADD BX,80 ;сдвигаем на 1 строку (80 символов) MOV DX,3D4H ;вывод в адресный регистр MOV AL,12 ;адресуем регистр 12 OUT DX,AL ;посылаем запрос INC DX ;теперь выводим в командный регистр MOV AL,BH ;старшее слово в AL OUT DX,AL ;посылаем его в регистр 12 DEC DX ;обратно к адресному регистру MOV AL,13 ;адресуем регистр 13 OUT DX,AL ;посылаем запрос INC DX ;снова командный регистр MOV AL,BL ;младшее слово в AL OUT DX,AL ;посылаем в регистр 13 Глава 5. Дисковые накопители. Раздел 1. Управление распределением диска. Все диски, как гибкие, так и жесткие, организованы одинаковым образом. Поверхность диска разделена на ряд концентрических ко- лец, называемых дорожками, а дорожки делятся радиально на секто- ра. Например, стандартная дискета с диаметром 5 1/4 дюйма имеет 40 дорожек и в системе MS DOS 2.0 каждая дорожка разбита на 9 секторов (15 секторов на дискете емкостью 1.2 Мбайта и 17 на фиксированном диске). Размер сектора 512 байт, и 512 байт * 9 секторов * 40 дорожек * 2 стороны дает в итоге емкость дискеты 360K. Все типы дисков используют размер сектора 512 байт в MS DOS. Файл распределен по такому количеству секторов, которое необ- ходимо, чтобы вместить его. Только несколько секторов на внешнем ободе дискеты зарезервированы для специальных нужд. Остальные доступны на основе правила "первый подошел - первого обслужат". Это означает, что по мере заполнения диска данными сектора посте- пенно заполняются по направлению к центру диска. При уничтожении файла сектора освобождаются и со временем свободные области ста- новятся разбросанными по диску, разбивая новые файлы и замедляя доступ к ним для чтения и записи. Фиксированные диски имеют некоторые специальные характеристи- ки. Часто они состоят из двух или более параллельных пластин, у каждой из которых есть две головки, чтобы читать обе их стороны. Все дорожки, расположенные на данном расстоянии от центра, вместе называются цилиндром. Поскольку головки всех дисков двигаются тандемом, то достигается экономия перемещений если заполнять все дорожки одного цилиндра, прежде чем переходить к следующему. Группы цилиндров могут относиться к различным операционным систе- мам. Программа DOS FDISK может разбивать фиксированный диск на несколько разделов (до четырех) разного размера. По этой причине параметры фиксированного диска могут сильно отличаться. Дисковые сектора определяются магнитной информацией, которую записывает утилита форматизации диска. Информация включает иден- тификационный номер каждого сектора. BIOS нумерует сектора 1-8, 1-9 или 1-15, в зависимости от емкости диска. Дорожки не марки- руются, вместо этого они определяются механически по смещению головки чтения/записи от внешнего края диска. Дорожки нумеруются от 0 до 39 для дискет диаметром 5 1/4 дюйма, а для дисков большей емкости их может быть больше. Дисковые функции BIOS обращаются к определенному сектору, указывая номера дорожки и сектора. Однако функции DOS рассматривают все сектора диска, как одну цепь, кото- рая нумеруется подряд, начиная от 0, поэтому каждый сектор имеет свой логический номер сектора. Для дискет первый сектор (дорожка 0, сектор 1) содержит запись начальной загрузки, которая является небольшой программой, позво- ляющей компьютеру считать с дискового накопителя остальные части MS DOS. Затем идут две копии таблицы размещения файлов, которые содержат информацию о распределении дискового пространства (вто- рая копия хранится из соображений безопасности). Затем идет кор- невой каталог, который содержит список файлов и ссылок на подка- талоги, а также указывает в каком месте диска они начинаются. Наконец, далее идут две небольшие программы DOS IBMBIO.COM и IBMDOS.COM, которые считываются при старте и обеспечивают компью- тер возможностями необходимыми для нахождения и загрузки файла C