[<>] ~~TOC wide~~ ====== Глава XI. Работа с видеопамятью и видеопроцессором ====== \\ Надо понять тот минимум, на котором покоится мир, и всё избыточное безжалостно отсекать (бритва Оккама). —//У.Оккам// {{anchor:n111}} ===== XI.1. Видеопамять ===== //Процессор// (англ. "processor", от "process" — "обрабатывать") — совокупность устройств ЭВМ, выполняющих функции по преобразованию информации. В зависимости от назначения различают центральные, функционально–ориентированные и проблемно–ориентированные процессоры. Графические возможности ПЭВМ "YAMAHA" поддерживаются функционально–ориентированным процессором — //видеопроцессором//. Видеопроцессор (VDP) постоянно "общается" с //видеопамятью// (VRAM), которая доступна центральному процессору через порты ввода–вывода, отвечает за изображение на экране и интерпретирует находящиеся в ней данные в соответствии с заданным режимом ''SCREEN''. Видеопроцессор обеспечивает отображение информации, хранящейся в видеопамяти, на экран дисплея. //Видеопамять// ("Video RAM") — доступная устройству сопряжения дисплея и компьютера область оперативной памяти ЭВМ, в которой расположены данные, соответствующие изображению на экране. В текстовом режиме видеопамять содержит коды и атрибуты символов,в графических режимах каждой точке экрана соответствует одна или несколько ячеек видеопамяти, указывающие её цвет и яркость. Видеопамять разделена на несколько областей, называемых //Таблицами//, имена которых, размеры и назначение зависят от установленного режима ''SCREEN''. Это деление памяти автоматически выполняется оператором ''SCREEN'', который инициализирует Таблицы видеопамяти. Прежде чем Вы попытаетесь непосредственно воздействовать на "содержимое" экрана дисплея, хорошо разберитесь в назначении Таблиц VRAM! Далее в тексте вам часто будут встречаются следующие аббревиатуры: ^ Аббревиатура ^ Что вам необходимо //запомнить//! ^^ | PNT |"Pattern Name Table"|"Таблица имён шаблонов"| | PGT |"Pattern Generation Table"|"Таблица шаблонов образов" ("Таблица изображений")| | CT |"Color Table"|"Таблица цветов"| | SGT |"Sprite Generation Table"|"Таблица шаблонов спрайтов"| | SAT |"Sprite Attribute Table"|"Таблица атрибутов спрайтов"| | SCT |"Sprite Color Table"|"Таблица цветов спрайтов"| | PT |"Palette Table"|"Таблица палитры"| {{anchor:n1111}} {{anchor:base}} ==== XI.1.1. Псевдопеременная BASE ==== Псевдопеременная ''BASE'' используется для чтения начальных адресов Таблиц VRAM, а также для их "перемещения" в видеопамяти. * Вначале о синтаксисе псевдопеременной ''BASE'', используемой как функция: BASE(N) , где: * ''BASE'' ("base" — "база", "значение или адрес, относительно которого представляются другие значения и адреса") — служебное слово; * N — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,19] для компьютеров [[msx:msx_1]] и отрезку [0,44] для компьютеров [[msx:msx_2]]. По значению N можно определить номер Таблицы видеопамяти (VRAM). Функция ''BASE(N)'', где N=M*5+T, возвращает //начальный адрес// таблицы с номером Т в режиме ''SCREEN M''. \\ Ясно, что M=N\5 и T=N MOD 5 Номер Таблицы T принадлежит интервалу [0,4]; режим экрана M может принимать значения 0, 1, 2, 3, 4, 5, 6, 7, 8 для компьютеров [[msx:msx_2]] (0, 1, 2, 3 для компьютеров [[msx:msx_1]]). Таким образом, с помощью функции ''BASE()'' можно иметь доступ не более чем к //пяти// Таблицам для каждого из режимов экрана. Ниже приведены имена Таблиц, соответствующих различным значениям T: ^T^ //Имя// Таблицы ^ |0|PNT| |1|CT (кроме режимов ''SCREEN 3, 5, 6, 7, 8'' и 40–символьного режима ''SCREEN 0'')| |2|PGT (кроме режимов ''SCREEN 5, 6, 7, 8'')| |3|SAT (кроме режима ''SCREEN 0'')| |4|SGT (кроме режима ''SCREEN 0'')| Например, найдём начальный адрес Таблицы CT в режиме ''SCREEN 2''. Для этого выполним команду: PRINT HEX$(BASE(5*2+1)) 2000 ▲ ▲ Ok Режим экрана──┘ └── Номер Таблицы Следующая табличка позволяет найти начальный адрес Таблицы VRAM с номером T для режима ''SCREEN M'': ^ М \ Т ^ 0(PNT) ^ 1(CT) ^ 2(PGT) ^ 3(SAT) ^ 4(SGT) ^ |0 (40)| 0 | —— | &H800 | —— | —— | |0 (80)| 0 | &H800 | &H1000 | —— | —— | |1| &H1800 | &H2000 | 0 | &H1B00 | &H3800 | |2| &H1800 | &H2000 | 0 | &H1B00 | &H3800 | |3| &H800 | —— | 0 | &H1B00 | &H3800 | |4| &H1800 | &H2000 | 0 | &H1E00 | &H3800 | |5| 0 | —— | —— | &H7600 | &H7800 | |6| 0 | —— | —— | &H7600 | &H7800 | |7| 0 | —— | —— | &HFA00 | &HF000 | |8| 0 | —— | —— | &HFA00 | &HF000 | Прочерками здесь помечены адреса Таблиц, отсутствующих в видеопамяти для данных M и T. Числа 40 и 80, стоящие в круглых скобках, указывают на ширину экрана в режиме ''SCREEN 0''. А в этой табличке показано количество байтов в каждой из Таблиц VRAM. ^ М \ Т ^ 0(PNT) ^ 1(CT) ^ 2(PGT) ^ 3(SAT) ^ 4(SGT) ^ |0 (40)| 960 | —— | 2048 | —— | —— | |0 (80)| 1920 | 270 | 2048 | —— | —— | |1| 768 | 32 | 2048 | 128 | 2048 | |2| 768 | 6144 | 6144 | 128 | 2048 | |3| 768 | —— | 1536 | 128 | 2048 | |4| 768 | 6144 | 6144 | 128 | 2048 | |5| 27136 | —— | —— | 128 | 2048 | |6| 27136 | —— | —— | 128 | 2048 | |7| 54272 | —— | —— | 128 | 2048 | |8| 54272 | —— | —— | 128 | 2048 | Внимание! Функция ''BASE'' не позволяет найти начальные адреса Таблиц PT и SCT Но Вы не волнуйтесь: в следующей табличке мы приводим начальные адреса и этих Таблиц: ^ Режим ^ PT ^ SCT ^ |0 (40)| &H0400 | —— | |0 (80)| &H0800 | —— | |1| &H2020 | —— | |2| &H1B80 | —— | |3| &H2020 | —— | |4| &H1E80 | &H1C00 | |5| &H7680 | &H7400 | |6| &H7680 | &H7400 | |7| &HFA80 | &HF800 | |8| &HFA80 | &HF800 | Таблица PT для всех режимов ''SCREEN'' занимает в видеопамяти 32 байта. Таблица SCT для всех режимов ''SCREEN'' занимает в видеопамяти 512 байт. * А теперь — синтаксис псевдопеременной BASE, используемой в //левой// части оператора присваивания: BASE(N)= 1024*A или BASE(N)=&H400*A , где: * N — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,19]. Значение N — это номер //Таблицы// VRAM; * A — арифметическое выражение,целая часть значения которого, умноженная на число 1024, определяет новый начальный адрес таблицы VRAM с номером N (1Кбайт = 1024 байтам). Значение A должно принадлежать отрезку [0,15] для компьютеров серий [[msx:msx_1]] и [[msx:msx_2]]. ^ Значение A | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ^ &H400×A | 0 | &H400 | &H0800 | &H0C00 | &H1000 | &H1400 | &H1800 | &H1C00 | &H2000 | ^ Значение A | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ^ &H400×A | &H2400 | &H2800 | &H2C00 | &H3000 | &H3400 | &H3800 | &H3C00 | Если значения N или A не будут принадлежать указанным отрезкам, то компьютер выдаст сообщение об ошибке: "Illegal function call". Псевдопеременная ''BASE'', расположенная в правой части оператора присваивания, позволяет "перемещать" Таблицы. Она используется только в режимах ''SCREEN 0'' – ''SCREEN 3'', и поэтому значение N должно принадлежать отрезку [0,19]. Вспомним, что в режимах ''SCREEN 5–8'' можно переключаться с одной экранной //страницы// на другую при помощи оператора ''SET PAGE''. Этот оператор, однако, не применим в режимах ''SCREEN 0–4''. Используя же псевдопеременную ''BASE'', можно "работать" с экранными страницами в режимах ''SCREEN 0–3''. В режиме ''SCREEN 4'' работа с экранными страницами запрещена. Приведём следующую табличку: ^ //Режим// экрана | 0(40) | 0(80) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ^ Число разрешённых \\ экранных страниц | 4 | 2 | 1 | 1 | 1 | 1 | 4 | 4 | 2 | 2 | |:::| Используется ''BASE'' ||||| | Используется ''SET PAGE'' |||| __//Пример//__. Запись нескольких экранных //страниц// в режиме ''SCREEN 0'' и их переключение. Стандартный начальный адрес для Таблицы PNT в режиме ''SCREEN 0'' равен 0. "Передвинем" эту Таблицу вначале к адресу &H2000, а затем к адресу &H2400. Идентифицируем экранные страницы ("что–нибудь" на них напишем!), а затем будем переключаться с одной страницы на другую путём переопределения начала Таблицы PNT в строках 100 и 110. Заметим, что начальные адреса Таблиц PNT, PGT, SGT и SAT для текущего режима ''SCREEN'' хранятся в рабочей области, начиная с адресов &HF922, &HF924, &HF926 и &HF928 соответственно, и занимают по два байта каждый. Эти значения не могут быть изменены оператором ''BASE'': Вы должны сделать это //сами// (строка 110). В противном случае выход в непосредственный режим работы будет возможен только из //нулевой// страницы, а выйти на нее из другой страницы можно осуществить, если набрать "вслепую" команду SCREEN М , где М — номер режима. {{anchor:e1111-01}} \\ {{.examples:1111-01.bas|}} \\ [[+tab|wmsxbpge>1111-01.bas]] 10 SCREEN 0:WIDTH 40 20 FOR I=0 TO 2 30 GOSUB 100:GOSUB 200 '──▶ 40 NEXT I 50 IF INKEY$="" THEN 50 60 I=(I+1)MOD3:GOSUB 100 '──▶ 70 GOTO 50 90 '∗∗∗∗∗ Подпрограмма 1 ∗∗∗∗∗ 100 IF I=0 THEN BASE(0)=0 ELSE BASE(0)=&H2000+(I-1)*&H400 110 IF I=0 THEN POKE &HF922,&H00:POKE &HF923,&H00 ELSE POKE &HF922,0:POKE &HF923,&H20+(I-1)*4'Запись в слово ──▲─── ───▲── ' NAMBAS Адрес младшего байта─┘ └─ Адрес старшего байта 120 RETURN '──▶ 190 '∗∗∗∗∗ Подпрограмма 2 ∗∗∗∗∗ 200 CLS:FOR J=0 TO 50:PRINT "PAGE";I;:NEXT:RETURN '──▶ {{anchor:n1112}} ==== XI.1.2. Функция VPEEK. Оператор VPOKE ==== {{anchor:vpeek}} Вы всегда можете посмотреть, какое число находится в той или иной ячейке видеопамяти. Для этого используется функция ''VPEEK'', общий вид которой: VPEEK(адрес) , где: * ''VPEEK'' ("Video RAM PEEK") — служебное слово; * //адрес// — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,16383] для компьютеров [[msx:msx_1]] и [0,65535] для компьютеров [[msx:msx_2]]. Нарушение этого условия приводит к сообщению об ошибке "Illegal function call". Функция ''VPEEK'' возвращает содержимое ячейки VRAM с номером //"адрес"//. Действия функций ''VPEEK'' и ''PEEK'' аналогичны. {{anchor:vpoke}} Для //записи// данных в конкретную ячейку видеопамяти предназначен оператор ''VPOKE'', синтаксис которого: VPOKE адрес, данное , где: * ''VPOKE'' ("Video RAM POKE") — служебное слово; * //адрес// — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,16383] для компьютеров [[msx:msx_1]] и отрезку [0,65535] для компьютеров [[msx:msx_2]]; * //данное// — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,255]. Если хотя бы одно из значений параметров //адрес// или //данное// не удовлетворяет требуемым условиям, то компьютер сообщает об ошибке: "Illegal function call". Приведём простейший пример: вначале запишем в ячейку VRAM с номером 16383 число 10 командой ''VPOKE 16383,10'', а затем "прочтём"содержимое этой ячейки: print VPEEK(16383) 10 Ok Думаем, вам ясна аналогия в действиях операторов ''VPOKE'' и ''POKE''. Если Вы посмотрите на структуру видеопамяти в различных экранных режимах, то заметите, что некоторые области видеопамяти не используются. Эти области могут служить в качестве дополнительного пространства для сохранения данных при помощи оператора ''VPOKE'', когда RAM почти полностью использована! Однако при таком методе необходимо постоянно пользоваться нулевым текстовым режимом экрана — при смене режима Ваши данные будут уничтожены. {{anchor:e1112-01}} __//Пример 1//__. "Спрячем" числовой массив (кстати, а где оператор ''DIM'' ?!) в видеопамяти, а затем "извлечём его" оттуда. \\ {{.examples:1112-01.bas|}} \\ [[+tab|wmsxbpge>1112-01.bas]] 10 SCREEN 0:WIDTH 40:ADR=4096 'Начальный адрес хранения данных в VRAM 20 INPUT"Число элементов массива";N 30 FOR T=1 TO N 40 INPUT"Очередной элемент";Z 50 FOR I=0 TO 7 60 VPOKE ADR+8*T+I,PEEK(VARPTR(Z)+I) 70 NEXT I,T 80 'Выведем элементы массива на экран 90 FOR T=1 TO N 100 IF VPEEK(ADR+8*T)\128=1 THEN Z$="-." ELSE Z$="+." 'Знак числа 110 FOR I=1 TO 7 120 Z$=Z$+RIGHT$("00"+HEX$(VPEEK(ADR+8*T+I)),2) 'Мантисса числа 130 NEXT I 140 IF(VPEEK(ADR+8*T) MOD 128)\64=1 THEN Z$=Z$+"E+" ELSE Z$=Z$+"E-" 150 Z$=Z$+MID$(STR$((VPEEK(ADR+8*T)MOD 128)-64),2) 'Порядок числа 160 U=VAL(Z$):PRINT U;:NEXT T {{anchor:e1112-02}} __//Пример 2//__. \\ {{.examples:1112-02.bas|}} \\ [[+tab|wmsxbpge>1112-02.bas]] 10 TP=4096:SCREEN 0:WIDTH 38 30 INPUT"Имя (символ '*' - для окончания)";N$ 40 IF LEFT$(N$,1)="*"THEN 120 50 IF TP+LEN(N$)+1>16383 THEN PRINT"Память заполнена":GOTO 120 60 FOR I=1 TO LEN(N$) 70 VPOKE TP,ASC(MID$(N$,I,1)):TP=TP+1 90 NEXT 100 VPOKE TP,0:TP=TP+1 110 GOTO 30 120 CLS:I=4096 140 X=VPEEK(I) 150 IF X=0 THEN PRINT:GOTO 170 160 PRINT CHR$(X) 170 I=I+1 180 IF I Если скорость не является существенным фактором, то рассмотренный способ хранения данных в видеопамяти может быть весьма полезным, особенно для больших программ! {{anchor:n1113}} ==== XI.1.3. Текстовые режимы ==== \\ Они мастера накапливать факты, а вот извлечь из них пользу им удаётся не всегда. —//А.Конан Дойль. Морской договор// Введём понятия //общей// ширины (высоты) экрана и //доступной// ширины (высоты) экрана. //Доступная// ширина экрана — это область экрана, "доступная" текстовому курсору. Её размер устанавливается оператором ''WIDTH''. //Общая// ширина экрана однозначно определяется оператором ''SCREEN''. В режиме ''SCREEN 1'' она равна 32 символам. В режиме ''SCREEN 0'' она устанавливается равной 40 символам, если аргумент в операторе ''WIDTH'' ≤ 40 и равной 80 символам в противном случае. Общая //высота// экрана для текстовых режимов равна 24 символам, однако для режимов ''SCREEN 0'' (80 символов) и ''SCREEN 1'' она может быть равной 26.5 символам. Для расположения символов в нужном вам месте экрана используйте Таблицу имён образов (PNT)! На рисунках показана нумерация возможных позиций курсора на текстовых экранах: * ''SCREEN 0'' (40 символов) ┌───┬───┬─┄┄┄─┬───┬───┐ │ 0 │ 1 │ │ 38│ 39│ ├───┴───┘ └───┴───┤ ┆ ⋯ ⋯ ⋯ ⋯ ⋯ ┆ ├───┬───┐ ┌───┬───┤ │920│921│ │958│959│ └───┴───┴─┄┄┄─┴───┴───┘ * ''SCREEN 0'' (80 символов), высота экрана — 24 симв. ┌────┬────┬─┄┄┄─┬────┬────┐ │ 0 │ 1 │ │ 78 │ 79 │ ├────┴────┘ └────┴────┤ ┆ ⋯ ⋯ ⋯ ⋯ ⋯ ┆ ├────┬────┐ ┌────┬────┤ │1840│1841│ │1918│1919│ └────┴────┴─┄┄┄─┴────┴────┘ * ''SCREEN 1'' , высота экрана — 24 симв. ┌───┬───┬─┄┄┄─┬───┬───┐ │ 0 │ 1 │ │ 30│ 31│ ├───┴───┘ └───┴───┤ ┆ ⋯ ⋯ ⋯ ⋯ ⋯ ┆ ├───┬───┐ ┌───┬───┤ │744│745│ │766│767│ └───┴───┴─┄┄┄─┴───┴───┘ Чтобы изобразить символ в нужном месте экрана, используйте оператор: VPOKE BASE(5*T)+W,K , где: * T — номер режима экрана (0 или 1); * W — номер позиции символа на экране; * K — код ASCII символа. {{anchor:e1113-01}} __//Пример 1//__. Вывести "A" (код ASCII 65) в 8–й строке и 10–м столбце экрана ''SCREEN 0'': \\ {{.examples:1113-01.bas|}} \\ [[+tab|wmsxbpge>1113-01.bas]] 10 SCREEN 0:WIDTH 40 20 VPOKE BASE(5*T)+40*8+10,65 ▲ ▲ Номер строки экрана─┘ └─ Номер столбца экрана Описанная возможность позволяет, например, выводить информацию в те места экрана, которые //недоступны// для вывода оператором ''PRINT''. {{anchor:e1113-02}} __//Пример 2//__. Обратите внимание на то, что общая ширина экрана и доступная ширина экрана — различны! \\ {{.examples:1113-02.bas|}} \\ [[+tab|wmsxbpge>1113-02.bas]] 10 TIME=0:INTERVAL ON:ON INTERVAL=60 GOSUB 100 20 GOTO 20 'Место для основной программы. 100 WIDTH 28:T1=INT(TIME/3600):T2=T2+1:IF T2=60 THEN T2=0 110 FOR J=0 TO 1 120 VPOKE 40+J,ASC(MID$(RIGHT$("0"+MID$(STR$(T1),2),2),J+1)):VPOKE 42,ASC(":") 130 VPOKE 43+J,ASC(MID$(RIGHT$("0"+MID$(STR$(T2),2),2),J+1)):NEXT:RETURN Оказывается, можно одновременно "хранить" содержимое нескольких экранных //страниц//, причём в любой момент можно "открыть" любую страницу и "прочесть" её содержимое. Вывод информации на нулевую страницу предполагает использование операторов ''PRINT'' или ''VPOKE''. Для остальных же страниц вывод информации оператором ''PRINT'' невозможен, и поэтому приходится пользоваться оператором ''VPOKE''. Вы всегда можете изобразить любой символ в нужном месте //любой// экранной страницы при помощи оператора: VPOKE 4096*T*(N+1)^2+W,K , где: * T — номер //страницы//; * N — режим экрана (0 или 1); * W — номер позиции символа на экране; * K — код ASCII символа. При этом Вы сможете увидеть содержимое только нулевой страницы. Чтобы "просмотреть содержимое" других страниц, воспользуйтесь псевдопеременной ''BASE''. {{anchor:e1113-03}} __//Пример 3//__. "Полистаем" экранные страницы! \\ {{.examples:1113-03.bas|}} \\ [[+tab|wmsxbpge>1113-03.bas]] NEW Ok ┌─ Код символа "SPACE"("пробел") 10 FOR T=1 TO 3 ▼ 20 FOR D=0 TO 959:VPOKE 4096*T+D,32:NEXT D 'Очистка T-й страницы 30 PRINT "Введите"T"слово";:INPUT A$ 40 PRINT "С какого места печатать?" 50 INPUT "X(от 0 до 39)";VX:INPUT "Y(от 0 до 23)";VY 60 FOR B=1 TO LEN(A$) 70 VPOKE 4096*T+40*VY+VX+B,ASC(MID$(A$,B,1))'Запись на T-ю страницу 80 NEXT B:NEXT T 90 FOR T=1 TO 3:Z$=INPUT$(1): BASE(0)=4096*T '4096=&H1000 ──▶ &H10 00 95 POKE &HF923, &H10*T: POKE &HF922, 0*T 'Чтение с экрана ──▲─── ───▲── └ Адрес старшего байта└ Адрес младшего байта 97 NEXT T 100 A$=INPUT$(1):BASE(0)=0:POKE &HF923,0 'Вывод "содержимого" 0-й страницы //Внимание//! Страницы могут быть "засорены" посторонней информацией, оставшейся от прежнего обращения к ним. Ваши сообщения могут затеряться среди этого "мусора". Поэтому рекомендуем своевременно заботиться о чистоте страниц (посмотрите на строку 20 примера 3)! Приведём структуру Таблицы имён образов (PNT) для 80–символьного режима ''SCREEN 0'' в соответствии с расположением символов на экране дисплея: | 0–й байт |код символа в 0–й строке и 0–м столбце экрана| | 1–й байт |код символа в 0–й строке и 1–м столбце экрана| | … | | 79–й байт |код символа в 0–й строке и 79–м столбце экрана| | 80–й байт |код символа в 1–й строке и 0–м столбце экрана| | … | | 1919–й байт |код символа в 23–й строке и 79–м столбце экрана| Приведём структуру Таблицы имён образов (PNT) для режима ''SCREEN 1'' в соответствии с расположением символов на экране дисплея: | 0–й байт |код символа в 0–й строке и 0–м столбце экрана| | 1–й байт |код символа в 0–й строке и 1–м столбце экрана| | … | | 31–й байт |код символа в 0–й строке и 31–м столбце экрана| | 32–й байт |код символа в 1–й строке и 0–м столбце экрана| | … | | 767–й байт |код символа в 23–й строке и 31–м столбце экрана| Структуру Таблицы имён образов(PNT) для 40–символьного режима ''SCREEN 0'' в соответствии с расположением символов на экране дисплея Вы теперь легко изобразите самостоятельно! Информация о символах, имеющихся на клавиатуре компьютера, находится в ROM, начиная с адреса &H1BBF, и занимает 2 Кбайта памяти. При переходе в режимы ''SCREEN 0'' или ''SCREEN 1'' эта информация автоматически копируется в видеопамять, инициализируя тем самым Таблицу шаблонов образов (PGT). Адрес ячейки, начиная с которой хранится информация о символах, можно узнать в системной области RAM. В ячейках &HF920 и &HF921 хранится адрес (по умолчанию — &H1BBF),а в ячейке &HF91F - номер слота памяти, в которой находятся шаблоны символов (о слотах см. в [[101|Приложении 1]]). Поэтому понятно, что шаблоны символов для инициализации видеопамяти можно хранить как в ROM, так и в RAM. Место в ROM, RAM и видеопамяти, предназначенное для записи //одного// символа, занимает //восемь// байтов. Адрес начала места, отведённого для символа в видеопамяти, можно определить обращением к функции ''BASE'': BASE(5*N+2)+K*8 , где: * N — номер режима экрана (0 или 1); * K — код ASCII символа. Приведём пример "хранения" информации о символе в ROM и VRAM (справа для каждого байта выписан его шестнадцатеричный код, который и задаёт содержимое данного байта): ┌───┬───┬───┬───┬───┬───┬───┬───┐ 0–й байт │ │ │ │ │ │ │ │ │ &H00 ├───┼───┼───┼───┼───┼───┼───┼───┤ 1–й байт │ │ │ │ │ │ │ │ │ &H00 ├───┼───┼───┼───┼───┼───┼───┼───┤ 2–й байт │ │ █ │ │ │ │ │ █ │ │ &H42 ├───┼───┼───┼───┼───┼───┼───┼───┤ 3–й байт │ █ │ │ │ │ │ │ │ █ │ &H81 ├───┼───┼───┼───┼───┤───┼───┼───┤ 4–й байт │ █ │ │ │ │ │ │ │ █ │ &H81 ├───┼───┼───┼───┼───┼───┼───┼───┤ 5–й байт │ █ │ │ │ │ │ │ │ █ │ &H81 ├───┼───┼───┼───┼───┼───┼───┼───┤ 6–й байт │ █ │ │ │ █ │ █ │ │ │ █ │ &H99 ├───┼───┼───┼───┼───┼───┼───┼───┤ 7–й байт │ │ █ │ █ │ │ │ █ │ █ │ │ &H66 └───┴───┴───┴───┴───┴───┴───┴───┘ 8 4 2 1 8 4 2 1 Расскажем вам о том, как можно получить "содержимое" конкретного байта видеопамяти. Разобьём каждый байт на две половинки (два полубайта). Под рисунком для каждого полубайта изображено по 4 числа (каждое из них назовём "весом"). Код полубайта получим суммированием "весов" точек, содержащихся в нем (напомним шестнадцатеричные цифры: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F). Код байта получим, если справа от кода левого полубайта напишем код правого полубайта, а слева — символ "&H". //Внимание//! Только режим ''SCREEN 0'', а в компьютере серии [[msx:msx_2]] также и режимы ''SCREEN 6'' и ''SCREEN 7'', поддерживает вывод символов размером 6×8 точек; остальные режимы используют размер 8×8. Приведём пример вывода одного и того же символа в двух режимах: SCREEN 0 SCREEN 1 ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ █ │ │ │ │ │ │ │ █ │ │ │ │ │ █ │ │ ├───┼───┼───┼───┼───┼───┼ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ │ │ │ │ │ │ █ │ │ │ │ │ │ │ █ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ │ │ │ │ │ │ █ │ │ │ │ │ │ │ █ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ │ │ │ │ │ │ █ │ │ │ │ │ │ │ █ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ │ │ █ │ █ │ │ │ █ │ │ │ █ │ █ │ │ │ █ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ █ │ █ │ │ │ █ │ │ │ █ │ █ │ │ │ █ │ █ │ │ └───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘ Важно отметить, что в языке [[msx:basic:]] есть возможность программным путём создавать "собственные" символы (отличные от стандартных!). Взгляните на приведённые ниже примеры. {{anchor:e1113-04}} __//Пример 4//__. \\ {{.examples:1113-04.bas|}} \\ [[+tab|wmsxbpge>1113-04.bas]] Код ASCII символа "у"┐ 5 SCREEN 0:WIDTH 40 ▼ 10 FOR I=0 TO 7:READ M:VPOKE 2048+213*8+I,M:NEXT 20 DATA &H00,&H00,&H42,&H81,&H81,&H81,&H99,&H66 Данные в операторе DATA определяют шестнадцатеричные коды каждого байта "нового" символа. Число 213 в операторе ''VPOKE'' означает, что "построенному" нами символу присваивается код ASCII, равный 213. Если раньше коду 213 соответствовал символ "у", то теперь это место занял символ, который мы "сконструировали". Поэтому в тех местах экрана дисплея, где встречался символ "у", Вы увидите новый символ. {{anchor:e1113-041}} __//Пример 4//__. \\ {{.examples:1113-041.bas|}} \\ [[+tab|wmsxbpge>1113-041.bas]] 5 SCREEN 0:WIDTH 80 10 FOR I=0 TO 7:READ M:VPOKE &h1000+213*8+I,M:NEXT 20 DATA &H00,&H00,&H42,&H81,&H81,&H81,&H99,&H66 {{anchor:e1113-05}} __//Пример 5//__. Пример иллюстрирует возможность хранения шаблонов символов в RAM. \\ {{.examples:1113-05.bas|}} \\ [[+tab|wmsxbpge>1113-05.bas]] 10 CLEAR 200,&HE800 'Место в RAM для шаблонов символов 20 FOR T=0 TO 2047:POKE &HE800+T,PEEK(&H1BBF+T):NEXT 30 FOR I=0 TO 7:READ M:POKE &HE800+213*8+I,M:NEXT 40 DATA &H00,&H00,&H42,&h81,&H81,&H81,&H99,&H66 50 POKE &HF91F,&H8B 'Номер с л о т а памяти 60 POKE &HF920,0:POKE &HF921,&HE8 'Начальный адрес ячеек памяти, в которых располагаются шаблоны символов 70 'А теперь посмотрим! 80 SCREEN 0:WIDTH 80:PRINT CHR$(213):A$=INPUT$(1) 90 SCREEN 0:WIDTH 40:PRINT CHR$(213):A$=INPUT$(1) 100 SCREEN 1:PRINT CHR$(213):A$=INPUT$(1) {{anchor:e1113-06}} __//Пример 6//__. \\ {{.examples:1113-06.bas|}} \\ [[+tab|wmsxbpge>1113-06.bas]] 5 PRINT"Вводите последовательно байты шаблона символа:" 10 FOR I=0 TO 7:INPUT T(I):NEXT 20 INPUT"Введите код изменяемого символа";K% 30 FOR I=0 TO 7:VPOKE 2048+K%*8+I,T(I):NEXT Отметим, что вместо переменной K% можно использовать любое арифметическое выражение, целая часть значения которого определяет код ASCII заменяемого символа. А теперь взгляните на следующую программу! {{anchor:e1113-07}} __//Пример 7//__. Изображение "псевдослучайных" символов. \\ {{.examples:1113-07.bas|}} \\ [[+tab|wmsxbpge>1113-07.bas]] 10 P=RND(-TIME):FOR I=0 TO 7:T(I)=INT(255*RND(1)):NEXT 20 K=INT(223*RND(1)+31) 30 FOR I=0 TO 7:VPOKE 2048+K*8+I,T(I):NEXT:PRINT K,CHR$(K) После выполнения этой программы нажмите на кнопку RESET. Отметим, что при выполнении оператора ''SCREEN 0'' (или ''SCREEN 1'') Таблица шаблонов образов (PGT) инициализируется вновь данными из ROM! Ещё ряд примеров на изменение шаблонов символов: {{anchor:e1113-08}} __//Пример 8//__ [[bibliography#b76|[76]]]. "Мелкие" и обычные буквы латинского алфавита. \\ {{.examples:1113-08.bas|}} \\ [[+tab|wmsxbpge>1113-08.bas]] 40 SCREEN 0:KEY OFF 50 BASE(2)=2048 60 PRINT"Загрузка данных":PRINT 70 FOR I=4616 TO 4823 80 READ A$:VPOKE I,VAL("&h"+A$) 90 VPOKE I+256,VAL("&h"+A$) 100 NEXT 120 PRINT"Нажмите клавишу для изменения" 130 PRINT" набора символов" 140 A$=INPUT$(1) 160 BASE(2)=4096 180 ' Б у к в ы а л ф а в и т а 200 DATA 00,00,70,88,F8,88,88,00:'A 210 DATA 00,00,F0,48,70,48,F0,00:'B 220 DATA 00,00,78,80,80,80,78,00:'C 230 DATA 00,00,F0,88,88,88,F0,00:'D 240 DATA 00,00,F0,80,E0,80,F0,00:'E 250 DATA 00,00,F0,80,E0,80,80,00:'F 260 DATA 00,00,78,80,B8,88,70,00:'G 270 DATA 00,00,88,88,F8,88,88,00:'H 280 DATA 00,00,70,20,20,20,70,00:'I 290 DATA 00,00,70,20,20,A0,E0,00:'J 300 DATA 00,00,90,A0,C0,A0,90,00:'K 310 DATA 00,00,80,80,80,80,F8,00:'L 320 DATA 00,00,88,D8,A8,88,88,00:'M 330 DATA 00,00,88,C8,A8,98,88,00:'N 340 DATA 00,00,F8,88,88,88,F8,00:'O 350 DATA 00,00,F0,88,F0,80,80,00:'P 360 DATA 00,00,F8,88,A8,90,E8,00:'Q 370 DATA 00,00,F8,88,F8,A0,90,00:'R 380 DATA 00,00,78,80,70,08,F0,00:'S 390 DATA 00,00,F8,20,20,20,20,00:'T 400 DATA 00,00,88,88,88,88,70,00:'U 410 DATA 00,00,88,88,90,A0,40,00:'V 420 DATA 00,00,88,88,A8,D8,88,00:'W 430 DATA 00,00,88,50,20,50,88,00:'X 440 DATA 00,00,88,50,20,20,20,00:'Y 450 DATA 00,00,F8,10,20,40,F8,00:'Z {{anchor:e1113-09}} __//Пример 9//__. Автограф программиста! \\ {{.examples:1113-09.bas|}} \\ [[+tab|wmsxbpge>1113-09.bas]] 10 COLOR15,1,1:SCREEN 1 20 J=33:KEYOFF 30 DATA 0000000000000003,00001E214346E098,0000000000000000,0001010101097595,C850408000000000,0409090701010262,840404081C026291,0202444464505162,89A1C10F32C20206,000000E010080810,938584C870000000,0102847800000000,0202010000000000,0A33C20000000000,906000000 40 READ A$:FOR T=2 TO 16 STEP 2:VPOKE8*J+T/2-1,VAL("&h"+MID$(A$,T-1,2)):NEXT 50 IF J<47 THEN J=J+1:GOTO 40 60 A$=CHR$(33)+CHR$(34)+CHR$(35)+CHR$(36)+CHR$(37)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(31)+CHR$(38)+CHR$(39)+CHR$(40)+CHR$(41)+CHR$(42)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(29)+CHR$(31)+CHR$(43)+CHR$(44)+CHR$(45)+CHR$(46)+CHR$(47) 70 LOCATE 2,2:PRINTA$ 80 GOTO 80 {{anchor:e1113-10}} __//Пример 10//__. "Изготовление" //"толстых"// символов! \\ {{.examples:1113-10.bas|}} \\ [[+tab|wmsxbpge>1113-10.bas]] 5 SCREEN 1:A1=0:A2=255 ' Имеющийся шаблон символа сдвигается 10 FOR X=A1*8 TO A2*8+7 ' на один разряд и складывается со 20 D=VPEEK(X):VPOKE X,D OR D/2' "старым". 30 NEXT \\ Целью придумавших систему было, очевидно, скрыть, что в этих значках содержится какой–то смысл. —//А.Конан Дойль. Пляшущие человечки// {{anchor:e1113-11}} //Пример 11//. //Бегущий// человечек. \\ {{.examples:1113-11.bas|}} \\ [[+tab|wmsxbpge>1113-11.bas]] 5 COLOR 15,1,1:CLS:INPUT"Укажите желаемую скорость движения человечка (чем больше число - тем меньше скорость)";C 10 CLS:SCREEN 1,2,90:DIM A$(50):J=100 30 DATA 0C0C7ADE38EC8406,03030E171607050A,0000010301000701 60 DATA C0C0808080C08080,0000000101000000,3030E078606050A0 90 READA$:FOR T=2 TO 16 STEP 2:VPOKE 8*J+T/2-1,VAL("&h"+MID$(A$,T-1,2)):NEXT 100 IF J<105 THEN J=J+1:GOTO 90 '──▶ 110 A$(0)=CHR$(100)+" ":A$(1)=CHR$(101)+" ":A$(2)=CHR$(102)+CHR$(103) 140 A$(3)=CHR$(104)+CHR$(105) 150 FOR I=0 TO 3:LOCATE Y,7:PRINT" ";A$(I) 165 FOR W=0 TO C:NEXT 166 IF Y=27 THEN Y=0 170 NEXT:Y=Y+1:A$=INKEY$:IF A$=" " THEN END 171 GOTO 150 '──▶ Приведём шаблоны четырёх символов из шести,сформированных в данной программе: ┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ █ │ █ │ │ │0C 03│ │ │ │ │ │ │ █ │ █ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ █ │ █ │ │ │0C 03│ │ │ │ │ │ │ █ │ █ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ █ │ █ │ █ │ █ │ │ █ │ │7A 0E│ │ │ │ │ █ │ █ │ █ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ █ │ │ █ │ █ │ █ │ █ │ │DE 17│ │ │ │ █ │ │ █ │ █ │ █ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ █ │ █ │ █ │ │ │ │38 16│ │ │ │ █ │ │ █ │ █ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ █ │ █ │ │ █ │ █ │ │ │EC 07│ │ │ │ │ │ █ │ █ │ █ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ █ │ │ │ │ │ █ │ │ │84 05│ │ │ │ │ │ █ │ │ █ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ █ │ █ │ │06 0A│ │ │ │ │ █ │ │ █ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘ ┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ │ │ │ │00 C0│ █ │ █ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ │00 C0│ █ │ █ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ █ │01 80│ █ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ █ │ █ │03 80│ █ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ █ │01 80│ █ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ │00 C0│ █ │ █ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ █ │ █ │ █ │07 80│ █ │ │ │ │ │ │ │ │ ├───┼───┼───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ │ │ │ │ │ │ │ █ │01 80│ █ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘ В режиме ''SCREEN 1'' Таблица цветов (CT) позволяет, вообще говоря, выводить текст, символы которого имеют разные цвета. Однако, учтите, что каждый из 32 байтов Таблицы CT действует на группу из 8 символов, причём за цвет //изображения// данной группы "отвечает" старший полубайт, а младший полубайт "отвечает" за цвет //фона// символов. //Байт Таблицы// CT |Цвет изображения восьми символов||||Цвет фона восьми символов|||| | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | {{anchor:e1113-12}} __//Пример 12//__. Вывод семи первых прописных букв латинского алфавита и символа "@" в "инвертированном" цвете: \\ {{.examples:1113-12.bas|}} \\ [[+tab|wmsxbpge>1113-12.bas]] 10 SCREEN 1:COLOR 15,4,7 20 VPOKE &H2008,&H4F Адрес Таблицы CT (&H2000+8) связан с символами, у которых коды ASCII принадлежат отрезку [64,71] (символы @, A, B, C, D, E, F, G). Если Вы хотите напечатать в "инвертированном" цвете символ "H" (восьмую букву латинского алфавита),то адрес &H2009 видеопамяти должен быть загружен значением &H4F. Это приведёт к выводу в "инвертированном" цвете восьми символов: H, I, J, K, L, M, N, O. {{anchor:e1113-13}} //Пример 13//. Изменение цвета символов (напомним,что начальный адрес Таблицы цветов &H2000 = 8192). \\ {{.examples:1113-13.bas|}} \\ [[+tab|wmsxbpge>1113-13.bas]] 40 SCREEN 1:COLOR 15,4,4 50 FOR I=0 TO 255:PRINT CHR$(I);:NEXT 60 FOR I=0 TO 255 70 FOR J=8192 TO 8223 80 VPOKE J,I 90 FOR K=1 TO 25:NEXT K 100 NEXT J 110 NEXT I {{anchor:e1113-14}} //Пример 14//. Изменение цвета курсора (напомним Вам, что код ASCII символа "█" равен 255). \\ {{.examples:1113-14.bas|}} \\ [[+tab|wmsxbpge>1113-14.bas]] SCREEN 1:VPOKE &H201F,&HFF Далее команда VPOKE BASE(1*5+1)+255\8,&H28 задаёт цвет курсора и цвет, которым через курсор "просвечивается" тот символ, на который курсор "наложен". Если оба этих цвета совпадают, то сам курсор и символ сливаются, создавая иллюзию непрозрачности курсора. Обратите внимание на тот факт, что Таблица CT в режиме ''SCREEN 1'' инициализируется оператором ''COLOR''. {{anchor:e1113-15}} __//Пример 15//__. Не поленитесь, наберите приведённую ниже программу. Затем включите принтер, вставьте лист бумаги и запустите программу. Результаты её работы пригодятся вам в дальнейшем! \\ {{.examples:1113-15.bas|}} \\ [[+tab|wmsxbpge>1113-15.bas]] 10 KEYOFF:CLS 120 LOCATE 0,12,0:PRINT CHR$(27);"MFirst page ";:MP=1:INPUT MP:IF MP<1 OR MP>6 GOTO 120 130 PRINT:PRINT:POKE &HF418,1:DEFUSR=&H156 140 LPRINT CHR$(27);"c1";CHR$(27);"p0";CHR$(27);"T15";CHR$(27);">";CHR$(27);"Q"; 150 IF MP=1 THEN I=0:LPRINT CHR$(27);"E (c) LHsoft ver.2":LPRINT CHR$(27);"Q" ELSE I=43*MP-45 160 P=MP 170 GOSUB 460 180 IF P=1 THEN K=41 ELSE K=43 190 FOR N=1 TO K 200 GOSUB 260 210 I=I+1 220 NEXT N 230 LPRINT"└────┴─────┴────┴──────┴──────┴──────┴──────┴──────┴──────┴─────────────────────────────────┴─────────────────────────┘ 240 LPRINT CHR$(12);:IF P<6 THEN PRINT CHR$(27);"MPut in a new sheet ";:QQ=USR(0):Q$=INPUT$(1):P=P+1:GOTO 170 250 CLS:KEYON:END 260 LPRINT"│ │ │ │ │ │ │ │ │ │ │ │ 270 LPRINT"│ │ "; 280 LPRINTUSING("###");I; 290 A1=I*8:A0=A1+2048:LPRINT" │ ";RIGHT$("0"+HEX$(I),2);" │";A0;"│ 0";HEX$(A0);" │ "; 300 LPRINTUSING("####");A1; 310 LPRINT" │ ";RIGHT$("000"+HEX$(A1),4);" │"; 320 IF IMOD8=0 THEN LPRINT 8192+I/8;"│ ";HEX$(&H2000+I/8);" │";ELSE LPRINT" │ │"; 330 FOR T=0 TO 7:LPRINTUSING(" ###");PEEK(&H1BBF+I*8+T);:NEXT 340 LPRINT" │ "; 350 FOR T=0 TO 7:LPRINT RIGHT$("0"+HEX$(PEEK(&H1BBF+I*8+T)),2);" ";:NEXT 360 LPRINT"│";CHR$(13);" ";CHR$(27);"N";CHR$(27);"S0008"; 370 M=128 380 FOR K1=0 TO 7 390 D=0 400 FOR K2=7 TO 0 STEP-1 410 D=D*2 420 IF PEEK(&H1BBF+I*8+K2)ANDM THEN D=D+1 430 NEXT K2:LPRINT CHR$(D);:M=M/2:NEXT K1 440 LPRINT CHR$(27);"Q" 450 RETURN 460 PRINT CHR$(27);"MCurrent page is";P; 470 LPRINT"┌────┬──────────┬───────────────────────────┬─────────────┬───────────────────────────────────────────────────────────┐ 480 LPRINT"│ │ Код │ Адрес в PGT │ Адрес в CT │ │ 490 LPRINT"│Сим-│ ├─────────────┬─────────────┼─────────────┤ Стандартное значение │ 500 LPRINT"│вол │ ASCII │ SCREEN 0 │ SCREEN 1 │ SCREEN 1 │ │ 510 LPRINT"│ ├─────┬────┼──────┬──────┼──────┬──────┼──────┬──────┼─────────────────────────────────┬─────────────────────────┤ 520 LPRINT"│ │ дес.│шест│ дес. │ шест.│ дес. │ шест.│ дес. │ шест.│ десятичное │ шестнадцатеричное │ 530 LPRINT"├────┼─────┼────┼──────┼──────┼──────┼──────┼──────┼──────┼─────────────────────────────────┼─────────────────────────┤ 540 RETURN {{anchor:n1114}} ==== XI.1.4. Режимы SCREEN 2 и SCREEN 4 ==== \\ Есть медленно и умеренно, не пить во время еды, тщательно разжёвывать пищу и с лёгкостью вставать из–за стола с чувством, что мог бы съесть ещё. —//Ж.Фрумузак// Разделим экран (размером 256×192 точек) на //квадраты// размером по 8×8 точек. Легко подсчитать, что мы получим 768 таких квадратов. Каждый из них имеет свой номер, который хранится в Таблице PNT. А так как максимальное целое число, которое можно "разместить" в одном байте памяти (в данном случае VRAM), равно 255, поэтому Таблицу PNT необходимо разбить на //три// области, каждая из которых будет отвечать за нумерацию только 256 квадратов. При установке режимов ''SCREEN 2'' или ''SCREEN 4'' (при инициализации) в каждую треть Таблицы PNT последовательно заносятся целые числа от 0 до 255. Адрес байта PNT, отвечающего за //квадрат// с номером n2, вычисляется при помощи арифметического выражения BASE(5×N) + 256×n1 + n2 , где: * N — номер режима ''SCREEN'' (2 или 4); * n1 — номер трети таблицы PNT, в которой находится квадрат; * n2 — номер квадрата. Соответственно Таблице PNT, весь экран также разбивается на три области (каждая размером 256×64 точек), которые мы будем называть //окнами//. ┌───┬───┬────────┄┄┄──────────┬───┐ │ 0 │ 1 │ │ 31│ ├───┴───┘ └───┤ ┆ Окно 0 ┆ ├───┬───┐ ┌───┤ │224│225│ │255│ ├───┼───┼────────┄┄┄──────────┼───┤ │ 0 │ 1 │ │ 31│ ├───┴───┘ └───┤ ┆ Окно 1 ┆ ├───┬───┐ ┌───┤ │224│225│ │255│ ├───┼───┼────────┄┄┄──────────┼───┤ │ 0 │ 1 │ │ 31│ ├───┴───┘ └───┤ ┆ Окно 2 ┆ ├───┬───┐ ┌───┤ │224│225│ │255│ └───┴───┴────────┄┄┄──────────┴───┘ Если мы захотим что–то изменить в Таблице PNT, это немедленно скажется на изображении в соответствующем окне. Таблица PNT редко используется при составлении программ. Более того, можно рассматривать структуру экрана, "забыв" о делении экрана на окна. Достаточно при этом мысленно пронумеровать квадраты экрана от 0 до 767. Покажем, как можно использовать Таблицу PNT для копирования изображения в пределах //одного// экранного окна. Пусть, например, вам нужно скопировать изображение из квадрата с номером A в квадрат с номером B. Для этого в байт Таблицы PNT, отвечающий за квадрат с номером B, поместите номер квадрата A. Этого достаточно для того, чтобы произошёл процесс копирования! {{anchor:e1114-01}} __//Пример 1//__. \\ {{.examples:1114-01.bas|}} \\ [[+tab|wmsxbpge>1114-01.bas]] 10 COLOR 1,15:SCREEN 2 20 LINE(8,8)-(15,15),,BF 'Сформировано изображение в квадрате 33 30 A$=INPUT$(1) 40 VPOKE &H1800+40,33 'Скопировали его в квадрат 40 50 GOTO 50 Более того, Вы можете заранее (до того, как будете что–то рисовать на экране) "размножить" по нужным адресам номер определённого блока. Далее вам достаточно лишь заполнить изображением тот квадрат,номер которого был "размножен", и, к Вашей радости, это изображение появится и в других местах! {{anchor:e1114-02}} __//Пример 2//__. \\ {{.examples:1114-02.bas|}} \\ [[+tab|wmsxbpge>1114-02.bas]] 10 COLOR 1,15:SCREEN 2 20 VPOKE &H1800+40,33 'Квадрат 40 подготовлен для приема 30 A$=INPUT$(1) 'копии из квадрата 33 40 LINE(8,8)-(15,15),,BF 'Сформировано изображение в 33-м и 50 GOTO 50 'в 40-м квадратах Если же Вы захотите скопировать какой–либо элемент в другое //окно// экрана, то вам поможет работа с Таблицами PGT и CT,к рассмотрению которых мы и переходим. Каждый квадрат 8×8 точек разобьём на 8 горизонтальных участков,которые будем называть //линиями// . Информация о каждой линии (1 байт) содержится в Таблице PGT. Следовательно, объем этой Таблицы равен 768×8 = 6144 байтам. Адрес байта Таблицы PGT, отвечающего за расположение //линии// вычисляется при помощи арифметического выражения BASE(5×N+2) + (256×n1+n2)×8 + k , где: * N — номер режима SCREEN; * n1 — номер окна; * n2 — номер квадрата в этом окне; * k — номер линии в этом квадрате. Отметим, что если в Таблице PNT были изменения, то могут возникнуть затруднения при попытке "нарисовать" что–либо в квадрате с изменённым номером. {{anchor:e1114-03}} __//Пример 3//__. \\ {{.examples:1114-03.bas|}} \\ [[+tab|wmsxbpge>1114-03.bas]] 10 COLOR 1,15:SCREEN 2 20 VPOKE 6144+40,VPEEK(6144+33)'Произошло изменение в Таблице PNT 30 A$=INPUT$(1) 'Ждем нажатия клавиши! 40 LINE(64,8)-(71,15),,BF 'Попытка вывести изображение в квадрате 50 GOTO 50 '40 не привела к ожидаемому результату! Так как информация о линии хранится в одном байте, то каждой точке линии соответствует определённый бит этого байта. Оказывается, что "высветить точку на экране" — это значит установить нужный бит в 1,"стереть точку с экрана" — это значит установить бит в 0 ! Если некоторый бит равен 0,то соответствующую ему точку на экране будем называть точкой //фона//, в противном случае будем называть её точкой //изображения//. Каждому байту Таблицы PGT однозначно соответствует один байт в Таблице цветов (CT), причём четыре младших бита этого байта кодируют локальный цвет //фона// для каждой линии, а четыре старших — локальный цвет //изображения//. Например: Точки фона │ │ │ │ │ ┌────┬──▼─┬──▼─┬──▼─┬────┬────┬──▼─┬──▼─┐ │ 1 │ 0 │ 0 │ 0 │ 1 │ 1 │ 0 │ 0 │ Байт PGT └──▲─┴────┴────┴────┴──▲─┴──▲─┴────┴────┘ │ │ │ Точки изображения ┌────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 0 │ 1 │ 1 │ 1 │ 0 │ 1 │ Байт CT └────┴────┴────┴────┴────┴────┴────┴────┘ └────────▲────────┘ └────────▲─────────┘ │ │ Цвет изображения Цвет фона Таким образом,точки изображения будут иметь цвет 5, а точки фона будут иметь цвет 13. Так как из четырёх двоичных цифр можно составить только 16 комбинаций, то ясно, что одновременно на экране может быть не //более// 16 цветов. Вследствие этого изменение цвета одной точки приводит к переопределению цвета //изображения всей// линии! Адрес байта Таблицы CT, отвечающего за //цвет// линии, вычисляется при помощи арифметического выражения: BASE(5×N+1) + (256×n1+n2)×8 + k , где: * N — номер режима ''SCREEN''; * n1 — номер окна; * n2 — номер квадрата в этом окне; * k — номер линии в этом квадрате. {{anchor:e1114-04}} __//Пример 4//__. Предположим, что вам захотелось в 5–й линии 58–го квадрата 2–го окна в режиме SCREEN 2 точки 0–3 изобразить цветом 3, а точки 4–7 — цветом 15. \\ {{.examples:1114-04.bas|}} \\ [[+tab|wmsxbpge>1114-04.bas]] 10 SCREEN 2 20 A=BASE(5*2+1)+(256*2+58)*8+5 30 B=BASE(5*2+2)+(256*2+58)*8+5 40 VPOKE B,&B11110000 50 VPOKE A,&H3F 60 GOTO 60 А теперь — давно обещанный вам пример: \\ {{anchor:e1114-05}} __//Пример 5//__. Копирование содержимого 0–го квадрата из 0–го окна в содержимое 0–го квадрата 2–го окна \\ {{.examples:1114-05.bas|}} \\ [[+tab|wmsxbpge>1114-05.bas]] 10 COLOR 15,1,1:SCREEN2 20 LINE(0,0)-(7,7),,BF 25 FOR I=0 TO 7 30 VPOKE BASE(5*2+2)+(256*2+0)*8+I,VPEEK(BASE(5*2+2)+(256*0+0)*8+I): 'Копирование изображения 35 VPOKE BASE(5*2+1)+(256*2+0)*8+I,VPEEK(BASE(5*2+1)+(256*0+0)*8+I): 'Копирование цвета 40 NEXT 50 GOTO 50 {{anchor:e1114-06}} __//Пример 6//__. Изобразим квадрат,стороны которого имеют разные цвета, не используя оператор ''PSET''. \\ {{.examples:1114-06.bas|}} \\ [[+tab|wmsxbpge>1114-06.bas]] 10 SCREEN 2 14 DATA 0,5,1,37,2,37,4,37,8,165,4,165,2,165,1,21,0,5,0,5,128,133,64,133,32,133,64,21,128,21,0,5:'Фон синего цвета 15 FOR I=0 TO 1 16 FOR J=0 TO 7 20 A=BASE(5*2+2)+(256*0+I)*8+J 30 B=BASE(5*2+1)+(256*0+I)*8+J 40 READ Z,U:VPOKE A,Z:VPOKE B,U 60 NEXT J 70 NEXT I 80 GOTO 80 · Точки · · Точки зелёного ──▶· ·◀── красного цвета · · цвета Точки ──▶· ·◀── Точки жёлтого · · чёрного цвета · цвета Важно заметить, что Таблица CT инициализируется цветом //фона//, задаваемым в операторе ''COLOR''. Опишем алгоритм установки точки в режимах ''SCREEN 2'' и ''SCREEN 4''. - Первый шаг состоит в нахождении адреса байта Таблицы PGT в зависимости от координат (X,Y) ("//грубая// настройка"). Адрес = ((Y\8)*32+Х\8)*8+Y MOD 8 . - После этого нужно точно определить номер бита найденного байта, отвечающего за данную точку ("//точная// настройка"). Трудность состоит в несоответствии номеров бит в байте и значений Х–координат тех точек, за которые этот байт отвечает: ^ Х MOD 8 |0|1|2|3|4|5|6|7| ^ Номер бита |7|6|5|4|3|2|1|0|. Формула, при помощи которой можно найти номер бита по Х–//координате//, выглядит следующим образом: NB = 2^(8+NOT(X MOD 8)) . - Теперь остаётся записать "1" в найденный бит. VPOKE Адрес, VPEEK (Адрес) OR NB . И… точка появится в требуемом месте экрана. - Наконец, изменим цвет изображения выведенной точки: //Адрес// = //Адрес// + &h2000 VPOKE //Адрес//, VPEEK(//Адрес//) MOD 16 + COL*16 , * где ''COL'' — номер цвета. Опишем алгоритм работы видеопроцессора при выводе содержимого квадрата 8×8 на графические экраны ''SCREEN 2'' или ''SCREEN 4''. Предположим, что нам известно местоположение данного квадрата на экране. Пусть N — номер квадрата с координатами (X,Y) (0≤X≤31,0≤Y≤23)(номер N пока нам неизвестен!). Взгляните на рисунок: ┌───┬───┬─────────┄┄┄─────────┬───┐ Y=0 │ 0 │ 1 │ │ 31│ ├───┴───┘ └───┤ ⋯ ┆ ⋯ ⋯ ⋯ ┆ Окно 0 ├───┬───┐ ┌───┤ Y=7 │224│225│ │255│ ├───┼───┼─────────┄┄┄─────────┼───┤ Y=8 │ 0 │ 1 │ ┌───┐ │ 31│ ├───┴───┘ ┼▼┼ X └───┤ ⋯ ┆ ⋯ ⋯ Y───▶N│ ⋯ ┆ Окно 1 ├───┬───┐ ┼─┼ ┌───┤ Y=15 │224│225│ │255│ ├───┼───┼─────────┄┄┄─────────┼───┤ Y=16 │ 0 │ 1 │ │ 31│ ├───┴───┘ └───┤ ⋯ ┆ ⋯ ⋯ ⋯ ┆ Окно 2 ├───┬───┐ ┌───┤ Y=23 │224│225│ │255│ └───┴───┴─────────┄┄┄─────────┴───┘ "Посмотрев" Таблицу PNT по адресу (Y\8)*256+(YMOD8)*32+X, найдём N. "Запишем" информацию о квадрате в Таблицу PGT по адресам: * (Y\8)*2048+N*8, * (Y\8)*2048+N*8+1, * (Y\8)*2048+N*8+2, * (Y\8)*2048+N*8+3, * (Y\8)*2048+N*8+4, * (Y\8)*2048+N*8+5, * (Y\8)*2048+N*8+6, * (Y\8)*2048+N*8+7, в результате на экране в квадрате (X,Y) Вы увидите то, что хотели! А теперь "раскрасим" изображение. "Запишем" информацию о цвете в Таблицу CT по адресам: * (Y\8)*2048+N*8 , * (Y\8)*2048+N*8+1, * (Y\8)*2048+N*8+2, * (Y\8)*2048+N*8+3, * (Y\8)*2048+N*8+4, * (Y\8)*2048+N*8+5, * (Y\8)*2048+N*8+6, * (Y\8)*2048+N*8+7, в результате квадрат (X,Y) будет раскрашен в нужные вам цвета. {{anchor:e1114-07}} __//Пример 7//__. \\ {{.examples:1114-07.bas|}} \\ [[+tab|wmsxbpge>1114-07.bas]] 10 COLOR 1,15,8:SCREEN 2:X=5:Y=10 20 N=VPEEK(BASE(5*2+0)+(Y\8)*256+(YMOD8)*32+X) 'Видеопроцессор "опрашивает" байт номер 69 в окне 1 Таблицы PNT и находит значение N (N=69, если Таблица PNT не изменялась) 30 FOR I=0 TO 7 40 VPOKE(&H800+N*8+I),&B11100011 'Таблица PGT разделена на три окна, каждое из которых содержит по 2048 байтов. Следовательно, окно 1 этой Таблицы начинается по адресу 2048=&H800. 41 'Первый из 8 байтов квадрата, на который указывает N в окне 1, размещается в ячейке &Н800+N*8 50 NEXT 'Содержимое этих 8 байтов и будет выведено в квадрате (X,Y) 60 GOTO 60 {{anchor:e1114-08}} __//Пример 8//__. \\ {{.examples:1114-08.bas|}} \\ [[+tab|wmsxbpge>1114-08.bas]] 10 SCREEN 2:X=15:Y=12 20 A=VPEEK(BASE(5*2+0)+(Y\8)*256+(YMOD8)*32+X) '"Смотрим" PNT 30 FOR I=0 TO 7 40 VPOKE(BASE(5*2+2)+(Y\8)*2048+A*8+I),&b11100011 'Формируем "содержимое" квадрата 50 NEXT 60 GOTO 60 {{anchor:e1114-09}} __//Пример 9//__. Раскрасим выводимый квадрат 8–м и 10–м цветами. \\ {{.examples:1114-09.bas|}} \\ [[+tab|wmsxbpge>1114-09.bas]] 10 SCREEN 2:X=15:Y=12 20 A=VPEEK(BASE(5*2+0)+(Y\8)*256+(YMOD8)*32+X) '"Смотрим" Таблицу PNT 30 FOR I=0 TO 7 40 VPOKE(BASE(5*2+2)+(Y\8)*2048+A*8+I),&B11100011 'Формируем "содержимое" квадрата 50 NEXT 60 FOR I=0 TO 7 70 VPOKE(BASE(5*2+1)+(Y\8)*2048+A*8+I),&H8A ' "Раскрасим" квадрат 80 NEXT 90 GOTO 90 Однако в режимах ''SCREEN 2'' и ''SCREEN 4'' используется система координат (X,Y), в которой Х изменяется от 0 до 255, а Y от 0 до 191. Следующий пример иллюстрирует, как эта система координат соотносится с делением экрана на квадраты. {{anchor:e1114-10}} __//Пример 10//__. \\ {{.examples:1114-10.bas|}} \\ [[+tab|wmsxbpge>1114-10.bas]] 10 SCREEN 2:X=100:Y=75 30 N=(Y\8)*32+(X\8) 'Номер квадрата, в котором будет выведена точка 40 M=Y MOD 8 'Номер линии в квадрате 50 AP=N*8+M 'Адрес соответствующего байта в Tаблице PGT 60 VA=&b00001000 65 AC=AP+&H2000 'Для определения соответствующего адреса в Таблице CT прибавим &H2000 к адресу Таблицы PGT 70 VPOKE AP,VA 'Значение VA=&B00001000 загрузим в PGT 80 VPOKE AC,&HF1 'Вводим значение &HF1 в Таблицу цветов для изображения точки белого цвета на черном фоне 90 IF INKEY$="" THEN 90 100 PSET(X,Y),6 110 GOTO 110 Сначала будет нарисована белая точка на чёрном фоне. Когда Вы нажмёте любую клавишу, эта точка приобретёт красный цвет. При программировании на [[msx:basic:]] этот способ формирования изображения применяется редко. Однако, если Вы хотите нарисовать что–либо с помощью программы на //машинном языке//, то приведённый выше алгоритм несомненно поможет Вам! Ясно,что обладая определённым набором графических элементов, можно синтезировать различные графические изображения. Приведём без комментариев ряд примеров: {{anchor:e1114-11}} __//Пример 11//__. Одинаковые шаблоны \\ {{.examples:1114-11.bas|}} \\ [[+tab|wmsxbpge>1114-11.bas]] 20 COLOR 15,1,1:CLS:SCREEN 2:COLOR 15,1:CLS 60 FOR I=0 TO 7 70 READ A:VPOKE I,A:VPOKE I+2048,A:VPOKE I+4096,A 80 NEXT 90 FOR I=6144 TO 6144+767:VPOKE I,0:NEXT 120 FOR I=8192 TO 14435:VPOKE I,241:NEXT 150 GOTO 150 160 DATA &b11111111 170 DATA &b10011001 180 DATA &b10111101 190 DATA &b11100111 200 DATA &b11100111 210 DATA &b10111101 220 DATA &b10011001 230 DATA &b11111111 {{anchor:e1114-12}} __//Пример 12//__. \\ {{.examples:1114-12.bas|}} \\ [[+tab|wmsxbpge>1114-12.bas]] 10 COLOR 1,15,6:SCREEN 2 20 FOR T=8 TO 15:LINE(8,T)-(15,T),T:NEXT:A$=INPUT$(1) 30 FOR T=0 T0 7:VPOKE 2048+33*8+T,VPEEK(33*8+T):NEXT 40 A$=INPUT$(1) 50 FOR T=0 TO 7:VPOKE 10240+33*8+T,VPEEK(8192+33*8+T):NEXT 60 A$=INPUT$(1) {{anchor:e1114-13}} __//Пример 13//__. \\ {{.examples:1114-13.bas|}} \\ [[+tab|wmsxbpge>1114-13.bas]] 10 'Шахматная доска! 20 INPUT "Координаты X,Y";X,Y:X=X-XMOD8:Y=Y-YMOD8 21 IF X=0 THEN X=8 22 U=Y/8*32+X/8 25 COLOR 1,15,1:SCREEN 2 30 FOR T=0 TO 3:FOR I1=0 TO 1:FOR I2=0 TO 1:FOR F=U TO U+12 STEP 4:FOR K=0 TO 1 40 VPOKE BASE(10)+(F+(64+2)*K)+I2+32*I1+128*T,VPEEK (BASE(10)):NEXT K,F,I2,I1,T 50 LINE(0,0)-(8,192),1,BF:LINE(X,Y)-STEP(128,128),1,B:A$=INPUT$(1) {{anchor:e1114-14}} __//Пример 14//__. \\ {{.examples:1114-14.bas|}} \\ [[+tab|wmsxbpge>1114-14.bas]] 10 COLOR 1,15,8:SCREEN 2:LINE(0,64)-(255,127),,BF 'Фон! 20 LINE(0,64)-(7,71),8,BF 'Перемещаемый объект! 30 FOR T=1 TO 31 40 F=VPEEK(6400+T):VPOKE 6400+T,VPEEK(6400+T-1):VPOKE 6400+T-1,F'Обмен значений между ячейками видеопамяти! 50 IF T=31 THEN VPOKE 6400+T,T:VPOKE 6400,0 60 NEXT T:GOTO 30 {{anchor:e1114-15}} __//Пример 15//__. \\ {{.examples:1114-15.bas|}} \\ [[+tab|wmsxbpge>1114-15.bas]] 10 CLEAR 200,&HC300:SCREEN 2 20 CIRCLE(90,70),56:PAINT STEP(0,0) 'Сформировано изображение 25 'Сохраняем изображения в памяти (RAM) 30 FOR I=BASE(5*2+1) TO BASE(5*2+1)+6143:POKE &HC300-BASE(5*2+1)+I, VPEEK(I):NEXT 40 FOR I=BASE(5*2+2) TO BASE(5*2+2)+6143:POKE &HC300+6144-BASE(5*2+2)+I,VPEEK(I):NEXT 50 SCREEN 0 60 SCREEN 2 'Вывод изображения на экран 70 FOR I=BASE(5*2+1) TO BASE(5*2+1)+6143:VPOKE I,PEEK(&HC300-BASE(5*2+1)+I):NEXT 80 FOR I=BASE(5*2+2) TO BASE(5*2+2)+6143:VPOKE I,PEEK(&HC300-BASE(5*2+2)+6144+I):NEXT 90 A$=INPUT$(1) 'Программа работает ≈ 5 минут {{anchor:n1115}} ==== XI.1.5. Режим SCREEN 3 ==== Как и в режиме ''SCREEN 2'', экран в режиме ''SCREEN 3'' разбит на //квадраты// размером 8×8 точек (32×24 квадрата). Каждый квадрат разобьём на две //линии// толщиной четыре точки (на экране расположено 32×48 "толстых" линий). Каждая из этих "толстых" линий разбита на две "большие" точки (4×4 "маленьких" точек). ──▲──┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ │ │ │ │ │ │ │ │ │ │████│◀── "Маленькая" │ │────│────│────│────│ │────│────│────│────│ точка "Толщина"│ │ │ │ │ │ │ │ │ │ │ │ │────│────│────│────│ │────│────│────│────│ линии │ │ │ │ │ │ │ │ │ │ │ │ │────│────│────│────│ │────│────│────│────│ │ │ │ │ │ │ │ ──▼──└────┴────┴──── Квадрат ────┴────┴────┘ ┌────┬────┬──── ────┬────┬────┐ │ │ │ │ │ │████│████│████│████│ │────│────│────│────│ │────│────│────│────│ "Толстая" │ │ │ │ │ │████│████│████│████│ ───▶ │────│────│────│────│ │────│────│────│────│ ◀── "Большая" линия │ │ │ │ │ │████│████│████│████│ точка │────│────│────│────│ │────│────│────│────│ │ │ │ │ │ │████│████│████│████│ ├────┴────┴────┴────┘ └────┴────┴────┴────┤ │◀─────────────"Длина" линии ─────────────▶│ Каждая из "больших" точек может быть раскрашена только в //один// цвет. Попытка расположить в "большой" точке "маленькую" точку другого цвета приведёт к //изменению// цвета //всей// "большой" точки. Информация о цвете "толстой" линии находится в Таблице PGT, причём левый полубайт байта PGT кодирует цвет левой "большой" точки "толстой" линии, а правый полубайт отвечает за цвет правой "большой" точки. Байт PGT ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ 1 │ 0 │ 0 │ 0 │ 1 │ 0 │ 1 │ 0 │ └───┴───┴───┴───┴───┴───┴───┴───┘ └──────▲──────┘ └──────▲──────┘ │ │ Цвет левой "большой" точки Цвет правой "большой" точки Поскольку один байт Таблицы PGT кодирует цвета "толстой" линии, то эта Таблица требует 32×48=1536 байт VRAM. {{anchor:e1115-01}} __//Пример 1//__. \\ {{.examples:1115-01.bas|}} \\ [[+tab|wmsxbpge>1115-01.bas]] 10 SCREEN 3:OPEN"GRP:" AS#1 20 PSET(8,0),3:PSET(12,0),1 'Рисуем "толстую" линию 30 PSET(30,80):PRINT #1,HEX$(VPEEK(8)) 40 A$=INPUT$(1) Оператор ''COLOR'' с последующим оператором ''CLS'' инициализируют Таблицу PGT, причём все байты Таблицы PGT инициализируются цветом фона, закодированным как в левом, так и в правом полубайтах. А в следующей табличке показаны номера позиций "толстых" линий на экране: ┌────┬────┬────┬─┄┄┄─┬────┐ │ 0 │ 8 │ 16 │ ⋯ │ 248│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 1 │ 9 │ 17 │ ⋯ │ 249│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 2 │ 10 │ 18 │ ⋯ │ 250│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 3 │ 11 │ 19 │ ⋯ │ 251│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 4 │ 12 │ 20 │ ⋯ │ 252│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 5 │ 13 │ 21 │ ⋯ │ 253│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 6 │ 14 │ 22 │ ⋯ │ 254│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 7 │ 15 │ 23 │ ⋯ │ 255│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 256│ 264│ 272│ ⋯ │ 504│ ├────┼────┼────┼─┄┄┄─┼────┤ │ 257│ 265│ 273│ ⋯ │ 505│ ├────┼────┼────┼─┄┄┄─┼────┤ │ ⋯ │ ⋯ │ ⋯ │ ⋯ │ ⋯ │ ├────┼────┼────┼─┄┄┄─┼────┤ │ 263│ 271│ 279│ ⋯ │ 511│ ├────┼────┼────┼─┄┄┄─┼────┤ │ ⋯ │ ⋯ │ ⋯ │ ⋯ │ ⋯ │ ├────┼────┼────┼─┄┄┄─┼────┤ │1285│1293│1301│ ⋯ │1534│ ├────┼────┼────┼─┄┄┄─┼────┤ │1286│1294│1302│ ⋯ │1535│ └────┴────┴──│─┴─┄┄┄─┴────┘ ┌──┬──┬──┬─▼┬──┬──┬──┬──┐ │ 1│ 0│ 0│ 0│ 0│ 0│ 1│ 0│ └──┴──┴──┴──┴──┴──┴──┴──┘ {{anchor:e1115-02}} __//Пример 2//__. Выполнив эту программу, Вы можете убедиться в правильности заполнения данной таблички. \\ {{.examples:1115-02.bas|}} \\ [[+tab|wmsxbpge>1115-02.bas]] NEW Ok 10 SCREEN 3 20 VPOKE BASE(5*3+2)+6,&H56 30 VPOKE BASE(5*3+2)+7,&H34 40 VPOKE BASE(5*3+2)+8,&H78 50 VPOKE BASE(5*3+2)+9,&H9A 60 A$=INPUT$(1) Байт из Таблицы PGT (в нем хранится цвет "толстой" линии с номером 1302) Приведём таблицу, по которой можно определить адрес байта Таблицы PGT, отвечающего за точку (X,Y), в режимах 2–4: ^ Режим экрана ^ //Адрес байта// в PGT ^ | 2 и 4 | %% ((Y\8)*32+(Х\8))*8+Y MOD 8 %% | | 3 | BASE(5*3+2)+(Х\8)*8+(Y\32)*256+(Y\4) MOD 8 | {{anchor:e1115-11}} __//Пример 1//__. Заполнение экрана чёрными и белыми клетками в шахматном порядке. \\ {{.examples:1115-11.bas|}} \\ [[+tab|wmsxbpge>1115-11.bas]] 10 'Шахматная доска 20 COLOR 15,1,1:CLS:SCREEN 3 50 FOR I=0 TO 7 STEP 2 60 VPOKE I,&HF1:VPOKE I+1,&H1F 70 NEXT 80 FOR I=BASE(5*3+0) TO I+767 90 VPOKE I,0 100 NEXT 110 GOTO 110 Таблица PGT разбита на 192 "кусочка" размером по 8 байт. Каждый "кусочек" отвечает за 4 квадрата размером 2×2 "больших" точки (такой квадрат называется //именем//). Упомянутые 4 имени имеют один и тот же номер, который записывается в Таблицу PNT. Но //первый// квадрат — это имя с данным номером для строк (строка имеет высоту 2 "большие" точки) с номерами 0, 4, 8, 12, 16, 20; * //второй// — для строк с номерами 1, 5, 9, 13, 17, 21; * //третий// — для строк с номерами 2, 6, 10, 14, 18, 22; * //четвёртый// — для строк с номерами 3, 7, 11, 15, 19, 23. Следовательно, весь экран разбит на //четыре окна// \\ (понятие экранного окна см. в описании режима ''SCREEN 2''). За имя с номером N в окне с номером M отвечают байты PGT N×8+M×2 и N×8+M×2+1, где N∈[0,191], a M∈[0,3] Приведём структуру PGT с учётом разбивки экрана на имена и окна. ┌────┬────┬────┬─┄┄┄─┬────┐ Номер имени │ 0 │ 1 │ 2 │ ⋯ │ 15 │ │ │ │ │ │ │ N ├────┼────┼────┼─┄┄┄─┼────┤ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ├────┼────┼────┼─┄┄┄─┼────┤ ─┐ │ 0 │ 8 │ 16 │ ⋯ │ 248│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ├─ Имя с номером N для окна 0 │ 1 │ 9 │ 17 │ ⋯ │ 249│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ─┤ │ 2 │ 10 │ 18 │ ⋯ │ 250│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ├─ Имя с номером N для окна 1 │ 3 │ 11 │ 19 │ ⋯ │ 251│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ─┤ │ 4 │ 12 │ 20 │ ⋯ │ 252│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ├─ Имя с номером N для окна 2 │ 5 │ 13 │ 31 │ ⋯ │ 253│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ─┤ │ 6 │ 14 │ 22 │ ⋯ │ 254│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ├─ Имя с номером N для окна 3 │ │ 7 │ 15 │ 23 │ ⋯ │ 255│ │ ─▼─ ├────┼────┼────┼─┄┄┄─┼────┤ ─┘ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ├────┼────┼────┼─┄┄┄─┼────┤ │ 263│ 271│ 279│ ⋯ │ 511│ ├────┼────┼────┼─┄┄┄─┼────┤ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ├────┼────┼────┼─┄┄┄─┼────┤ ─┐ │1285│1293│1301│ ⋯ │1534│ │ ├────┼────┼────┼─┄┄┄─┼────┤ ├─ Имя с номером N для окна 3 │1286│1294│1302│ ⋯ │1535│ │ └────┴────┴────┴─┄┄┄─┴──▲─┘ ─┘ └─ Имя с номером 191 Приведём структуру PNT с номерами имён и их расположением на экране: 0 1 2 3 … … … 31 ◀─ Номер столбца ┌───┬───┬───┬───┬───┬───┬───┬────┐ 0 │ 0 │ 1 │ 2 │ 3 │ … │ … │ … │ 31 │ Окно 0: строки 0,4, 8,12,16,20 ├───┼───┼───┼───┼───┼───┼───┼────┤ 1 │ 0 │ 1 │ 2 │ … │ … │ … │ 30│ 31 │ Окно 1: строки 1,5, 9,13,17,21 ├───┼───┼───┼───┼───┼───┼───┼────┤ 2 │ 0 │ 1 │ … │ … │ … │ 29│ 30│ 31 │ Окно 2: строки 2,6,10,14,18,22 ├───┼───┼───┼───┼───┼───┼───┼────┤ 3 │ 0 │ … │ … │ … │ 28│ 29│ 30│ 31 │ Окно 3: строки 3,7,11,15,19,23 ├───┼───┼───┼───┼───┼───┼───┼────┤ 4 │ 32│ 33│ 34│ 35│ … │ 61│ 62│ 63 │ ├───┼───┼───┼───┼───┼───┼───┼────┤ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ├───┼───┼───┼───┼───┼───┼───┼────┤ 7 │ 32│33 │ … │ … │ … │ … │ 62│ 63 │ ├───┼───┼───┼───┼───┼───┼───┼────┤ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯ ┆ ⋯┆ ⋯ ┆ ├───┼───┼───┼───┼───┼───┼───┼────┤ 23│160│161│ … │ … │ … │189│190│ 191│ ▲ └───┴───┴───┴───┴───┴───┴───┴────┘ └─ Номер строки Номер имени в квадрате с координатами X,Y (X∈[0,31],Y∈[0,23]) хранится в ячейке VRAM с адресом: \\ BASE(5*3+0)+(Y\4)*32+X \\ Это имя находится в окне с номером Y MOD 4 {{anchor:e1115-12}} __//Пример 2//__. \\ {{.examples:1115-12.bas|}} \\ [[+tab|wmsxbpge>1115-12.bas]] 10 COLOR 15,1,1:CLS:SCREEN 3 20 FOR I=0 TO 1 STEP 2 30 VPOKE I,&HF1:VPOKE I+1,&H1F 'Имя 0 для окна 0 (черно-белое) 40 VPOKE I+2,&HF8:VPOKE I+3,&H8F 'Имя 0 для окна 1 (красно-белое) 45 'Имя с номером 0 для окон 2 и 3 - пустое 60 NEXT 70 FOR I=BASE(5*3+0) TO I+767 ' Заполним PNT нулями 80 VPOKE I,0 90 NEXT 95 'На экране появятся 6 (24/4) черно-белых и красно-белых полос 100 GOTO 100 {{anchor:n1116}} ==== XI.1.6. Режимы SCREEN 5, SCREEN 6, SCREEN 7 и SCREEN 8 (для компьютеров MSX 2) ==== В режимах ''SCREEN 5'' – ''SCREEN 8'' Таблицы PGT и CT //отсутствуют//! Поэтому вся информация об изображении точек находится в Таблице PNT. В отличие от рассмотренных ранее режимов, эти режимы не имеют деления экрана на //квадраты//. Вначале приведём важную табличку, которая поможет вам определить адрес байта Таблицы PNT, отвечающего за точку с координатами (X,Y), в различных режимах ''SCREEN''>: ^ Режим экрана ^ //Адрес байта// в PNT ^ | ''SCREEN 5'' | BASE(5*5)+(256/2)*Y+(X\2) | | ''SCREEN 6'' | BASE(5*6)+(512/4)*Y+(X\4) | | ''SCREEN 7'' | BASE(5*7)+(512/2)*Y+(X\2) | | ''SCREEN 8'' | BASE(5*8)+(256/1)*Y+(X\1) | - В режиме ''SCREEN 5'' экран разделен на 212 строк (или на 192 строки), состоящих из 256 точек каждая. Совокупность двух точек по горизонтали будем называть //линией// (точки 0 и 1 образуют 1–ю линию, точки 2 и 3 — 2–ю линию ,… , точки 254 и 255 — 128–ю линию). Каждая линия кодируется в //одном// байте, причём четыре старших бита этого байта определяют цвет первой точки, а четыре младших — цвет второй точки. Ясно, что требуется 212×256/2=27136 байтов для хранения сведений о цветах линий (как раз объем Таблицы PNT в режиме ''SCREEN 5'' !). Первый байт Таблицы PNT "хранит" информацию о цвете первой линии первой строки экрана, второй байт — о цвете второй линии той же строки, и так далее: ^ 1–й байт Таблицы PNT ^| ^ 2–й байт Таблицы PNT ^^ |Цвет 1–й точки \\ первой линии | Цвет 2–й точки \\ первой линии | | Цвет 1–й точки \\ второй линии | Цвет 2–й точки \\ второй линии | Таблица PNT инициализируется цветом фона, который устанавливается оператором ''COLOR''. {{anchor:e1116-01}} __//Пример 1//__. Изобразим в режиме ''SCREEN 5'' точку с координатами (X,Y) белым цветом. \\ {{.examples:1116-01.bas|}} \\ [[+tab|wmsxbpge>1116-01.bas]] 10 COLOR 15,4,7:INPUT"X,Y";X,Y 20 SCREEN 5 ┌───────── Код цвета фона 30 AD=BASE(5*5)+Y*128+(X\2) │┌──────── Код цвета изображения ▼▼ 40 IF XMOD2=0 THEN C=&HF4 ELSE C=&H4F'Если не будет этого условия, то изобразятся д в е соседние точки 50 VPOKE AD,C ' Этот оператор эквивалентен оператору PSET(X,Y),15.PSET(X,Y),15. 60 GOTO 60 Приведём схематическое изображение PNT для режима ''SCREEN 5''. | 0–й байт |отвечает за точки с координатами (0,0) и (1,0)| | 1–й байт |отвечает за точки с координатами (2,0) и (3,0)| | … | … | | 127–й байт |отвечает за точки с координатами (254,0) и (255,0)| | 128–й байт |отвечает за точки с координатами (0,1) и (1,1)| | … | … | | 27134–й байт |отвечает за точки с координатами (252,211) и (253,211)| | 27135–й байт |отвечает за точки с координатами (254,211) и (255,211)| - В режиме ''SCREEN 6'' экран имеет 212 строк (или 192 строки) по 512 точек в каждой строке. Количество байтов в Таблице PNT точно такое же,как и в Таблице PNT режима ''SCREEN 5'': информация об одной строке экрана кодируется в 128 байтах. //Линия// в режиме ''SCREEN 6'' состоит из четырёх точек и кодируется в //одном// байте. А тогда //палитра// каждой точки кодируется в двух битах, а так как из двух двоичных цифр можно составить только четыре комбинации (00, 01, 10, 11), то каждую точку экрана можно раскрасить не более чем //четырьмя// различными способами. Так, например, оператор VPOKE 0,&B11100100 присваивает палитру 3 первой точке первой линии, палитру 2 — второй точке первой линии, палитру 1 — третьей точке первой линии и палитру 0 — четвёртой точке первой линии. Байт Таблицы PNT ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ 1 │ 1 │ 1 │ 0 │ 0 │ 1 │ 0 │ 0 │ └───┴───┴───┴───┴───┴───┴───┴───┘ └───▲───┘└──▲──┘└───▲───┘└──▲───┘ │ │ │ │ Палитра Палитра Палитра Палитра первой второй третьей четвёртой точки точки точки точки Таблица PNT инициализируется последними двумя битами цвета фона, задаваемого в операторе ''COLOR''. Поясним сказанное примером. Если цвет фона имеет номер 13=&B1101, то в каждый байт Таблицы PNT будет занесено число &B01010101 (четыре раза повторяются последние два бита кода цвета фона). Приведём схематическое изображение PNT для режима ''SCREEN 6''. | 0–й байт | (0,0) | (1,0) | (2,0) | (3,0) | | 1–й байт | (4,0) | (5,0) | (6,0) | (7,0) | | … | … | … | … | … | | 127–й байт | (508,0) | (509,0) | (510,0) | (511,0) | | 128–й байт | (0,1) | (1,1) | (2,1) | (3,1) | | … | … | … | … | … | | 27135–й байт | (508,211) | (509,211) | (510,211) | (511,211) | - Как и в режиме ''SCREEN 6'', в режиме ''SCREEN 7'' на экране расположено 212 строк (или 192 строки), состоящих из 512 точек каждая. Однако один байт Таблицы PNT кодирует //линию//, состоящую из //двух// точек: старшие четыре бита определяют палитру левой точки, младшие четыре — палитру правой точки. ^ 1–й байт Таблицы PNT ^| ^ 2–й байт Таблицы PNT ^^ | Палитра первой \\ точки 1–й линии | Палитра второй \\ точки 1–й линии | | Палитра первой \\ точки 2–й линии | Палитра второй \\ точки 2–й линии | Следовательно, каждой точке может быть присвоена любая из 16 палитр. Поскольку для кодирования номера палитры необходимо четыре бита, то Таблица PNT занимает объем 212×512/2 = 54272 байта. Уже отсюда становится понятно, что для использования этого режима VRAM должна иметь объем не менее 128 Кбайт! Режим ''SCREEN 7'' аналогичен режиму ''SCREEN 5'', за исключением того, что в режиме ''SCREEN 7'' в строке экрана в два раза //больше// точек. Таблица PNT инициализируется цветом фона, который устанавливает оператор ''COLOR''. Приведём схематическое изображение PNT для режима ''SCREEN 7''. | 0–й байт |отвечает за точки с координатами (0,0) и (1,0)| | 1–й байт │отвечает за точки с координатами (2,0) и (3,0)| | … | … | | 255–й байт │отвечает за точки с координатами (510,0) и (511,0)| | 256–й байт |отвечает за точки с координатами (0,1) и (1,1)| | … | … | | 54270–й байт |отвечает за точки с координатами (508,211) и (509,211)| | 54271–й байт |отвечает за точки с координатами (510,211) и (511,211)| - В режиме ''SCREEN 8'' экран состоит из 212 строк по 256 точек в каждой или из 212 строк по 192 точки в каждой. //Линия// состоит из одной–единственной точки. Цвет линии здесь уже определяется не кодом палитры, а непосредственным заданием "смеси" основных цветов. Этот оригинальный способ кодирования цвета требует по одному //байту//(!) на линию, а, значит, на точку! Поэтому Таблица PNT имеет объем 212·256=54272 байта. Уже отсюда становится понятно, что для использования этого режима VRAM должна иметь объем не менее 128 Кбайт! Информация о линии с координатами (X,Y) находится по адресу X+256·Y в Таблице PNT. Для высвечивания этой линии достаточно занести по этому адресу значение цвета из отрезка [0,255], которое можно найти по формуле: C = 32·G+4·R+B , где G, R, B — значения в диапазоне от 0 до 7, определяющие интенсивность зелёного ("Green"), красного ("Red") и синего ("Blue") цветов соответственно. Например, цвету с номером 187=&b10111011 соответствует следующее "содержимое" байта Таблицы PNT: Байт Таблицы PNT ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ 1 │ 0 │ 1 │ 1 │ 1 │ 0 │ 1 │ 1 │ └───┴───┴───┴───┴───┴───┴───┴───┘ └──────────┘ └──────────┘└──────┘ Интенсивность Интенсивность Интенсивность зелёного красного синего цвета цвета цвета При инициализации байты Таблицы PNT получают номер цвета фона (который изменяется в пределах от 0 до 255). Приведём схематическое изображение PNT для режима ''SCREEN 8''. Базовый адрес PNT | 0–й байт |отвечает за точку с координатами (0,0)| | 1–й байт |отвечает за точку с координатами (1,0)| | … | … | | 255–й байт |отвечает за точку с координатами (255,0)| | 256–й байт |отвечает за точку с координатами (0,1)| | … | … | | 54270–й байт |отвечает за точку с координатами (256,210)| | 54271–й байт |отвечает за точку с координатами (256,211)| {{anchor:n1117}} ==== XI.1.7. Таблица палитр (для компьютеров MSX 2) ==== Независимо от режима ''SCREEN'' Таблица PT занимает в видеопамяти объём 32 байта. "Местоположение" этой Таблицы зависит от режима ''SCREEN''. | Режим | Адрес | Комментарий | |''SCREEN 0'' (40 символов) | &H0400 |Не используется в [[msx:msx_1]]| |''SCREEN 0'' (80 символов) | &H0800 | | |''SCREEN 1'' | &H2020 |Не используется в [[msx:msx_1]]| |''SCREEN 2'' | &H1B80 |Не используется в [[msx:msx_1]]| |''SCREEN 3'' | &H2020 |Не используется в [[msx:msx_1]]| |''SCREEN 4'' | &H1E80 | | |''SCREEN 5'' | &H7680 | | |''SCREEN 6'' | &H7680 |Используются палитры 0–3| |''SCREEN 7'' | &HFA80 | | |''SCREEN 8'' | &HFA80 |Не используется| Каждая из палитр закодирована в //двух// байтах. Адрес AD первого байта палитры N в Таблице PT вычисляется по формуле: AD=A0+2·N , где А0 — адрес начала Таблицы PT (например,в режиме ''SCREEN 1'' Таблица PT начинается по адресу &h2020). По адресу AD в Таблице PT находится байт, который мы назовём "красный–синий". Биты 4–6 этого байта определяют пропорцию //красного//, а биты 0–2 — пропорцию //синего// цвета. Байт Таблицы PT с адресом AD+1 определяет пропорцию зелёного цвета, закодированную в битах 0–2 : 7 6 5 4 3 2 1 0 ◀── Номера бит ┌───┬───┬───┬───┬───┬───┬───┬───┐ AD │ │ ∗ │ ∗ │ ∗ │ │ ∗ │ ∗ │ ∗ │◀──────┐ └───┴───┴───┴───┴───┴───┴───┴───┘ │ └─────▲─────┘ └─────▲─────┘ │ Два │ │ ◀── последовательных Красный цвет ("Red") Синий цвет ("Blue") │ байта ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ Таблицы PT AD+1 │ │ │ │ │ │ ∗ │ ∗ │ ∗ │◀──────┘ └───┴───┴───┴───┴───┴───┴───┴───┘ └─────▲─────┘ └── Зелёный цвет ("Green") {{anchor:e1117-01}} __//Пример 1//__. "Чтение" Таблицы палитр в режиме ''SCREEN 1''. Выполнив программу, Вы узнаете, каким образом оператор ''SCREEN'' инициализирует Таблицу PT. \\ {{.examples:1117-01.bas|}} \\ [[+tab|wmsxbpge>1117-01.bas]] 10 COLOR 1,15,7:SCREEN 1 20 ' ::::::::::::::: 30 FOR N=0 TO 15 40 AD=&H2020+2*N 50 RB=VPEEK(AD):G=VPEEK(AD+1)'Обратите внимание на мнемонику имен: 'RB и G! 60 PRINT N;TAB(4);HEX$(RB);HEX$(G) 70 NEXT Отметим, что оператор ''COLOR=(…)'' переопределяет байты Таблицы PT в соответствии с указанной палитрой. {{anchor:e1117-02}} //Пример 2//. Изменим Таблицу PT и вновь "прочитаем" её. \\ {{.examples:1117-02.bas|}} \\ [[+tab|wmsxbpge>1117-02.bas]] 10 COLOR 1,15,7:SCREEN 1 20 GOSUB 30:COLOR=(7,7,2,7):GOSUB 30:COLOR=(7,7,7,4):GOSUB 30:END 30 FOR N=0 TO 15 40 AD=&H2020+2*N 50 RB=VPEEK(AD):G=VPEEK(AD+1) 60 PRINT N;TAB(4);HEX$(RB);HEX$(G) 70 NEXT 80 A$=INPUT$(1):CLS:RETURN Как видите, байты, соответствующие палитре 7, изменяются; немедленно изменяется и цвет бордюра! {{anchor:color_restore}} Разумеется, палитры в Таблице PT могут быть изменены и операторами ''VPOKE''. Однако следует отметить, что изменение Таблицы PT операторами ''VPOKE'' само по себе не приводит к изменению цветов. Для считывания содержимого Таблицы PT и присвоения цвета новой палитре существует специальный оператор. Его синтаксис предельно прост: COLOR = RESTORE . {{anchor:e1117-03}} __//Пример 3//__. \\ {{.examples:1117-03.bas|}} \\ [[+tab|wmsxbpge>1117-03.bas]] 10 COLOR 1,15,7:SCREEN 1 20 GOSUB 30:VPOKE &H2020+14,&H77:VPOKE &H2020+15,2 25 COLOR=RESTORE:GOSUB 30:END 30 FOR N=0 TO 15 40 AD=&H2020+2*N 50 RB=VPEEK(AD):G=VPEEK(AD+1) 60 PRINT N;TAB(4);HEX$(RB);HEX$(G) 70 NEXT 80 A$=INPUT$(1):CLS:RETURN Для инициализации Таблицы PT используются: * оператор ''SCREEN'' ; * оператор ''COLOR=NEW'' ; * оператор ''COLOR'' (без параметров!) . {{anchor:n1118}} {{anchor:sprites}} ==== XI.1.8. Спрайты ==== \\ Вопрос в том, кто за это отвечает? —//Шалтай–Болтай// Видеопроцессор имеет //два// режима отображения спрайтов. Режим отображения спрайтов выбирается автоматически в соответствии с выбранным Вами режимом ''SCREEN''. Если в Вашей программе присутствует один из операторов: SCREEN 1, SCREEN 2, SCREEN 3, то Вы находитесь в //режиме спрайтов// 1. Если же в Вашей программе присутствует один из операторов: SCREEN 4, SCREEN 5, SCREEN 6, SCREEN 7, SCREEN 8, то Вы находитесь в //режиме спрайтов// 2. Вкратце напомним уже известные Вам результаты. В //режиме спрайтов// 1 на экран одновременно можно вывести 32 спрайта с номерами от 0 до 31. Спрайты с //меньшими// номерами имеют более высокий приоритет. На одной горизонтальной линии экрана размещается до //четырёх// спрайтов с высшим приоритетом, а в пересекающейся части спрайты с более низким приоритетом становятся невидимыми. Когда два спрайта //сталкиваются//, т.е. пересекаются заполненные части их образов (если сталкиваются два спрайта, шаблоны которых занулены, или спрайты сталкиваются занулёнными участками шаблонов,то столкновение не бнаруживается), тогда бит 5 регистра состояния с номером 0 устанавливается в 1. Кроме того, если на одной горизонтальной линии находятся //пять// или более спрайтов, то 6–й бит регистра состояния будет установлен в 1, а пять младших бит зафиксируют номер пятого спрайта. В //режиме спрайтов// 2 на экран одновременно можно вывести 32 спрайта, пронумерованных от 0 до 31. Спрайты с //меньшими// номерами имеют более высокий приоритет. На одной горизонтальной линии экрана изображается до //восьми// спрайтов с высшим приоритетом, а в перекрывающейся части спрайты с меньшим приоритетом не видны. Столкновение //двух// спрайтов обнаруживается по состоянию 5–го бита регистра состояния с номером 0 (он устанавливается в 1). Интересно отметить, что в этом случае координаты столкновения фиксируются в регистрах состояния с номерами от 3 до 5. Вдобавок, если на одной горизонтальной линии экрана появляются девять или более спрайтов, то 6–й бит регистра состояния с номером 0 будет установлен в 1,а 5 младших бит этого регистра зафиксируют номер девятого спрайта. В режимах ''SCREEN 1'' – ''SCREEN 3'' спрайты задаются при помощи двух Таблиц: * Таблицы //шаблонов// спрайтов (SGT); * Таблицы //атрибутов// спрайтов (SAT);\\ В режимах ''SCREEN 4'' – ''SCREEN 8'' дополнительно используется ещё и * Таблица //цветов// спрайтов (SCT). В этом разделе мы расскажем вам о каждой Таблице. \\ //Шаблон// (от нем. Schablone — образец, модель) — пластина с вырезами, очертания которых соответствуют контуру чертежа, изделия и т.п. —//Советский Энциклопедический Словарь// - Таблица SGT содержит образы спрайтов (которые ниже мы будем называть //шаблонами//), установленные оператором SPRITE$(N)= строковое выражение Эта Таблица инициализируется нулями оператором SCREEN, причём оператор ''SCREEN ,T'' приводит к исчезновению спрайтов с экрана, сохраняя при этом на экране остальную информацию, а операторы ''SCREEN M,T'' и ''SCREEN M'' инициализируют всю видеопамять. 2048 байт Таблицы SGT позволяют хранить информацию о 256 шаблонах спрайтов, если //вторым// параметром в операторе ''SCREEN'' является 0 или 1, и информацию о 64 шаблонах, если этот параметр равен 2 или 3. Адрес шаблона спрайта в Таблице SGT, созданного при помощи оператора ''SPRITE$(N)=…'', вычисляется по формуле: A0 +8·N или A0+32·N , где А0 — адрес начала Таблицы SGT. Напомним Вам, что начальный адрес Таблицы SGT для разных режимов ''SCREEN'' возвращает функция ''BASE()'': BASE(M*5+4) , где M — номер режима ''SCREEN''. Байты шаблона записаны в Таблице SGT в том же порядке, что и байты (символы!) значения строкового выражения, стоящего в правой части оператора ''SPRITE$(N)=…'' Теперь, надеемся, вам понятно, что действие, например, операторов: SCREEN 1:SPRITE$(0)=STRING(8,255) эквивалентно действию цикла: FOR I=0 TO 7:VPOKE &H3800+I,255:NEXT ───▲── └─ BASE(1*5+4) {{anchor:e1118-01}} __//Пример 1//__. \\ {{.examples:1118-01.bas|}} \\ [[+tab|wmsxbpge>1118-01.bas]] 10 SCREEN 1,0 20 A$="Microsoft" 30 FORI=1TOLEN(A$):B$=MID$(A$,I,1) 50 VPOKEBASE(1*5+4)+8*2+(I-1),ASC(B$) 60 NEXT 70 PRINT SPRITE$(2) 8 байтов 8 байтов 8 байтов ┌────────────────┬────────────────┬────────────────┐ │ "Место" в SGT │ "Место" в SGT │ "Место в SGT │ │для 0–го спрайта│для 1–го спрайта│для 2–го спрайта│ └────────────────┴────────────────┴▲───────────────┘ │ BASE(1*5+4)+8*2 \\ Атрибут (от лат. Attribuo — придаю, наделяю), необходимое, существенное, неотъемлемое свойство объекта. —//Советский Энциклопедический Словарь// - В 128 байтах Таблицы атрибутов спрайтов (Таблицы SAT) кодируется информация о //способе// вывода образов (шаблонов) спрайтов на экран. Поскольку одновременно на экране может отображаться не более 32 спрайтов, то атрибуты одного спрайта кодируются в 128/32 = 4 байтах. Вероятно, Вас заинтересует их содержимое? Поспешим удовлетворить Ваше любопытство: Байты Таблицы SAT ┌──────────────┬──────────────┬──────────────┬───────────────┐ │ Первый байт │ Второй байт │ Третий байт │ Четвёртый байт│ └──────▲───────┴───────▲──────┴───────▲──────┴────────▲──────┘ │ │ │ │ Координата Y Координата X Номер шаблона Номер палитры (для режимов SCREEN 1 ÷ SCREEN 3) (0÷255) (0÷255) в SGT (0÷255) Цвет изображения (для режимов SCREEN 4 ÷ SCREEN 8) Отметим, что если величина Y–координаты спрайта равна 216, то все спрайты с меньшим приоритетом не будут отображаться. Например, если Y–координата спрайта с номером 10 равна 216,то спрайты с номерами от 10 до 31 не будут отображаться. Если размер спрайта — 16×16, то, как известно, одному спрайту соответствуют //четыре// номера шаблонов спрайта. В этом случае можно задать любой из четырёх номеров шаблонов спрайта! Таким образом, если мы обозначим A0 — начальный адрес Таблицы SAT, то оператор PUT SPRITE SN,(X,Y),C,NP эквивалентен следующим операторам: AD=A0+4*SN:VPOKE AD,Y:VPOKE AD+1,X:VPOKE AD+2,NP:VPOKE AD+3,C ▲ ▲ ▲ ▲ ▲ └─!!! └─!!! └─!!! └─!!! └─!!! {{anchor:e1118-02}} __//Пример 2//__. \\ {{.examples:1118-02.bas|}} \\ [[+tab|wmsxbpge>1118-02.bas]] 10 COLOR 1,15,8:SCREEN 1,1:SPRITE$(20)="СПРАЙТ!" 20 PUT SPRITE 2,(165,38),7,20 30 ? "X=";VPEEK(6921):? "Y="VPEEK(6920):?"Цвет номер";VPEEK(6923):?"Шаблон";VPEEK(6922) 40 FOR T=0 TO 8:? CHR$(VPEEK(14336+VPEEK(6922)*8+T));: NEXT Рассмотрим подробнее содержимое //четвертого// байта Таблицы SAT для какого–нибудь выбранного спрайта. ┌───┬───┬───┬───┬───┬───┬───┬───┐ Старший бит│ │ 0 │ 0 │ 0 │ Цвет спрайта │ Младший бит └─▲─┴───┴───┴───┴───┴───┴───┴───┘ └── Синхронизирующий бит (его имя EC) Его //младшие// четыре бита определяют текущий //цвет// спрайта (для высвечиваемых точек шаблона). Невысвечиваемые точки шаблона "окрашены" в прозрачный цвет. Старший бит этого байта называется //синхронизирующим//. Если его значение равно 1, то положение спрайта смещается //влево// на 32 точки. {{anchor:e1118-03}} __//Пример 3//__. "Работа" синхронизирующего бита. \\ {{.examples:1118-03.bas|}} \\ [[+tab|wmsxbpge>1118-03.bas]] 20 COLOR 1,15,15 30 SCREEN 1,3:WIDTH 30 40 SPRITE$(0)=STRING$(32,255) 50 PUT SPRITE 0,(80,80),8,0 60 VPOKE 6915,&B10001000 61 ' ▲ 63 ' │──────────── 1 - координаты спрайта (X-32,Y) 65 ' └──────────── 0 - координаты спрайта (X,Y) 70 LOCATE 2,8,0:PRINT"Нажмите клавишу" 80 A$=INPUT$(1) 90 VPOKE 6915,&B00001000 100 END Разумеется, при программировании на языке [[msx:basic:]] лучше использовать оператор ''PUT SPRITE'', а не последовательность операторов ''VPOKE''. Однако последовательность операторов ''VPOKE'' гораздо проще моделировать на //машинном языке//, чем оператор ''PUT SPRITE'' Более того, знание структуры Таблицы SAT позволяет "прочитать" атрибуты спрайта непосредственно из //памяти// ! {{anchor:e1118-04}} __//Пример 4//__. Превращение белого спрайта в чёрный и наоборот. \\ {{.examples:1118-04.bas|}} \\ [[+tab|wmsxbpge>1118-04.bas]] 10 COLOR 1,4,8:SCREEN 1,1 20 SPRITE$(0)=STRING$(8,255) 30 PUT SPRITE 0,(115,80),15,0 40 IF INKEY$="" THEN 40 50 GOSUB 100:GOTO 40 100 VPOKE &H1B03,VPEEK(&H1B03) XOR 14 'BASE(1*5+3) ──▶ &H1B00 110 RETURN ──────────▲───────── │ &b00001111 XOR &b00001110 = &b00000001 ──▶ цвет 1 Оператор ''SCREEN'' инициализирует четыре байта Таблицы SAT, кодирующих атрибуты одного спрайта, следующим образом: ┌──────────────┬──────────────┬──────────────┬───────────────┐ │ Первый байт │ Второй байт │ Третий байт │ Четвёртый байт│ └──────▲───────┴───────▲──────┴───────▲──────┴────────▲──────┘ │ │ │ │ Координата Y Координата X Номер шаблона Текущий цвет в Таблице SGT изображения //Координата Y// отображения спрайта по умолчанию приведена в следующей табличке (из неё видно, что при таких Y неважно, каково Х): ^ Серия компьютера| [[msx:msx_1]] | [[msx:msx_2]] | ^ //Режим экрана// ^ Y ^ Y ^ | ''SCREEN 1'' | 209 | 209 | | ''SCREEN 2'' | 209 | 209 | | ''SCREEN 3'' | 209 | 209 | | ''SCREEN 4'' | | 217 | | ''SCREEN 5'' | | 217 | | ''SCREEN 6'' | | 217 | | ''SCREEN 7'' | | 217 | | ''SCREEN 8'' | | 217 | С учётом значения координаты Y спрайт является //невидимым//. Координата Y обладает интересной особенностью. Если Y–координата спрайта с номером N равна 209 (в режимах ''SCREEN 1'', ''SCREEN 2'', ''SCREEN 3'') или 217 (в режимах ''SCREEN 4'', ''SCREEN 5'', ''SCREEN 6'', ''SCREEN 7'', ''SCREEN 8''), то этот спрайт не отображается на экране. Самое интересное заключается в том, что не отображаются и все остальные спрайты с номерами, большими чем N. {{anchor:e1118-05}} __//Пример 5//__. \\ {{.examples:1118-05.bas|}} \\ [[+tab|wmsxbpge>1118-05.bas]] 10 DIM X(3):SCREEN 2,0 20 A$="ЧЧЧЧЧЧЧЧ":Y=0 30 FOR I=1 TO 3:SPRITE$(I)=A$:X(I)=10*I:NEXT I 40 PUT SPRITE 1,(X(1),Y),1,1 50 PUT SPRITE 3,(X(3),Y),15,3 60 PUT SPRITE 2,(X(2),Y),8,2 70 Y=Y+1:IF Y>208 THEN BEEP:A$=INPUT$(1):END 'Исчезли два спрайта! 80 GOTO 60 //"Экранный" номер// спрайта по умолчанию равен номеру шаблона спрайта. //Цветом// спрайта по умолчанию является текущий цвет изображения. - Таблица SCT используется только в режимах ''SCREEN 4'' – ''SCREEN 8''. Базовый адрес Таблицы цветов спрайтов (SCT) будет всегда автоматически вычисляться вычитанием числа 512 из базового адреса Таблицы атрибутов спрайтов (SAT). С помощью SCT можно моделировать оператор ''COLOR SPRITE$()'', который, как Вы, конечно, помните, позволяет определить цвет для высвечиваемых точек шаблона спрайта для //каждой// спрайтовой линии (цвет невысвечиваемых точек шаблона спрайта всегда //прозрачный//). Так как для каждого из 32 спрайтов необходимо хранить информацию максимум о 16 спрайтовых линиях различного цвета, эта Таблица занимает 32·16 = 512 байтов VRAM . Адрес байта, начиная с которого располагается информация о //цвете// спрайта в Таблице SCT, вычисляется по формуле: AD = A0 + 16·SN , где: * A0 — адрес начала Таблицы SCT; * SN — номер шаблона спрайта {{anchor:e1118-06}} __//Пример 6//__. Вторая спрайтовая линия изображения девятого спрайта раскрашена восьмым цветом. \\ {{.examples:1118-06.bas|}} \\ [[+tab|wmsxbpge>1118-06.bas]] 10 COLOR 15,1,8:SCREEN 4,0 20 SPRITE$(3)="пример":PUT SPRITE 9,(40,80),15,3 40 VPOKE &H1C00+16*9+2,8 50 GOTO 50 Заметим, что для информации о цвете шаблона спрайта размером 8×8 точек отводятся //только// 16 младших полубайтов 16 байтов SCT, отводимых для одного шаблона. Опишем содержимое оставшихся 16 //старших// полубайтов… Оказывается с их помощью можно разрешить или запретить приоритеты спрайтов, обработать определённым образом столкновения и задать или отменить так называемое "опережение" для спрайта. Изобразим схематически Таблицу SCT: ┌────┬────┬────┬────┬───┬───┬───┬───┐ │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ Номера бит ├────┼────┼────┼────┼───┴───┴───┴───┤ 0–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 1 для спрайта 0 ├────┼────┼────┼────┼───────────────┤ 1–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 2 для спрайта 0 ├────┴────┴────┴────┼───────────────┤ … ┆ … ┆ … ┆ … ├────┬────┬────┬────┼───────────────┤ 15–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 16 для спрайта 0 ├────┴────┴────┴────┼───────────────┤ … ┆ … ┆ … ┆ … ├────┬────┬────┬────┼───────────────┤ 496–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 1 для спрайта 31 ├────┼────┼────┼────┼───────────────┤ 497–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 2 для спрайта 31 ├────┴────┴────┴────┼───────────────┤ … │ … ┆ … ┆ … ├────┬────┬────┬────┼───────────────┤ 511–й байт│ │ │ │ 0 │ Код цвета │ Спр.линия 16 для спрайта 31 └──▲─┴──▲─┴──▲─┴────┴───────────────┘ │ │ └─ Бит IC (определитель столкновений):1 — нет, 0 — да; │ └────── Бит CC (разрешение приоритета) :0 — нет, 1 — да; └─────────── Бит EC ("опережение") :1 — да, 0 — нет. В режиме спрайтов 2, если СС–бит Таблицы SCT установлен в 1, порядок приоритетности спрайтов для данной спрайтовой линии //отменяется//. Спрайтовая линия, для которой бит СС установлен в 1 , будет отображаться только на горизонтальных линиях,где существуют спрайты с низшими номерами. Отметим, что и в этом случае, если на одной линии экрана более 8 спрайтов, то //девятый// спрайт и все последующие не будут изображаться на экране дисплея. Более того, не фиксируется столкновение спрайта, для которого с SCT бит СС установлен в 1, с другим спрайтом (даже если у этого спрайта в SCT бит СС установлен в 0). В этом случае для пересекающихся спрайтов над их цветовыми кодами производится логическая операция OR. Говорят, что в режиме ''SCREEN 6'' цвет фона и цвета спрайтов подвергаются //аппаратному тилингу//. Эти цвета кодируются четырьмя битами: два //старших// бита определяют код цвета нечётных точек, а два //младших// бита определяют код цвета чётных точек по X–координате (от 0 до 511). В режиме SCREEN 6 размер одной точки спрайта в 2 раза больше, чем у графической точки (пикселя), однако за счёт наличия аппаратного тилинга, одна точка спрайта может обладать двумя цветами одновременно (чётные и нечётные точки фонового цвета могут быть определены таким же образом). ┌─────────────────── Чётные точки (0,2,…,510) │ ┌────────────── Нечётные точки (1,3,…,511) ┌──▼─┬──▼─┐ │ │ │ Две графические точки └────┴────┘ ┌────┬────┐ │ │ │ Одна точка спрайта └──▲─┴─▲──┘ │ │ ┌───┬───┐ ┌───┬───┐ │ █ │ █ │ │ █ │ █ │ Биты, определяющие цвета спрайта └───┴───┘ └───┴───┘ Приведём табличку начальных адресов Таблиц SCT для различных режимов: ^ Режим ^ Адрес ^ | ''SCREEN 4'' | &H1C00 | | ''SCREEN 5'' | &H7400 | | ''SCREEN 6'' | &H7400 | | ''SCREEN 7'' | &HF800 | | ''SCREEN 8'' | &HF800 | Отметим, что 16 байтов Таблицы SCT, отвечающих за цвет спрайта, первоначально инициализируются текущим цветом изображения или цветом, заданным в операторе ''PUT SPRITE''. "Содержимое" этих байтов может быть переопределено непосредственно операторами ''VPOKE'' или оператором ''COLOR SPRITE()'' (''COLOR SPRITE$()''). В режиме ''SCREEN 8'' цвета спрайта фиксированы и не зависят от регистра палитры. Цвета спрайта в режиме ''SCREEN 8'' показаны на следующей таблице. ^ Код цвета ^^^^ Зелёный ^^^ Красный ^^^ Синий ^^^ ^С3^С2^С1^С0^G2^G1^G0^R2^R1^R0^B2^B1^B0^ | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | | | | | | | | | | | | | | | | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | | | | | | | | | | | | | | | | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | | | | | | | | | | | | | | | | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | {{anchor:n1119}} ==== XI.1.9. Слоты видеопамяти ==== Вся видеопамять на компьютерах серии [[msx:msx_2]] разбита на два больших участка объёмом по 64 Кбайта каждый. Эти участки будем называть //слотами// видеопамяти (по аналогии с участками RAM и ROM объёмом по 64 Кбайта, называемыми //слотами// памяти). На компьютерах серии [[msx:msx_1]] имеется только один слот VRAM объёмом в 16 Кбайт. Для того чтобы переключиться с работы со слотом 0 на работу со слотом 1, достаточно выполнить оператор: * ''SET PAGE 2'' или ''SET PAGE 3'' в режимах ''SCREEN 5'' и ''SCREEN 6''; * ''SET PAGE 1'' в режимах ''SCREEN 7'' и ''SCREEN 8''. После этого оператором ''VPOKE'' и функцией ''VPEEK'' можно работать с логическими адресами видеопамяти. В помощь вам предлагаем следующие таблички: ^ Физические адреса ^ Логические адреса ^ Номера слотов ^Способ включения слота | | от &H00000 | от &H0000 | Слот 0 | SET PAGE 0 | Для режимов SCREEN 5 и SCREEN 6 | | до &H07FFF | до &H7FFF |:::|:::|:::| | от &H08000 | от &H8000 |:::| SET PAGE 1 |:::| | до &H0FFFF | до &HFFFF |:::|:::|:::| | от &H10000 | от &H0000 | Слот 1 | SET PAGE 2 |:::| | до &H17FFF | до &H7FFF |:::|:::|:::| | от &H18000 | от &H8000 |:::| SET PAGE 3 |:::| | до &H1FFFF | до &HFFFF |:::|:::|:::| | от &H00000 | от &H0000 | Слот 0 | SET PAGE 0 | Для режимов SCREEN 7 и SCREEN 8 | | до &H0FFFF | до &HFFFF |:::|:::|:::| | от &H10000 | от &H0000 | Слот 1 | SET PAGE 1 |:::| | до &H1FFFF | до &HFFFF |:::|:::|:::| {{anchor:n11110}} ==== XI.1.10. Порты, отвечающие за работу с видеопамятью ==== Другой способ доступа к видеопамяти заключается в работе с //портами// ввода–вывода. Этот способ очень часто используется при написании программ в машинных кодах. Напомним, что перед использованием команды (оператора) ''OUT'' на компьютерах серии [[msx:msx_2]] необходимо выполнить команду ''[[msx:network_basic#CALL NETEND]]''. - Для //записи// числа в ячейку видеопамяти примените серию команд: * OUT &H99, Младший байт номера ячейки * OUT &H99, Старший байт номера ячейки OR &H40 * OUT &H98, Число {{anchor:e11110-01}} __//Пример//__. \\ {{.examples:11110-01.bas|}} \\ [[+tab|wmsxbpge>11110-01.bas]] 10 SCREEN 0:CLS:KEYOFF 20 OUT &H99,0:OUT &H99,0 OR &H40 30 FOR I=1 TO 20 40 READ R$:R=ASC(R$):OUT &H98,R 50 NEXT I:PRINT 'Попробуйте убрать в этой строке оператор PRINT 60 DATA Г,р,у,п,п,о,в,а,я," ",п,е,р,е,с,ы,л,к,а,! - Для //чтения// числа из ячейки видеопамяти, примените следующие команды: * OUT &H99, Младший байт номера ячейки * OUT &H99, Старший байт номера ячейки * A=INP(&H98) Важно отметить следующее. Изменение содержимого видеопамяти или видеопроцессора приводит к немедленной корректировке содержимого экрана. Однако отсюда вовсе не следует истинность обратного утверждения. Изменение "содержимого" экрана не всегда приводит к изменению VRAM. Если Вы не будете в программе "работать" с портами ввода–вывода,то можно утверждать, что VRAM и VDP "управляют" "содержимым" экрана.На самом же деле состояние экрана изменяют //порты// ввода–вывода с адресами &H98, &H99, &H9A и &H9B. На эти порты можно "воздействовать" оператором ''VPOKE''. В этом случае сигнал из VRAM сразу же поступает в порт, а тот, в свою очередь, изменяет "рисунок" на экране. ┌───────────┐ │ Экран │ └───▲─▲─▲───┘ │ │ │ ┌─────────────────────────────┐ ◀── │ Порты ввода–вывода │ ◀── Оператор OUT └────▲─▲─▲────────────▲─▲─▲───┘ ◀── │ │ │ │ │ │ ┌──────────────┐ ┌───────────┐ ◀── │Видеопроцессор│─▶│Видеопамять│ ◀── Оператор VPOKE └──────────────┘ └───────────┘ ◀── Если же воздействовать непосредственно на порт оператором ''OUT'', минуя видеопамять, то могут возникнуть следующие ситуации: - если адрес VRAM принадлежит отрезку [0,&H3FFE], то после записи оператором ''OUT'' в ячейку с этим адресом её содержимое можно прочесть как функцией ''INP'', так и функцией ''VPEEK''; - если адрес VRAM принадлежит отрезку [&H3FFF,&HFFFF], то после записи оператором ''OUT'' в ячейку с этим адресом её содержимое можно прочесть только функцией ''INP''. {{anchor:e11110-02}} __//Пример//__. Сравните результаты работы этой программы на компьютерах серий [[msx:msx_1]] и [[msx:msx_2]] ! \\ {{.examples:11110-02.bas|}} \\ [[+tab|wmsxbpge>11110-02.bas]] 10 CALL NETEND 20 INPUT"Младший байт";N1:INPUT"Старший байт";N2:INPUT"Значение";D 30 PRINT"Старое значение:"; 40 OUT&H99,N1:OUT&H99,N2:PRINT INP(&H98) 50 OUT&H99,N1:OUT&H99,N2 OR&H40:OUT&H98,D 60 PRINT"Новое значение:"; 70 OUT&H99,N1:OUT&H99,N2:PRINT INP(&H98) 80 CALL NETINI:'Отмена действия команды CALL NETEND {{anchor:n112}} ===== XI.2. Работа с видеопроцессором ===== \\ Четыре величайших изобретения в истории человечества: - колесо; - электрическая лампочка; - микрокомпьютер; - руководства по микрокомпьютерам вместе с их авторами. —//М.Уэйт, С.Прата, Д.Мартин// Работа с псевдопеременными ''[[#base|BASE]]'' и ''[[#vdp|VDP]]'' — весьма эффективное средство управления видеопамятью. Однако при использовании этих средств нужно быть крайне осторожным, ибо малейшая ошибка в программировании может сделать экран "неуправляемым", что вынудит Вас нажать кнопку RESET! Мы познакомим Вас с несколькими сравнительно "безопасными" примерами. {{anchor:vdp}} Более детальная информация о способах работы с видеопамятью содержится в книгах [[bibliography#b65|[65]]], [[bibliography#b89|[89]]] (если Вы, конечно, сможете их раздобыть!). Работой видеопамяти управляет специальный процессор,который называется //видеопроцессором//. Видеопроцессор "работает" с двумя группами восьмибитных //регистров//: 47 регистров VDP и 16 регистров статуса. //Регистр// — электронное устройство для временного хранения информации во время её обработки. Регистры называют часто сверхоперативной памятью, т.к. для регистров используются специальные электронные схемы, позволяющие значительно быстрее записывать информацию в регистры и читать информацию из регистров. Регистры VDP можно разделить на несколько категорий: * по назначению: - регистры //установки режима// (0, 1, 8, 9); - регистры //базовых адресов// (2–6, 10, 11); - регистры //цветов// (7, 12, 13, 20–22); - регистры //управления экраном// (18, 19, 23); - регистры //доступа// (14–17); - регистры //команд// (32–46); * по способу доступа: - разрешены чтение и запись на компьютерах и серии [[msx:msx_1]], и серии [[msx:msx_2]] (регистры 0–7); - разрешены чтение и запись на компьютерах [[msx:msx_2]] и только запись на компьютерах [[msx:msx_1]] (регистры 8–23); - разрешена только //запись// (регистры 32–46). Для //чтения// "содержимого" регистров VDP предназначена одноименная псевдопеременная, используемая в правой части оператора присваивания. Её синтаксис: VDP(N) , где: * ''VDP'' ("ViDeo Processor") — служебное слово; * N — арифметическое выражение, целая часть значения которого указывает на номер регистра VDP, причём: * α) если используется регистр с номером из диапазона [0,7], то значение параметра N должно быть равно номеру регистра; * β) если используется регистр с номером из диапазона [8,23] (для компьютера [[msx:msx_2]]), то N=RG+1, где RG — номер регистра. Теперь мы расскажем вам о способах //записи// в регистры VDP: - запись с использованием псевдопеременной VDP. Этот способ является самым простым: оператор VDP(N) = M , где: * ''VDP'' ("ViDeo Processor") — служебное слово; * N — арифметическое выражение, целая часть значения которого указывает на номер регистра VDP, причём: * α) если используется регистр с номером из диапазона [0,7], то значение параметра N должно быть равно номеру регистра; * β) если используется регистр с номером из диапазона [8,23] либо из диапазона [32,46] (для компьютера [[msx:msx_2]]), то N=RG+1, где RG — номер регистра; * M — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,255], позволяет поместить значение выражения M в регистр VDP; - запись через //порты// ввода–вывода (для всех регистров). Этот способ заключается в использовании порта с номером &H99, связывающего видеопроцессор с центральным процессором MSX–компьютера (Z80). Чтобы записать число A в регистр VDP с номером N, примените следующие операторы: OUT &H99,A:OUT &H99,RG OR &H80 . Они последовательно выводят данные и номер регистра в порт 99h. ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Первый байт| данные |||||||| ^Второй байт| 1 | 0 | номер регистра |||||| //Замечание//. Будьте особенно внимательными при обращении к видеопроцессору из подпрограммы обработки прерываний. - //косвенная// запись в регистры VDP. Про неё будет рассказано в [[#XI.2.6. Доступ к видеопамяти|разделе XI.2.6.]]. Напомним, если Вы работаете с компьютером серии [[msx:msx_2]],то перед набором программы, использующей порты ввода–вывода, нужно выполнить команду CALL NETEND . {{anchor:n1121}} ==== XI.2.1. Регистры установки режима ==== \\ Нехватка информации восполняется избытком интуиции. —//М.Мишин// Перейдём теперь к описанию "содержимого" некоторых регистров VDP. Вначале напомним вам принятую нумерацию бит в байте: | 7–й \\ бит | 6–й \\ бит | 5–й \\ бит | 4–й \\ бит | 3–й \\ бит | 2–й \\ бит | 1–й \\ бит | 0–й \\ бит | __//Регистр 0//__. ^ Номер бита ^ Значение бита ^ Комментарий ^^ | 7 | 0 | Не используется || | 6 | 1 | Устанавливает цветовую шину в режиме ввода и вводит данные в видеопамять || | 5 | 1 | Бит "IE2" | Запретить прерывания от светового пера | |:::| 0 |:::| Разрешить прерывания от светового пера | | 4 | 1 | Бит "IE1" | Запретить прерывание от горизонтального сканирования линии по "IE1" и отключить сигналы с клавиатуры | |:::| 0 |:::| Разрешить прерывания по "IE1" | | 3 | | Бит "M5" установки графических режимов || | 2 | | Бит "M4" установки графических режимов || | 1 | | Бит "M3" установки графических режимов || | 0 | | Внешний видеосигнал (бит "IV") || {{anchor:e1121-00}} __//Пример//__. \\ {{.examples:1121-00.bas|}} \\ [[+tab|wmsxbpge>1121-00.bas]] 10 OUT &H99,VDP(0) OR 16:OUT &H99,0 OR &H80 'Отключение клавиатуры! __//Регистр 1//__. ^ Номер бита ^ Значение бита ^ Комментарий ^^ | 7 | 0 |Не используется|| | 6 | 0 |Применение аналогично нажатию кнопки питания дисплея|изображение отключено| |:::| 1 |:::|изображение включено| | 5 | 0 |Бит "IE0"|Запретить прерывание от горизонтального сканирования линии по "IE0" и отключить сигналы с клавиатуры| |:::| 1 |:::|Разрешить прерывания по "IE0"| | 4 | |Бит "M1" установки графических режимов|| | 3 | |Бит "M2" установки графических режимов|| | 2 | 0 |Не используется|| | 1 | 0 |Размер спрайтов 8×8|Использование этих бит позволяет моделировать оператор ''SCREEN,n''| |:::| 1 |Размер спрайтов 16×16|:::| | 0 | 0 |Нормальный размер спрайтов|:::| |:::| 1 |"Увеличение" размера спрайтов|:::| Назначение 6–го бита регистра 1 иллюстрируется примерами 1 и 2: {{anchor:e1121-01}} __//Пример 1//__. - \\ {{.examples:1121-011.bas|}} \\ [[+tab|wmsxbpge>1121-011.bas]] 10 SCREEN 2 15 ::::::::::::::::: 20 CIRCLE(125,95),90 30 PAINT STEP(0,0) 35 ::::::::::::::::: 40 GOTO 40 - \\ {{.examples:1021-012.bas|}} \\ [[+tab|wmsxbpge>1021-012.bas]] ┌─ OFF 10 SCREEN 2 ▼ 15 VDP(1)=&B10100000 20 CIRCLE(125,95),90 30 PAINT STEP(0,0) 35 VDP(1)=&B11100000 40 GOTO 40 ▲ └─ ON - \\ {{.examples:1021-013.bas|}} \\ [[+tab|wmsxbpge>1021-013.bas]] 10 SCREEN 2 15 OUT &H99,&B10100000:OUT &H99,1 OR &H80 20 CIRCLE(125,95),90:PAINT STEP (0,0) 35 VDP(1)=&B11100000 40 GOTO 40 Перед записью в регистр лучше всего сначала прочитать его текущее содержимое, а лишь затем с помощью логических операций ''AND'', ''OR'' и ''XOR'' установить или "сбросить" нужные биты. {{anchor:e1121-02}} __//Пример 2//__. Включение и выключение экрана дисплея \\ {{.examples:1121-02.bas|}} \\ [[+tab|wmsxbpge>1121-02.bas]] VDP(1)=VDP(1) XOR 64 . Эта команда включает экран, если он был выключен, и наоборот. А теперь разберёмся с //нулевым// битом регистра 1… {{anchor:e1121-03}} //Пример 3//. Изменение размера спрайта без очистки шаблонов. \\ {{.examples:1121-031.bas|}} \\ [[+tab|wmsxbpge>1121-031.bas]] 10 SCREEN 2,1 20 SPRITE$(0)="0123456789ABCDEF" 30 PUT SPRITE 0,(50,50),,0 40 FOR I=1 TO 1000:NEXT 50 VDP(1)=VDP(1) XOR 1 'Эта команда переключает масштаб спрайтов без очистки шаблонов 60 GOTO 60 А теперь замените строку 50 на строку \\ {{.examples:1121-032.bas|}} \\ [[+tab|wmsxbpge>1121-032.bas]] 50 OUT &H99,VDP(1) XOR 1:OUT &H99,1 OR &H80 и выполните программу. Биты "M1","M2","M3","M4","M5" "отвечают" за выбор режима экрана: ^ Биты и их значение ^^^^^ Режим видеопроцессора ^ ^ M1 ^ M2 ^ M3 ^ M4 ^ M5 ^:::^ | 1 | 0 | 0 | 0 | 0 |''SCREEN 0'' (40 символов)| | 1 | 0 | 0 | 1 | 0 |''SCREEN 0'' (80 символов)| | 0 | 0 | 0 | 0 | 0 |''SCREEN 1''| | 0 | 0 | 1 | 0 | 0 |''SCREEN 2''| | 0 | 1 | 0 | 0 | 0 |''SCREEN 3''| | 0 | 0 | 0 | 1 | 0 |''SCREEN 4''| | 0 | 0 | 1 | 1 | 0 |''SCREEN 5''| | 0 | 0 | 0 | 1 | 1 |''SCREEN 6''| | 0 | 0 | 1 | 0 | 1 |''SCREEN 7''| | 0 | 0 | 1 | 1 | 1 |''SCREEN 8''| Изменять содержимое бит "M1","M2","M3","M4" и "M5" не рекомендуется! Эти биты используются видеопроцессором при инициализации режима ''SCREEN'', однако следует помнить, что для полной инициализации этого надостаточно! Легко, например, проверить, что команда ''VDP(0)=4'' не устанавливает полностью 80–символьный режим ''SCREEN 0''. Зато чтение этих бит поможет вам "вспомнить", в каком режиме ''SCREEN'' Вы работаете в данный момент. Для полной инициализации экрана нужно выполнить следующие действия: - установить биты M1, M2, M3, M4, M5; - установить начальные адреса Таблиц VRAM в регистрах базовых адресов; - заполнить Таблицы видеопамяти необходимыми данными; - занести в ячейку памяти с адресом &HFCAF номер режима ''SCREEN''. __//Регистр 8//__. ^ Номер бита ^ Значение бита ^ Комментарий ^ | 7 | 1 |Цветовая шина устанавливается на режим //ввода// и разрешается использование манипулятора "мышь"| |:::| 0 |Цветовая шина устанавливается на режим //вывода// и запрещается использование манипулятора "мышь"| | 6 | 1 |Разрешается обработка светового пера| |:::| 0 |Запрещается обработка светового пера| | 5 |Бит с именем TP. Устанавливается цвет кода 0 в цветовой палитре|| |:::| 1 |изображение 0–го цвета имеет цвет 0 из Таблицы PT| |:::| 0 |изображение 0–го цвета имеет цвет бордюра| | 4 | Моделирует оператор ''SET VIDEO,,n''|| |:::| 1 |происходит вывод данных на видеомагнитофон| |:::| 0 |происходит ввод данных от внешнего TV–источника или от компьютера;| | 3 |Содержимое бита изменять не рекомендуется!|| |:::| 1 |Размер видеопамяти ≥64 Кбайт (для компьютеров [[msx:msx_2]])| |:::| 0 |Размер видеопамяти ≤64 Кбайт (для компьютеров [[msx:msx_1]])| | 2 | 0 |Не используется| | 1 | 1 |Запрещается отображение спрайтов| |:::| 0 |Разрешается отображение спрайтов| | 0 | 1 |Установить черно–белый режим с 32 градациями тона| |:::| 0 |Установить цветовой режим| По умолчанию 5–й бит регистра с номером 8 равен 0. В этом случае объект нулевого цвета будет окрашиваться цветом бордюра (т.е. будет //прозрачным//). Участки спрайтов с нулевым цветом на экране не отображаются. Но если спрайты пересекаются "невидимыми" частями, то столкновение спрайтов не будет установлено. Для получения на экране одновременно 16 цветов необходимо, чтобы бордюр был окрашен в //нулевой// цвет. Если 5–й бит 8–го регистра равен 1, то объект нулевого цвета не будет окрашиваться цветом бордюра (если, конечно, бордюр сам не окрашен в нулевой цвет). Код цвета 0 будет кодом, который определяется в регистре палитры (только в режиме ''SCREEN 8'' R=0, G=0, B=0). На экране одновременно могут отображаться 16 цветов, причём в области, отличной от бордюра; более того, отображаются спрайты всех цветов. Участки спрайтов с нулевым цветом на экране по–прежнему не отображаются. Но если спрайты пересекаются "невидимыми" частями, то столкновение спрайтов //будет установлено//. {{anchor:e1121-04}} __//Пример 4//__. \\ {{.examples:1121-04.bas|}} \\ [[+tab|wmsxbpge>1121-04.bas]] 10 COLOR =(0,2,4,7) 'Изменим палитру нулевого цвета 20 COLOR 1,15,8:SCREEN 2 30 VDP(8+1)=8 'Инициализация 8-го регистра 40 CIRCLE (90,90),45,0 'Изображение имеет цвет бордюра 50 A$=INPUT$(1) 60 VDP(8+1)=&B00101000 'Бордюр окрашен в 8-й цвет, 70 GOTO 70 'а изображение - в нулевой __//Регистр 9//__. ^ Номер \\ бита ^ Значение \\ бита ^ Комментарий ^^ | 7 |Бит "LN" Отвечает за //общую// высоту экрана (за доступную высоту отвечает ячейка &hF3B1 в рабочей области RAM)||| |:::| 1 |На экране 212 графических или 26.5 текстовых строк|| |:::| 0 |На экране 192 графических или 24 текстовых строк|| | 6 | 0 |Не используется|| | 5 | 1 |Поступает сигнал только от внешнего TV–источника|Эти биты моделируют оператор ''SET VIDEO n''| |:::| 0 |Разрешено изображение от компьютера|:::| | 4 | 1 |Происходит смешивание изображения от компьютера и от TV–источника|:::| |:::| 0 |Смешивания сигналов не происходит|:::| | 3 | 1 |Происходит "дрожание" экрана|Эти биты моделируют оператор ''SCREEN ,,,,,n'' (5 запятых!)| |:::| 0 |"Дрожания" не происходит|:::| | 2 | 1 |Происходит поочерёдный показ страниц на страницах с нечётными номерами в режимах ''SCREEN 5'' – ''SCREEN 8''|:::| |:::| 0 |Отображается одна и та же страница на чётное/нечётное поле|:::| | 1 |Выбор системы телевидения||| |:::| 1 |PAL (313 линий, американский стандарт)|| |:::| 0 |NTSC (262 линии, японский стандарт) — только для RGB–выхода|| | 0 | 1 |Установка на режим //ввода//|| |:::| 0 |Установка на режим //вывода//|| {{anchor:e1121-05}} //Пример 5//. Установим высоту экрана равной 26.5 строкам. \\ {{.examples:1121-05.bas|}} \\ [[+tab|wmsxbpge>1121-05.bas]] 10 SCREEN 0:WIDTH 80 20 VDP(9+1)=VDP(9+1) OR 128 30 POKE &hF3B1,27 40 FOR T=BASE(0)+(1920-80) TO BASE(0)+(1920-80)+240 50 VPOKE T,32:NEXT {{anchor:n1122}} ==== XI.2.2. Регистры базовых адресов ==== \\ Мы находимся в положении, несколько аналогичном положению человека, держащего в руках связку ключей и пытающегося открыть одну за другой несколько дверей. Рано или поздно ему всегда удаётся подобрать ключ к очередной двери, но сомнения относительно взаимнооднозначного соответствия между ключами и дверями у него остаются. —//Ю.Вигнер// Адрес байта видеопамяти кодируется 17 двоичными цифрами, которые мы будем обозначать Ai, где i=0,1,2,…,16, причём через A16 будем обозначать //старший// бит, через A0 — //младший// бит. ^Старший бит| A16 | A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 ^Младший бит| В регистрах базовых адресов хранятся старшие биты начальных адресов Таблиц VRAM для текущего режима ''SCREEN''. Эти регистры инициализируются псевдопеременной ''BASE''. Отметим,что при использовании этих регистров рекомендуется маскировать //ненужные// в текущем режиме отображения биты. Регистр с номером 2 VDP содержит семь старших бит начального адреса Таблицы PNT: | 0 | A16 | A15 | A14 | A13 | A12 | A11 | A10 | {{anchor:e1122-01}} __//Пример 1//__. \\ {{.examples:1122-01.bas|}} \\ [[+tab|wmsxbpge>1122-01.bas]] 10 SCREEN 1 20 A$=RIGHT$("0000000000000000"+BIN$(BASE(5*1+0)),16) 30 ?A$:B$=RIGHT$("00000000"+BIN$(VDP(2)),8):?B$ 'Читаем текущий адрес PNT run ┌──────┐ │000110│0000000000◀── Начальный адрес Таблицы PNT в SCREEN1 └──────┘ ┌──────┐ 00│000110│ ◀── Содержимое регистра с номером 2 Ok └──────┘ Регистры с номерами 10 и 3 содержат одиннадцать старших бит начального адреса Таблицы CT: Регистр 10 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | A14 | Регистр 3 | A13 | A12 | A11 | A10 | A9 | A8 | A7 | A6 | {{anchor:e1122-02}} __//Пример 2//__. \\ {{.examples:1122-02.bas|}} \\ [[+tab|wmsxbpge>1122-02.bas]] 10 SCREEN 1 20 A$=RIGHT$("0000000000000000"+BIN$(BASE(5*1+1)),16) 30 ?A$:B$=RIGHT$("0000000000000000"+BIN$(VDP(10+1))+BIN$(VDP(3)),16):?B$ run ┌──────────┐ │0010000000│000000 ◀── Начальный адрес Таблицы CT в SCREEN1 └──────────┘ ┌──────────┐ 000000│0010000000│◀── Содержимое регистров с номерами 10 и 3 Ok └──────────┘ Регистр с номером 4 содержит шесть старших бит начального адреса Таблицы PGT: | 0 | 0 | A16 | A15 | A14 | A13 | A12 | A11 | {{anchor:e1122-03}} __//Пример 3//__. \\ {{.examples:1122-03.bas|}} \\ [[+tab|wmsxbpge>1122-03.bas]] 10 SCREEN 0:WIDTH 80 20 A$=RIGHT$("0000000000000000"+BIN$(BASE(5*0+2)),16) 30 ?A$:B$=RIGHT$("00000000"+BIN$(VDP(4)),8):?B$ run ┌─────┐ │00010│00000000000◀── Начальный адрес Таблицы PGT └─────┘ в SCREEN0 ┌─────┐ 000│00010│ ◀── Содержимое регистра с номером 4 Ok └─────┘ Регистры с номерами 11 и 5 содержат десять старших бит начального адреса Таблицы SAT: Регистр 11 | 0 | 0 | 0 | 0 | 0 | 0 | A16 | А15 | Регистр 5 | А14 | A13 | A12 | A11 | A10 | A9 | A8 | А7 | {{anchor:e1122-04}} __//Пример 4//__. \\ {{.examples:1122-04.bas|}} \\ [[+tab|wmsxbpge>1122-04.bas]] 10 SCREEN 1 20 A$=RIGHT$("0000000000000000"+BIN$(BASE(5*1+3)),16) 30 ?A$:A$=RIGHT$("0000000000000000"+BIN$(VDP(1+11))+BIN$(VDP(5)),16):?A$ run ┌─────────┐ │000110110│0000000 ◀── Начальный адрес Таблицы SAT в SCREEN1 └─────────┘ ┌─────────┐ 0000000│000110110│◀── Содержимое регистров с номерами 11 и 5 Ok └─────────┘ //Замечание//. С Таблицей SAT связана Таблица SCT, адрес которой получается вычитанием 512 байт из начального адреса Таблицы SAT. Регистр с номером 6 содержит шесть старших бит начального адреса Таблицы SGT: | 0 | 0 | A16 | A15 | A14 | A13 | A12 | A11 | {{anchor:e1122-05}} __//Пример 5//__. \\ {{.examples:1122-05.bas|}} \\ [[+tab|wmsxbpge>1122-05.bas]] 10 SCREEN 1 20 A$=RIGHT$("0000000000000000"+BIN$(BASE(5*1+4)),16) 30 ?A$:B$=RIGHT$("00000000"+BIN$(VDP(6)),8):?B$ 'Читаем текущий адрес SGT run ┌─────┐ │00111│00000000000◀── Начальный адрес Таблицы SGT └─────┘ в SCREEN1 ┌─────┐ 000│00111│ ◀── Содержимое регистра с номером 6 Ok └─────┘ Отметим, что при использовании этих регистров рекомендуется //маскировать// ненужные в текущем режиме отображения биты. {{anchor:n1123}} ==== XI.2.3. Регистры цветов ==== \\ — Вы знаете отличительные способности животного, называемого раком?\\ — Да, конечно. Рак — это рыба //красного цвета//, которая ходит боком.\\ — Ну, что ж. Я вижу, что Вы кое–что //знаете// о раке… —//Студенческий фольклор// - Регистр с номером 7 видеопроцессора в режиме ''SCREEN 0'' определяет цвет изображения и фона. Четыре старших бита этого регистра "хранят" цвет //изображения//, а четыре младших — цвет //фона//. Например, команда VDP(7)=&H4B ▲▲ Цвет изображения ──┘└── Цвет фона в режиме SCREEN 0 эквивалентна команде ''COLOR 4,11'' . А команда ''VDP(7)=&H1F'' приводит к тому же результату, что и оператор ''COLOR 1,15'' . //Регистр// с номером 7 (регистр цвета текста/фона) ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Имя бита| TC3 | TC2 | TC1 | TC0 | BD3 | BD2 | BD1 | BD0 | ^Назначение|определяет цвет текста в режимах ''SCREEN 0'' и ''SCREEN 1''||||определяет цвет фона во всех режимах отображения|||| В других режимах ''SCREEN'' этот регистр "хранит" цвет //бордюра//. {{anchor:e1123-01}} __//Пример 1//__. \\ {{.examples:1123-01.bas|}} \\ [[+tab|wmsxbpge>1123-01.bas]] 10 COLOR 1,15,4:SCREEN 2:Z=VDP(7) 20 SCREEN 0:PRINT Z run 4 Ok Содержимое седьмого регистра инициализируется оператором ''COLOR'' - В 80–символьном режиме ''SCREEN 0'' существует явление, которое мы назовём //миганием//. Информация о символах, которые должны мигать, находится в Таблице цветов (CT), которая занимает 270 байтов с адреса, возвращаемого псевдопеременной ''BASE(0*5+1)''. Рассмотрим, как она располагается. Каждая строка экрана разбивается на 10 участков по 8 квадратов (знакомест) в каждом. За каждый из этих участков отвечает один байт, а за квадрат, естественно, один бит. Если значение бита равно 1, то символ на соответствующем знакоместе (в соответствующем квадрате) //мигает//. В противном случае мигания не происходит. Запись в Таблицу CT ещё не означает, что какое–то знакоместо на экране сразу замигает. Для начала мигания необходимо обратиться к регистрам VDP, отвечающим за этот процесс. Вначале договоримся о терминологии. // Основным// цветом текста (фона) будем называть цвет, задаваемый оператором ''COLOR'' и хранящийся в 7–м регистре VDP. //Цветом мигания// текста (фона) будем называть цвет,который приобретает текст (фон) при мигании. //Частотой включения мигания// назовём промежуток времени, в течение которого текст и фон приобретают цвет мигания. //Частотой выключения мигания// будем называть промежуток времени, в течении которого текст и фон приобретают основной цвет. Единица измерения частоты мигания равна 1/6 секунды. Максимально возможный период мигания составляет 5 секунд (15/6 секунд на включение мигания и столько же на выключение мигания). Регистр с номером //двенадцать// VDP содержит информацию о цвете мигания текста и фона. Старший полубайт этого регистра отвечает за цвет мигания текста, а младший полубайт отвечает за цвет мигания фона. //Регистр// с номером 12 (регистр цвета текста/фона) ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Имя бита| TC3 | TC2 | TC1 | TC0 | BC3 | BC2 | BC1 | BC0 | ^Назначение|определяют цвет части 1 шаблона||||определяют цвет части 0 шаблона|||| Если в режиме ''SCREEN 1'' установлен признак мерцания, то цвета из этого регистра и из регистра с номером 7 поочерёдно отображаются. За частоту мигания "отвечает" регистр с номером //тринадцать//, причём в его старшем полубайте хранится информация о частоте включения мигания, а в младшем — информация о частоте выключения мигания. //Регистр// с номером 13 (регистр периода мерцания) ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Имя бита| ON3 | ON2 | ON1 | ON0 | OF3 | OF2 | OF1 | OF0 | ^Назначение|определяют период отображения для чётной страницы||||определяют период отображения для нечётной страницы|||| В режимах растровой графики (''SCREEN 5'' – ''SCREEN 8'') попеременно сменяются две страницы памяти. Данные помещаются в этот регистр для установления отображаемой страницы как нечётной страницы для начала мерцания. Этот регистр используется также в режиме ''SCREEN 1''. Приведём табличку… ^ Содержимое \\ полубайта \\ регистра 13 ^ Время (мс) ^ | 0000 | 0 | | 0001 | 166,9 | | 0010 | 333,8 | | 0011 | 500,6 | | 0100 | 667,5 | | 0101 | 834,4 | | 0110 | 1001,3 | | 0111 | 1168,2 | | 1000 | 1335,1 | | 1001 | 1501,9 | | 1010 | 1668,8 | | 1011 | 1835,7 | | 1100 | 2002,6 | | 1101 | 2169,5 | | 1110 | 2336,3 | | 1111 | 2503,2 | А теперь взгляните на следующий пример. {{anchor:e1123-02}} __//Пример 2//__. \\ {{.examples:1123-02.bas|}} \\ [[+tab|wmsxbpge>1123-02.bas]] NEW Ok 10 SCREEN 0:WIDTH 80 'Установка режима для мигания 20 FOR T=2048 TO 2048+269:VPOKE T,0:NEXT 'Очистка Таблицы мигания 30 LINEINPUT "Введите слово:";B$ 40 INPUT "Где ему мигать (X,Y)";X,Y 50 INPUT "Цвет слова для мигания";MI 60 INPUT "Цвет фона для мигания";MF 70 INPUT "Частота включения мигания (от 0 до 15)";TN 80 INPUT "Частота выключения мигания (от 0 до 15)";TK 90 VPOKE 2048+10*Y+X/8,&B11111111 'Будут мигать 8 символов 100 CLS:LOCATE X,Y:PRINT B$ 110 COL=16*MI+MF:TIM=16*TN+TK 120 VDP(12+1)=COL:VDP(13+1)=TIM Для прекращения мигания поместите в старший полубайт 13–го регистра число 0. - Две графические страницы экрана могут отображаться //попеременно// (в режимах ''SCREEN 5'' – ''SCREEN 8''). Страницы, которые будут попеременно отображаться, расположены следующим образом: Режим SCREEN 5 и SCREEN 6 Режим SCREEN 7 и SCREEN 8 ┌─────────────┐ ┌────────────┐ │ Страница 0 │─┐ │ │─┐ ├─────────────┤ │ │ Страница 0 │ │ │ Страница 1 │─┘ │ │ │ ├─────────────┤ ├────────────┤ │ │ Страница 2 │─┐ │ │ │ ├─────────────┤ │ │ Страница 1 │─┘ │ Страница 3 │─┘ │ │ └─────────────┘ └────────────┘ Период отображения,находящийся в промежутке между 166 мс и 2053 мс, может быть определён для каждой страницы. Для этого необходимо: - задать базовый адрес Таблицы имён шаблонов //нечётной// страницы (регистр с номером 2); - задать время включения (интервал, в течение которого отображается //чётная// страница) и время выключения (интервал, в течение которого отображается //нечётная// страница) в регистре с номером 13. //Регистр// с номером 13 (регистр периода мерцания) ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Имя бита| ON3 | ON2 | ON1 | ON0 | OF3 | OF2 | OF1 | OF0 | ^Назначение|Время включения||||Время выключения|||| - после этого начнётся процесс мигания. {{anchor:e1123-03}} __//Пример 3//__. \\ {{.examples:1123-03.bas|}} \\ [[+tab|wmsxbpge>1123-03.bas]] 10 SCREEN 7 :' Режим растровой графики (SCREEN 5–8) 20 SET PAGE 0,0: CLS :' На странице 0 30 CIRCLE (254,106),30,15 :' рисуем окружность 40 SET PAGE 1,1: CLS :' А на странице 1 50 CIRCLE (254,106),60,15 :' рисуем окружность большего радиуса 60 VDP(13+1)=&H11 :' Включим смену страниц 70 :' Окружность п у л ь с и р у е т ! 80 A$=INPUT$(1) :' Ждем нажатия любой клавиши... 90 VDP(13+1)=0 :' Выключим смену страниц Опишем ещё один способ осуществления смены двух графических страниц на экране. Бит EO (второй бит регистра с номером 9), используется для попеременной демонстрации //двух// графических страниц экрана с частотой 60 Гц. Для этого необходимо: 1) задать базовый адрес Таблицы имён шаблонов //нечётной// страницы (регистр с номером 2); 2) установить //второй// бит регистра с номером 9 в 1. {{anchor:e1123-04}} __//Пример 4//__. \\ {{.examples:1123-04.bas|}} \\ [[+tab|wmsxbpge>1123-04.bas]] 10 SCREEN 7:VDP(10)=0 :' Режим растровой графики (SCREEN 5–8) 20 SET PAGE 0,0: CLS :' Рисуем на странице 0 30 CIRCLE (256,106),30,15 :' окружность радиусом 30 31 FOR I=1 TO 100:NEXT :' З а д е р ж к а... 40 SET PAGE 1,1: CLS :' А на странице 1 - 50 CIRCLE (256,106),60,15 :' окружность радиусом 60 51 FOR I=1 TO 100:NEXT :' З а д е р ж к а... 59 :' :' А теперь - п о м и г а е м ... 60 VDP(9+1)=&B00000100:' Включаем попеременное отображение страниц. 70 :' Окружности с двух страниц одновременно отображаются на экране ! 80 :' Недостаток: заметное мигание изображения 81 :' Эта возможность используется в программе PAINTER 82 :' (меню Tool.Show Canvas) 90 A$=INPUT$(1) :' З а д е р ж к а Кроме того, видеопроцессор поддерживает функцию черезстрочного отображения. Отображение первого и второго //полей// на одной и той же странице можно получить, установив бит IL (третий бит регистра с номером 9) в 1. Отображение чётной страницы в первом поле и нечётной страницы во втором поле можно получить, выполнив следующее: 1) установить бит IL (третий бит регистра с номером 9) в 1; 2) установить бит EO (второй бит регистра с номером 9) в 1; 3) задать базовый адрес Таблицы имён шаблонов нечётной страницы (регистр с номером 2). {{anchor:e1123-05}} __//Пример 5//__. \\ {{.examples:1123-05.bas|}} \\ [[+tab|wmsxbpge>1123-05.bas]] 10 COLOR 15,1,1: SCREEN 7 ' Режим растровой графики 15 ' Обратите внимание на координаты линий ! 20 SET PAGE 0,0:CLS:LINE (0,100)-(511,100),15 'На странице 0 рисуем линию 30 SET PAGE 1,1:CLS:LINE (0,100)-(511,100),8 ' На 1–й странице тоже рисуем линию 31 VDP(9+1)=&B00001100 32 ' │└─────── Отображаем четную страницу в первом поле 33 ' └──────── и нечетную страницу во втором поле 34 'Линии накладываются друг на друга на 1/2 (!) точки 40 A$=INPUT$(1) ' Задержка 41 VDP(9+1)=0 ' Выключим мигание - * Регистр с номером 20 называется регистром цветовой вспышки 1. * Регистр с номером 21 называется регистром цветовой вспышки 2. * Регистр с номером 22 называется регистром цветовой вспышки 3. Данные регистры инициализируются при включении компьютера следующим образом: ^Номер бита^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ ^Регистр 20| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ^Регистр 21| 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | ^Регистр 22| 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | Если все величины в трёх вышеуказанных регистрах равны нулю, то сигнал "цветовой вспышки" на NTSC–видеовыходе будет отсутствовать. Если же вышеуказанные величины затем возвращаются в исходное состояние, то будет получен обычный сигнал "цветовой вспышки" на NTSC–видеовыходе. {{anchor:n1124}} ==== XI.2.4. Регистры управления экраном ==== Регистрами //управления экраном// будем называть регистры с номерами 18, 19, 23. Эти регистры используются для управления отображением на дисплее. - Использование регистра с номером //восемнадцать// даёт возможность центрирования изображения относительно электронно–лучевой трубки дисплея: Регистр с номером 18 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │ │ Параметр смещения │ │ Параметр смешения │ │ │ вверх–вниз │ │ вправо–влево │ └──▲───┴──────┴──────┴──────┴──▲───┴──────┴──────┴──────┘ │ │ Флаг смещения вверх–вниз: Флаг смещения вправо–влево: 1 означает смещение экрана вниз; 1 означает смещение экрана вправо; 0 означает смещение экрана вверх 0 означает смещение экрана влево А теперь посмотрите на фрагмент алгоритма нахождения величины смещения экрана, который записан на школьном алгоритмическом языке: если Флаг смещения = 1 ──── │ то Величина смещения = 8 - параметр смещения │ ── │ иначе Величина смещения = параметр смещения │ ───── │ все ─── {{anchor:e1124-01}} __//Пример 1//__. Сдвинем экран влево на 2 точки и вниз на 5 точек. \\ {{.examples:1124-01.bas|}} \\ [[+tab|wmsxbpge>1124-01.bas]] 10 VDP(18+1)=&B10110010 ▲└▲┘▲└▲┘ Смещение экрана вниз ─┘ │ │ └─ 2 точки 5=8-3 ───┘ └─── Смещение экрана влево На компьютерах [[msx:msx_2]] по умолчанию "содержимое" регистра с номером 18 по умолчанию задаётся оператором SET ADJUST (X,Y) . Значения выражений X и Y принадлежат отрезку [-7,8]. - Можно установить прерывание в момент, когда видeопроцессор начинает сканировать определённую линию. Для получения прерывания используется регистр с номером //девятнадцать//, в котором хранится номер линии. - __//Регистр 23//__. Взгляните на рисунок, и Вы увидите, как изменяется изображение символов на //текстовом// экране в зависимости от содержимого 23–го регистра (значимыми при этом являются только три младших бита): VDP(23+1)=0 VDP(23+1)=1 VDP(23+1)=2 VDP(23+1)=3 ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ VDP(23+1)=4 VDP(23+1)=5 VDP(23+1)=6 VDP(23+1)=7 ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │ │ │ │ │ │ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │ │ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│ │█│ │█│ │ │ │ │█│█│ │█│█│ │ │ │ │█│ │ │ │█│ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ {{anchor:e1124-02}} __//Пример 2//__. \\ {{.examples:1124-02.bas|}} \\ [[+tab|wmsxbpge>1124-02.bas]] 5 SCREEN 0 10 CLS:KEYOFF 20 FOR I=0 TO 5:PRINT "▧▨▧▨▧":NEXT 30 FOR J=0 TO 7 40 FOR K=0 TO 10:NEXT K 50 VDP(23+1)=J 60 NEXT J 70 IF INKEY$="" THEN 30 80 VDP(23+1)=0:END В //графических// режимах регистр с номером 23 предоставляет другую интересную возможность. Вначале следует вспомнить, что доступная высота графического экрана равна 192 или 212 линиям (в зависимости от девятого регистра VDP). Однако Вы можете, воздействуя на VRAM (используя, например, оператор ''VPOKE''), сформировать шаблоны 256 линий, просмотрев которые Вы можете, использовав регистр с номером 23. Понять, как это происходит, Вы можете из следующих рисунков: VDP(23+1)=0: ┌─────────────────┐ Y=0 │ Видимые линии │ ├─────────────────┤ Y=192 или 212 │ Невидимые линии │ └─────────────────┘ Y=255 VDP(23+1)=200: ┌─────────────────┐ Y=0 │ Видимые линии │ ├─────────────────┤ Y=136 или 156 │ Невидимые линии │ ├─────────────────┤ Y=200 │ Видимые линии │ └─────────────────┘ Y=255 {{anchor:n1125}} ==== XI.2.5. Некоторые регистры доступа ==== Имеется возможность изменить палитру некоторого цвета. Для установки данных в //девятибитные// регистры палитры видеопроцессора (с номерами от 0 до 15) следует вначале установить номер регистра палитры в регистре с номером //шестнадцать//, а затем последовательно вывести //два// байта данных (по порядку) через порт &H9A. ^Номера бит^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ |//Регистр// 16| 0 | 0 | 0 | 0 | //Номер палитры// |||| |//Порт// &H9A| 0 | //Красный// ||| 0 | //Синий// ||| |//Порт// &H9A| 0 | 0 | 0 | 0 | 0 | //Зелёный// ||| Для изменения цвета надо набрать последовательно команды (операторы): VDP(16+1)=C:OUT &H9A,16*R+B:OUT &H9A,G , где: * C — номер цветовой палитры, которую Вы хотите изменить; * R, B, G — числа, определяющие соотношение красного, синего и зелёного цветов в палитре. {{anchor:e1125-01}} __//Пример 1//__. \\ {{.examples:1125-01.bas|}} \\ [[+tab|wmsxbpge>1125-01.bas]] COLOR 15,3 Ok VDP(16+1)=3:OUT &H9A,64:OUT &H9A,3 Ok Отметим, что для компьютеров [[msx:msx_1]] этот способ изменения цветов является единственно возможным! {{anchor:e1125-02}} __//Пример 2//__. \\ {{.examples:1125-02.bas|}} \\ [[+tab|wmsxbpge>1125-02.bas]] 10 COLOR 8,15,0:KEY OFF:SCREEN 1 20 FOR R=0 TO 7:FOR G=0 TO 7:FOR B=0 TO 7 30 OUT &H99,0:OUT &H99,16 OR &H80:OUT &H9A,16*R+B:OUT &H9A,G 40 LOCATE 10,10:?"R="R:LOCATE 10,11:?"G="G:LOCATE 10,12:?"B="B 50 FOR T=1 TO 500:NEXT T:NEXT B,G,R Регистр с номером //семнадцать// хранит информацию о //косвенном// доступе в регистры VDP. Взгляните на его содержимое: ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ∗ | 0 | //Номер регистра// |||||| | 0 |//запрещено//||||||| | 1 |//разрешено//||||||| | ∗ = автоинкрементирование|||||||| В соответствии со значением 7–го бита регистра 17 содержимое этого регистра может автоматически увеличиваться. Если автoинкрементирование запрещено, то содержимое 17–го регистра останется прежним. Приведём два способа //косвенной записи// в видеопроцессор с использованием регистра с номером 17: - α) 10 VDP(17+1)=N OR &H80'или OUT &H99,N OR &H80:OUT &H99,17 OR &H80 20 OUT &h9B, Число для регистра с номером N 30 OUT &h9B, Число для регистра с номером N+1 40 OUT &H9B, Число для регистра с номером N+2 50 ' ··· {{anchor:e1125-03}} __//Пример 3//__. \\ {{.examples:1125-03.bas|}} \\ [[+tab|wmsxbpge>1125-03.bas]] 5 SCREEN 1:COLOR 15,0,8 10 VDP(17+1)=8 OR &H40 'Установка регистра с номером 17 на косвенный доступ 20 OUT &H9B,VDP(8+1) OR &H20 'Цвет 0 из Таблицы палитр 30 OUT &H9B,VDP(9+1) OR &H80 'На экране - 26.5 строк - β) 10 VDP(17+1)=N 'или OUT &H99,N:OUT &H99,17 OR &H80 20 OUT &H9B, Число для регистра N 30 OUT &H9B, Число для регистра N 40 OUT &H9B, Число для регистра N 50 ' ··· Косвенный доступ к регистрам видеопроцессора применяется тогда, когда необходимо записать информацию в несколько регистров, адреса которых идут //подряд//. При этом запись через порт с адресом &H9B будет происходить до тех пор, пока не будет сделана новая установка на косвенный доступ. Данные в 17–м регистре не могут быть изменены косвенной адресацией! {{anchor:n1126}} ==== XI.2.6. Доступ к видеопамяти ==== __//Регистр 14//__ (регистр базового адреса доступа к VRAM). Этот регистр видеопроцессора используется при доступе к видеопамяти. Если Вы располагаете видеопамятью объёмом до 16 Кбайт, то использование этого регистра не имеет смысла, так как в нем хранятся //старшие// биты текущего адреса видеопамяти. //Регистр с номером// 14 ^Номера бит^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | | 0 | 0 | 0 | 0 | 0 | A16 | A15 | A14 | В регистре с номером 14 устанавливаются три старших бита адреса ячейки видеопамяти (A16, A15, A14). Сейчас мы расскажем, как обратиться к //любой// ячейке видеопамяти. На компьютерах серии [[msx:msx_2]] существует 2 типа видеопамяти: VRAM и ERAM. VRAM ("Video RAM") имеет объем в 128 Кбайт, а ERAM ("Expanded RAM") — 64 Кбайт. Информация о том, какая видеопамять используется в настоящий момент, хранится в регистре с номером 45. Доступ к видеопамяти осуществляется в следующей последовательности: - выберите //тип// видеопамяти: VDP(45+1)=&B0∗∗∗∗∗∗∗ ▲└──▲─┘ │ └── эти биты используются для других целей ├────── 1 — если используется ERAM └────── 0 — если используется VRAM Отметим, что содержимое регистра с номером 45 не меняется при очередном обращении к памяти. - установите биты A14–A16 адреса видеопамяти: VDP(14+1)=&B00000∗∗∗ ▲▲▲ A16 ───┘│└─── A14 └──── A15 - установите биты A0–A7 счётчика адреса посредством вывода данных в порт &H99: OUT &H99,&B∗∗∗∗∗∗∗∗ ▲▲▲▲▲▲▲▲ │││││││└──── A0 ││││││└───── A1 │││││└────── A2 ││││└─────── A3 │││└──────── A4 ││└───────── A5 │└────────── A6 └─────────── A7 - установите биты A8–A13 счётчика адреса и признак чтения или записи посредством вывода данных в порт &H99: OUT &H99,&B∗∗∗∗∗∗∗∗ ▲▲▲▲▲▲▲▲ │││││││└──── A8 ││││││└───── A9 │││││└────── A10 ││││└─────── A11 │││└──────── A12 ││└───────── A13 └┼────────── 00 — признак чтения └────────── 01 — признак записи - а теперь остаётся прочитать или записать данные в нужный байт: A=INP(&H98) — чтение OUT &H98,A — запись - после чтения или записи данных содержимое адресного счётчика автоматически увеличивается на единицу. При этом, если есть перенос из бита A13, то в режимах ''SCREEN'' 4–8 происходит увеличение содержимого регистра с номером 14. В режимах ''SCREEN'' 1–3 и в 40–символьном режиме ''SCREEN 0'' увеличения содержимого 14–го регистра не происходит. Из сказанного следует, что если нужно записать информацию в несколько подряд расположенных ячеек видеопамяти, достаточно установить лишь начальный адрес этой группы ячеек. {{anchor:n1127}} ==== XI.2.7. Регистры статуса ==== Кроме регистров VDP, видеопроцессор работает с группой регистров, называемыми регистрами //статуса//. Эти регистры содержат информацию о состоянии видеопроцессора. Из них информацию можно только //читать//. Текущий номер регистра статуса записывается в регистр VDP с номером //пятнадцать// (регистр–указатель регистра состояния). ^Номера бит^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | | 0 | 0 | 0 | 0 | Номер регистра статуса |||| Для доступа к регистрам //состояния// видеопроцессора (с номерами 0,1,2,3,…,9) вначале нужно установить номер регистра статуса в регистре с номером 15, а затем прочесть данные через порт &H99. Для записи в переменную W числа из регистра статуса с номером S выполните следующие действия: VDP(15+1)=S:W=INP(&H99):VDP(15+1)=0 __//Регистр статуса номер 0//__. 7 6 5 4 3 2 1 0 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │ │ │ │ ∗ │ ∗ │ ∗ │ ∗ │ ∗ │ └───▲──┴───▲──┴──▲───┴──────┴──────┴──────┴──────┴──────┘ │ │ │ └───▲──────────────────────────────┘ │ │ │ └ Экранный номер пятого или девятого │ │ │ (в зависимости от режима SCREEN) спрайта в строке │ │ └─── Флаг, указывающий на столкновение 2 спрайтов │ │ │ └───────── Флаг обнаружения пятого (или девятого) спрайта в строке │ └──────────────── Флаг прерывания от вертикального сканирования (после чтения регистра состояния 0 данный флаг сбрасывается) Если бит СС=0 и высвечиваемые части шаблонов спрайтов перекрываются, то устанавливается столкновение спрайтов. Если столкновение спрайтов обнаружено, то бит 5 регистра статуса с номером 0 устанавливается в 1. Этот бит устанавливается в 0 после чтения регистра статуса с номером 0. Использование регистра статуса с номером 0 рассмотрим на примерах. {{anchor:e1127-01}} __//Пример 1//__. \\ {{.examples:1127-01.bas|}} \\ [[+tab|wmsxbpge>1127-01.bas]] 10 SCREEN 1,2 20 SPRITE$(2)="Проверка":SPRITE$(3)="на столкновение" 30 FOR T=1 TO 130 40 PUT SPRITE 2,(T,80):PUT SPRITE 3,(240-T,80) 50 VDP(15+1)=0:Z=INP(&H99) AND 32 60 IF Z<>0 THEN PRINT "Столкновение состоялось!" 70 NEXT {{anchor:e1127-02}} __//Пример 2//__. \\ {{.examples:1127-02.bas|}} \\ [[+tab|wmsxbpge>1127-02.bas]] 10 SCREEN 1:KEYOFF 20 FOR I=0 TO 7:READ E:VPOKE &H3800+I,E:NEXT 30 A0=BASE(1*5+3):AD=A0+4*1:AP=A0+4*2 40 VPOKE AP,50:VPOKE AP+1,100:VPOKE AP+2,0:VPOKE AP+3,15 50 FOR X=0 TO 255 60 VPOKE AD,50:VPOKE AD+1,X:VPOKE AD+2,0:VPOKE AD+3,15 70 VDP(15+1)=0:Z=INP(&H99) AND 32 80 IF Z<>0 THEN LOCATE 1,1:PRINT"столкновение":FOR L=0 TO 100:NEXT:LOCATE1,1:PRINT" " 90 NEXT 100 GOTO 50 110 DATA 255,255,195,195,195,195,255,255 {{anchor:e1127-03}} __//Пример 3//__. \\ {{.examples:1127-03.bas|}} \\ [[+tab|wmsxbpge>1127-03.bas]] 10 SCREEN1,2 20 SPRITE$(1)="Проверка":SPRITE$(2)="появления":SPRITE$(3)="пятого": SPRITE$(4)="спрайта":SPRITE$(5)="в строке" 30 PUT SPRITE0,(10,80),,5:PUT SPRITE1,(20,80),,4:PUT SPRITE2,(30,80),,3:PUT SPRITE3,(40,80),,2 40 VDP(15+1)=0:Z=INP(&H99) 50 PRINT RIGHT$("00000000"+BIN$(Z),8) 55 A$=INPUT$(1) 60 PUT SPRITE4,(50,80),,1 70 VDP(15+1)=0:Z=INP(&H99) 80 ? RIGHT$("00000000"+BIN$(Z),8);"◀─ Появился 5-й спрайт в строке!" Отметим, что содержимое регистра статуса с номером 0 можно прочесть не только функцией ''INP'', но и при помощи псевдопеременной ''VDP'': A = VDP(8) . {{anchor:e1127-04}} __//Пример 4//__. Управление столкновениями спрайтов. \\ {{.examples:1127-04.bas|}} \\ [[+tab|wmsxbpge>1127-04.bas]] 20 SCREEN 2,2 30 SPRITE$(0)=STRING$(32,255) 40 PUT SPRITE 0,(112,80),1,0 50 PUT SPRITE 1,(10,80),8,0 60 IF (VDP(8)AND32)=32 THEN GOTO 90 70 PUT SPRITE 1,STEP(1,0),8,0 80 GOTO 60 90 BEEP:GOTO 90 //Замечание//. Назначения бит регистров статуса с номерами 1, 2, 3, 4, 5, 6, 7, 8, 9 рассмотрены в Приложении 2 ((Пока не найдено, подробнее [[start#Список отсутствующего материала|здесь]])). Там же рассмотрены назначения бит командных регистров с номерами 32,33,… ,45,46. {{anchor:n113}} ===== XI.3. Нестандартные режимы видеопроцессора ===== \\ Боги открыли людям не все.\\ В поиск пустившись, люди сами открыли немало. —//Ксенофан// {{anchor:n1131}} ==== XI.3.1. Режим SCREEN 4 на компьютерах MSX 1 ==== Для Вас, наверное, окажется неожиданностью, что на компьютерах [[msx:msx_1]] можно использовать режимы ''SCREEN 4'' – ''SCREEN 8''. Доступ к этим режимам осуществляется путём непосредственной записи в регистры видеопроцессора. Режим ''SCREEN 4'' вызывается из режима ''SCREEN 2'' путём обращения к видеопроцессору: VDP(0)=4 . При этом изображение, нарисованное в режиме ''SCREEN 2'', останется на экране. Этот режим выгодно отличается возможностями работы со спрайтами. Приведём начальные адреса Таблиц VRAM, отвечающих за спрайты, в этом режиме: ^ //Имя// Таблицы ^ Начальный адрес Таблицы ^ | SGT | &H3800 | | SAT | &H1A00 | | SCT | &H1800 | Чтобы вернуться в режим ''SCREEN 2'', достаточно снова обратиться к видеопроцессору: VDP(0)=2 . Учтите, что режим ''SCREEN 4'' на компьютерах серии [[msx:msx_1]] имеет некоторые //особенности//: - происходит частичное "наложение" Таблиц SAT и SCT на Таблицу PNT, что приводит к искажению неподвижного изображения. Поэтому необходимо "спасти" Таблицу PNT, т.е. передвинуть её на свободное место в видеопамяти; - при переходе в этот режим возникает несоответствие между начальным адресом Таблицы SAT, возвращаемым псевдопеременной ''BASE(13)'', и тем же адресом,хранящимся в рабочей области RAM. Поместите поэтому в рабочую область RAM по адресам &HF928 и &HF929 число, записанное в псевдопеременной ''BASE(13)''; - образы спрайтов выводятся на экран уже на стадии формирования спрайтовых переменных.Единственный способ избавиться от этого — временно отключить изображение (без очистки экрана) и включить его непосредственно перед обращением к Таблице атрибутов спрайтов (SAT). А теперь взгляните на {{anchor:e1131-01}} __//Пример 1//__. Вы, конечно, помните, что текущий адрес Таблицы PNT хранится в рабочей области по адресам &HF922 и &HF923. \\ {{.examples:1131-01.bas|}} \\ [[+tab|wmsxbpge>1131-01.bas]] 10 SCREEN 2,2 20 'Инициализация режима SCREEN 4 50 VDP(2)=7:POKE &HF923,&H1C 'Передвинем Таблицу PNT 60 VDP(5)=52:POKE &HF929,&H1A 'Приведем в порядок SAT 65 VDP(0)=4 'Установим режим SCREEN 4 70 'Основная программа 75 VDP(1)=VDP(1) XOR 64 'Отключим изображение 80 CIRCLE(100,100),50,15 90 FOR X=0 TO 8 100 SPRITE$(X)=STRING$(32,255):NEXT 'Сформируем спрайты 110 FOR Y=0 TO 15:V=INT(RND(1)*16) 120 FOR X=0 TO 8 130 VPOKE &H1800+X*16+Y,V 'Раскрасим спрайты, используя Таблицу SCT 140 NEXT X,Y 150 VDP(1)=VDP(1) XOR64 'Включим изображение 160 PUT SPRITE 8,(70,30),,0 170 X=128:Y=96 180 A=STICK(0) 190 IF A=1 OR A=2 OR A=8 THEN Y=Y-2 200 IF A=2 OR A=3 OR A=4 THEN X=X+2 210 IF A=4 OR A=5 OR A=6 THEN Y=Y+2 220 IF A=6 OR A=7 OR A=8 THEN X=X-2 230 FOR Z=0 TO 7 240 PUT SPRITE Z,(X-Z*17,Y),,0 'В о с е м ь спрайтов в строке! 250 NEXT Z 260 GOTO 180 Вас, конечно, не удивляет тот факт, что на экране — //восемь// спрайтов в //строке//, так как Вам, наверное, известно, что режимы ''SCREEN 4'' – ''SCREEN 8'' предоставляют такую возможность! {{anchor:n1132}} ==== XI.3.2. Текстово–графические режимы ==== Мы опишем здесь два текстово–графических режима: * режим ''SCREEN'' 1–2 ("совмещённый" режим ''SCREEN 1'' и ''SCREEN 2''); * режим ''SCREEN'' 1–4 ("совмещённый" режим ''SCREEN 1'' и ''SCREEN 4''). "Совмещенный" режим ''SCREEN'' 1–2 устанавливается операторами: SCREEN 1:DEFUSR=&H7E:A=USR(0) . {{anchor:e1132-00}}Однако, прежде чем начать "работать" в этом режиме, его надо инициализировать следующим образом: \\ {{.examples:1132-00.bas|}} \\ [[+tab|wmsxbpge>1132-00.bas]] 10 SCREEN1:WIDTH 32 20 DEFUSR=&H7E:A=USR(0) 'Установили совмещенный режим 30 'Считываем шаблоны символов из ROM в Таблицу PGT 40 FOR T=0 TO 2 50 FOR K=0 TO 2047 60 VPOKE BASE(7)+2048*T+K,PEEK(&H1BBF+K) 70 NEXT K,T 80 'Инициализируем цвета символов в Таблице CT 90 FOR I=0 TO 6143:VPOKE BASE(6)+I,&HF4:NEXT I 100 'Установим форму курсора во 2-м и 3-м окне экрана 110 FOR Y=1 TO 2:FOR X=0 TO 7:VPOKE &H800*Y+255*8+X,255:NEXT X,Y 120 NEW Не беда, что для инициализации требуется более двух минут. При соответствующей подготовке Вы сможете написать программу в машинных кодах, которая будет работать в несколько десятков раз быстрее: {{anchor:e1132-01}} __//Пример 1//__. Смотрите и завидуйте! \\ {{.examples:1132-01.bas|}} \\ [[+tab|wmsxbpge>1132-01.bas]] 100 CLEAR 100,&HD000 110 SCREEN 1:WIDTH 32:DEFUSR=&H7E:A=USR(0) 120 A$="21000011BF1B1ACD1CD03EF0CBECCD1CD0CBAC13237CD608C 206D0C947CD4D00CBDC78CD4D00CB9CCBE478CD4D00CBA4C9" 130 FOR X=0 TO 48:POKE &HD000+X,VAL("&h"+MID$(A$,X*2+1,2)):NEXT 140 DEFUSR=&HD000:A=USR(0) 150 FOR Y=1 TO 2:FOR X=0 TO 7:VPOKE &H800*Y+255*8+X,255:NEXT X,Y Поговорим об //особенностях// режима ''SCREEN'' 1–2 : - Данный режим позволяет формировать многоцветные символы, причём информация о цветах каждого из них хранится в //восьми// байтах Таблицы CT: 1–й байт … 8–й байт ┌─────────────┬─────────────┬─────┬─────────────┬─────────────┐ │ Код цвета Код цвета │ │ Код цвета Код цвета │ │ изображения │ фона │ │ изображения │ фона │ │ для первой для первой │ … │ для восьмой для восьмой │ │ строки │ строки │ │ строки │ строки │ │ символа символа │ │ символа символа │ └─────────────┴─────────────┴─────┴─────────────┴─────────────┘ Проведём аналогию с режимом ''SCREEN 1'': 1–й байт CT ┌─────────────┬─────────────┐ │ Код цвета Код цвета │ │ изображения │ фона │ │ для первых для первых │ │ восьми │ восьми │ │ символов символов │ └─────────────┴─────────────┘ - Режим ''SCREEN'' 1–2 имеет трёхоконную структуру(как и режим ''SCREEN 2''): Внимательно изучите следующую табличку: ^ Адрес ^ //Комментарий// ^ | &H0000 |Таблица шаблонов образов, расположенных в верхней части экрана, т.е. с 0–й по 7–ю строку. На каждый символ отводится 8 байтов| | &H0800 |Таблица шаблонов символов, расположенных в средней части экрана, т.е. с 8–й по 15–ю строку| | &H1000 |Таблица шаблонов символов, расположенных в нижней части экрана, т.е. с 16–й по 23–ю строку| | &H1800 |Таблица имён образов (строки 0–7)| | &H1900 |Таблица имён образов (строки 8–15)| | &H1A00 |Таблица имён образов (строки 16–23)| | &H1B00 |Таблица атрибутов спрайтов| | &H2000 |Таблица цветов символов, расположенных с 0–й по 7–ю строку.\\ На каждый символ отводится 8 байтов. На каждую строку символа отводится 1 байт, старший полубайт которого отвечает за цвет установленных бит в Таблице шаблонов символов| | &H2800 |Таблица цветов символов, расположенных с 8–й по 15–ю строку| | &H3000 |Таблица цветов символов, расположенных с 16–й по 23–ю строку| | &H3800 |Таблица шаблонов спрайтов| - В режиме ''SCREEN'' 1–2 разрешено использование как текстовых,так и графических операторов, т.е. "совмещённый" режим ''SCREEN'' 1–2 может находиться в двух "состояниях". //Во–первых//, это — //текстовый// режим.В нем "работают" все операторы текстового экрана. Однако он отличается от текстового режима ''SCREEN 1'' в следующих моментах: - весь экран разбит на //три// горизонтальных окна; - символ, вообще говоря, раскрашен //одновременно// в 16 цветов (по два цвета на линию); - один и тот же символ (определяемый кодом АSCII), может быть различным по начертанию и цвету в трёх различных окнах экрана. Для изменения цвета какой–либо строки любого символа в любой трети экрана, примените оператор: VPOKE BASE(5+1)+2048*N+8*K+S,&HIF , где: * N — номер окна экрана; * K — код ASCII символа; * S — номер строки символа; * I — цвет изображения; * F — цвет фона. Для изменения шаблона одной строки символа используйте оператор VPOKE BASE(5+2)+2048*N+8*K+S,&B∗∗∗∗∗∗∗∗ , где: * N — номер окна экрана; * K — код ASCII символа; * S — номер строки символа; * ∗∗∗∗∗∗∗∗ — двоичное представление шаблона строки символа. Приведём несколько примеров: {{anchor:e1132-02}} __//Пример 2//__. Полюбуйтесь на //цветной// курсор! \\ {{.examples:1132-02.bas|}} \\ [[+tab|wmsxbpge>1132-02.bas]] 10 FOR X=0 TO 2 20 A=&H2000+&H800*X+255*8 30 FOR Y=0 TO 7 40 VPOKE A+Y,Y*16 50 NEXT Y 60 NEXT X {{anchor:e1132-03}} __//Пример 3//__. А вот "переливание" латинских букв "А" в верхней трети экрана! \\ {{.examples:1132-03.bas|}} \\ [[+tab|wmsxbpge>1132-03.bas]] 10 FOR A=0 TO 8 20 FOR X=0 TO 7 30 VPOKE &H2000+65*8+X,(X+A)*16 40 NEXT X 50 NEXT A 60 GOTO 10 Чтобы прекратить процесс "переливания", нажмите клавиши CTRL+STOP. {{anchor:e1132-04}} __//Пример 4//__. Вместо буквы "W" в верхнем углу экрана Вы уведите… "яблоко"! \\ {{.examples:1132-04.bas|}} \\ [[+tab|wmsxbpge>1132-04.bas]] 10 OUT&H99,6:OUT&H99,144:OUT&H98,16*4:OUT&H98,2 'Изменим 6-й цвет 20 A$="3C7E307830787E3C8484B8B8B8866414" 30 FOR X=0 TO 7 40 VPOKE 87*8+X,VAL("&H"+MID$(A$,X*2+1,2)) 50 VPOKE &H2000+87*8+X,VAL("&H"+MID$(A$,2*X+17,2)) 60 NEXT X {{anchor:e1132-05}} __//Пример 5//__. //"Толстые"// символы — только в верхней трети экрана! \\ {{.examples:1132-05.bas|}} \\ [[+tab|wmsxbpge>1132-05.bas]] 10 FOR X=&HFF TO &H7F7 20 A=VPEEK(X):VPOKE X,A OR A/2 30 NEXT X {{anchor:e1132-06}} __//Пример 6//__. Теперь повращаем "трубу" вокруг своей оси! \\ {{.examples:1132-06.bas|}} \\ [[+tab|wmsxbpge>1132-06.bas]] 10 FOR I=0 TO 7:VPOKE 8*43+I,255:NEXT 20 CLS:PRINT"++++++++++++++++++++++++++++++" 30 FOR F=7 TO 0 STEP -1 40 VPOKE &H2000+&H800*0+8*43+F,&H71 50 IF F=7 THEN W=0 ELSE W=F+1 60 VPOKE &H2000+&H800*0+8*43+W,&H51 70 IF W=7 THEN WC=0 ELSE WC=W+1 80 VPOKE &H2000+&H800*0+8*43+WC,&H41 90 IF WC=7 THEN JC=0 ELSE JC=WC+1 100 VPOKE &H2000+&H800*0+8*43+JC,&H51 110 IF JC=7 THEN JJ=0 ELSE JJ=JC+1 120 VPOKE &H2000+&H800*0+8*43+JJ,&H71 130 IF JJ=7 THEN YJ=0 ELSE YJ=JJ+1 140 VPOKE &H2000+&H800*0+8*43+YJ,&HF1 150 NEXT:GOTO 30 //Во–вторых//, режим ''SCREEN'' 1–2 — это графический режим, в котором можно одновременно и рисовать, и выводить текст. Для этого предварительно решите, в какой части экрана (одной или нескольких) Вы будете рисовать, а в какой — писать. Для того чтобы рисовать в какой–либо части экрана, её надо предварительно подготовить следующим образом: FOR T=0 TO 255 :VPOKE BASE(5)+256*N+T,T :NEXT FOR T=0 TO 2047:VPOKE BASE(5+1)+2048*N+T,&HF4:NEXT FOR T=0 TO 2047:VPOKE BASE(5+2)+2048*N+T,0 :NEXT , где N — номер части экрана, в которой Вы хотите применить графические операторы. Таким образом, Вы инициализируете участки Таблиц PNT, CT и PGT, отвечающие за изображение в нужном окне экрана. Теперь в приготовленной части экрана можно применять графические операторы. Однако их можно применять только после выполнения оператора: POKE &HFCAF,2 . Для выхода в //текстовый// режим "пригодится" оператор: POKE &HFCAF,1 . Если Вы его не выполните, то произойдёт переход в режим ''SCREEN 1'' ! Нужно постоянно помнить о том, что Ваши рисунки могут "портиться", так как любой символ, напечатанный в графической части экрана, портит рисунок. Однако рисунок можно восстановить, применив операторы: FOR T=0 TO 255:VPOKE BASE(5)+256*N+T,T:NEXT {{anchor:e1132-07}} __//Пример 7//__. В верхней части экрана — //графический// режим! \\ {{.examples:1132-07.bas|}} \\ [[+tab|wmsxbpge>1132-07.bas]] 10 CLS 20 FOR X=0 TO 255:VPOKE &H1800+X,X:NEXT 30 FOR X=0 TO &H7FF:VPOKE X,0:NEXT 40 LOCATE 5,10:PRINT"Вверху графика!" 50 POKE &HFCAF,2 60 LINE (20,10)-(100,40),15,BF 70 CIRCLE (80,30),40,8 80 POKE &HFCAF,1 Рассмотрим теперь "совмещённый" режим ''SCREEN'' 1–4. Единственное отличие режима ''SCREEN'' 1–4 от режима ''SCREEN'' 1–2 состоит в том, что в нем разрешена работа с //многоцветными// спрайтами (как и в режиме ''SCREEN 4''). {{anchor:e1132-08}} Инициализируется режим ''SCREEN'' 1–4 следующим образом: \\ {{.examples:1132-08.bas|}} \\ [[+tab|wmsxbpge>1132-08.bas]] 10 SCREEN 1:WIDTH 32 15 'Установим режим SCREEN 1-2 20 DEFUSR=&H7E:A=USR(0) 30 'Считываем шаблоны символов из ROM в Таблицу PGT 40 FOR T=0 TO 2 50 FOR K=0 TO 2047 60 VPOKE BASE(7)+2048*T+K,PEEK(&H1BBF+K) 70 NEXT K,T 80 'Инициализируем цвета символов в Таблице CT 90 FOR I=0 TO 6143:VPOKE BASE(6)+I,&HF4:NEXT I 100 'Установим форму курсора во 2-м и 3-м окнах экрана 110 FOR Y=1 TO 2:FOR X=0 TO 7:VPOKE &H800*Y+255*8+X,255:NEXT X,Y 115 'Теперь установим режим SCREEN 1-4 120 VDP(2)= 7:POKE &HF923,&H1C 'Передвинем Таблицу PNT 140 VDP(5)=52:POKE &HF929,&H1A 'Приведем в порядок SAT 150 VDP(0)=4:CLS:NEW Все сказанное о режиме ''SCREEN'' 1–2 распространяется и на режим ''SCREEN'' 1–4. Остаётся только добавить, что структура видеопамяти в "совмещённом" режиме ''SCREEN'' 1–4 полностью совпадает со структурой VRAM в режиме ''SCREEN 4'' для компьютеров серии [[msx:msx_1]]. {{anchor:examples11}} ====== Диск с примерами ====== {{.examples:examples11.dsk|Загрузить образ диска}} [[+tab|wmsxbpged>examples11.dsk|Открыть диск в WebMSX]] ---- [<>] {{tag>MSX msxbdpl}}