THE
COMPLETE AMIGA HARDWARE
REFERENCE MANUAL
Глава 6 БЛИТТЕР ВВЕДЕНИЕ Блиттер - часть чипа Agnus и один из двух сопроцессоров Амиги. Он используется для копирования прямоугольных блоков памяти и рисования линий. При копировании памяти он примерно вдвое быстрее 68000. Пропускная способность около 4 Mb в секунду. При рисовании линий производительность около миллиона пикселей в секунду. В блочном режиме блиттер может выполнять любую логическую операцию над тремя исходными областями, может сдвигать две исходные область от 1 до 15 бит, может закрашивать очерченную область, может маскировать первое и последнее слово в каждой линии. В режиме линии может использоваться любой шаблон для линии или линия может рисоваться так, чтобы на каждой горизонтальной линии ставился только 1 пиксель. Блиттер может адресовать только CHIP память. Попытка использования блиттера для чтения или записи в FAST или другую не CHIP память может разрушить содержимое CHIP памяти. Блит - отдельная операция блиттера - возможно рисование линии или перемещение блока памяти. Блит выполняется инициализацией регистров блиттера и запуском блиттера записью в регистр BLTSIZE. Так как блиттер асинхронный сопроцессор, 68000 продолжает выполнять программу. ПЛАНИРОВАНИЕ ПАМЯТИ Блиттер работает со словами, а не с битами. Все данные выбираются, изменяются и записываются как полные 16ти битные слова. Однако, при внимательном программировании, блиттер может делать множество операций над битами. Блиттер особенно подходит для графических операций. Как пример, экран 320x200x16 организован как 4 битплана по 8000 байт в каждом. Каждый битплан содержит 200 строк по 40 байт или по 20 слов в каждой. КАНАЛЫ DMA Блиттер имеет 4 канала DMA - 3 канала источника, обозначаемые как A, B и C, и один канал - приемник, называемый D. Каждый из этих каналов имеет независимый указатель адреса, модуль, регистры данных и бит включения. Имеется также два регистра сдвига и один для маски первого и последнего слова. Все каналы используют один регистр размера операции. Указатели адреса состоят из 2 слов, называемых BLTxPTH и BLTxPTL (здесь и далее "x" обозначает имя канала A, B, C или D) Вы можете записывать указатель записью одного длинного слова по адресу старшего слова. Регистр - указатель содержит адреса в байтах. Поскольку блиттер работает только со словами, младший бит адреса игнорируется. Так как доступна только CHIP память, некоторые из старших бит тоже игнорируются. На машинах с 512К CHIP памяти игнорируются старшие 13 бит, на 1М - 12 бит и на 2М - 11 бит. ПРИМЕЧАНИЕ Будьте уверены, что вы записываете 0 во все неиспользуемые биты регистров чипсета. Эти биты могут использоваться в следующих версиях чипсета. Запись ненулевых значений может стать причиной неработоспособности программы на будущих машинах. Каждый канал DMA может быть отдельно включен или выключен с помощью бит SRCA, SRCB, SRCC и DEST в управляющем регистре BLTCON0. При выключении канал не использует циклы памяти. Кроме того, канал - источник может сохранять константу в регистре данных и использовать ее в каждом цикле. Для этого каждый из 3 каналов - источников имеет предзагружаемые регистры данных BLTxDAT Изображения в памяти хранятся в виде последовательности линий как показано на рис. 6-1 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 Рис. 6-1: Как изображения хранятся в памяти Рис. 6-1 представляет собой один битплан (1 бит цвета) Если изображение имеет, например, 16 цветов, оно будет состоять из 4 подобных битпланов и для изображения его на экране потребуется 4 операции копирования. Для запуска операции копирования необходимо указать начальный адрес (20), адрес назначения и размер блока (высота =6, ширина =7). Затем следует автоматический переброс данных, одно слово при каждом обращении к шине данных. Когда перенос завершится, блиттер сигнализирует об этом установкой флага и (или) прерыванием. ПРИМЕЧАНИЕ Операция копирования производится в памяти и может и не изменять память, используемую в данный момент экранную память. Копирование данных выполняется в виде прямоугольника из слов, имеющего высоту и ширину. Все 4 канала DMA используют один регистр размера, называемый BLTSIZE, содержащий ширину и высоту. Ширина имеет значение от 1 до 64 слов (16-1024 бит) Высота имеет значение 1 - 1024 линий. Ширина хранится в нижних 6 битах регистра BLTSIZE. Если они содержат 0, то используется ширина 64 слова. Высота хранится в 10ти старших битах регистра, 0 обозначает 1024 линии. Итак, максимально возможный блит имеет размер 1024x1024 пикселя. Но поскольку операции сдвига и маски требуют выборка одного дополнительного слова, практически максимальная ширина равна 1008 пикселей. Блиттер имеет так называемые модули, для работы с изображениями, меньшими, чем целый экран. Все 4 канала имеют 16ти битный регистр модуля, называемый BLTxMOD. После выборки (записи) каждого слова регистр указателя адреса увеличивается на 2 байта (1 слово) После завершения каждого ряда к указателям адреса прибавляется значение модуля со знаком. (Длина ряда определяется регистром BLTSIZE) ПРИМЕЧАНИЕ Модуль задается в байтах, а не в словах. Но, поскольку блиттер может работать только со словами, младший бит игнорируется. Значение модуля может быть отрицательным. Это может использоваться для многократного повтора строк. Например, возьмем битплан 320х200 и скопируем в его позицию, начинающуюся с 13й строки, 12го байта блок шириной 10 байт. Устанавливаем регистр адреса равным адресу битплана + 40 байт на строку * 13 + 12 байт, ширину 5 слов (10 байт). В конце каждой строки нам надо пропустить 30 байт для того, чтобы попасть в 12й столбец следующей строки, следовательно модуль = 30. В общем случае ширина (в словах) * 2 плюс модуль должно быть равно полной ширине битплана, содержащего изображение. РИС. 6-2: Вычисление BLTxPTR и BLTxMOD ПРИМЕЧАНИЕ Блиттер может использоваться и для обработки линейных областей за счет установки горизонтального или вертикального размера = 1 Поскольку у каждого канала DMA имеется свой собственный регистр модуля, данные могут перемещаться между битпланами различных размеров. ГЕНЕРАТОР ФУНКЦИЙ Для получения конечного результата блиттер может объединять данные из трех источников 258-ю различными способами. Эти источники могут быть битпланами из трех разных изображений и над ними может производиться любая логическая операция. Для 3 бит (по одному из каждого источника) существует 8 различных комбинаций, каждой из которых должно соответствовать значение приемника 0 или 1. Это может быть отображено в таблице истинностей как показано ниже. В ней изображены 3 источника и возможные значения каждого бита для всех них. A B C D позиция BLTCON0 MINTERM 0 0 0 ? 0 abc 0 0 1 ? 1 abC 0 1 0 ? 2 aBc 0 1 1 ? 3 aBC 1 0 0 ? 4 Abc 1 0 1 ? 5 AbC 1 1 0 ? 6 ABc 1 1 1 ? 7 ABC Эта информация собирается в управляющий байт LF, находящийся в регистре BLTCON0 и программирует блиттер для выполнения одной из 256ти возможных логических операций при трех источниках. Для вычисления байта LF надо заполнить таблицу истинностей желаемыми значениями для D и прочитать получившееся значение. Например, если мы хотим установить бит в приемнике, если соответствующий бит источника А = 1 или бит B = 1 то заполним последние 4 строки таблицы (потому что установлен А) и заполним 3ю, 4ю, 7ю и 8ю строку (потому что установлен B), а все остальные = 0, потому что ни А ни В не установлен. Получившееся значение 11111100 или $FC и есть байт LF. Еще один пример. Байт LF равный $80 (%1000 0000) включает бит в приемнике только, если соответствующие биты всех трех источников были включены (ABC =1, бит 7 =1). Все другие точки, для других комбинаций бит будут 0. Это потому что биты 0-6 в байте LF, которые определяют вывод для этих ситуаций, равны 0. КОНСТРУИРОВАНИЕ БАЙТА LF С ПОМОЩЬЮ МИНИТЕРМОВ Еще один подход к конструированию байта LF это использование логических уравнений. Каждой из строк в таблице истинностей соответствует минитерм, состоящий из значений бит A, B и C. Например, первый минитерм обычно записывается как abc т.е. "не A, не B и не C", последний записывается как АВС. ПРИМЕЧАНИЕ Два условия, идущие подряд соответствуют операции AND, а два условия, разделенные знаком "+" - операции OR. AND имеет больший приоритет, т. е. AB + BC равно (AB) + (BC). Любая функция может быть записана как сумма минитерм. Если мы хотим вычислить функцию в которой D =1 если бит А установлен, а бит С очищен _ или бит В установлен, мы можем записать это уравнение как АС+В : "А и не С или В". Т.к. "1 и А" равно А: D = Ac + B D = A(1)c + (1)B(1) Т.к. сумма A or a истина (1 = A + a), и подобным образом для В и С, мы можем расширить это равенство так: D = A(1)c + (1)B(1) D=A(B+b)c+(A+a)b(C+c) D=ABc+Abc+AB(C+c)+aB(C+c) D=ABc+Abc+ABC+ABc+aBC+aBc После исключения повторений, у нас получилось пять минитерм: Ac+B=ABc+Abc+ABC+aBC+aBc которые соответствуют битам BLTCON0 - 6, 4, 7, 3, and 2. Эти биты включаются, а остальные - выключаются. Широкий диапазон логических операций позволяет выполнять некоторые сложные операции небольшим количеством операций блиттера. Например, вы можете накладывать изображение автомобиля на существующее изображение здания. Для создания этого эффекта требуются изображения автомобиля, здания и маски автомобиля, содержащей включенные биты в непрозрачных частях автомобиля. Эта маска может также быть использована в качестве тени. ПРИМЕЧАНИЕ Для маски автомобиля необходим только один битплан, несмотря на глубину фонового изображения. Она используется на каждом битплане заднего плана. Для анимации автомобиля сначала сохраните задний план там, где будет размещаться автомобиль, затем скопируйте автомобиль на его место. Картинка готова для изображения. Для создания следующего кадра восстановите старый задний план, сохраните задний план под местом нового размещения автомобиля и перерисуйте автомобиль. Все это выполняется раздельными операциями блиттера. Эта технология работает лучше при использовании синхронизации с лучем или двойной буферизации. Для временного сохранения заднего плана скопируйте квадрат заднего плана (например из канала А) в буфер (канал D). В этом случае функция, используемая блиттером будет A=D - стандартная функция копирования. По табл 6-1 получаем код LF для этой функции $F0. Для рисования автомобиля будем использовать канал A для выборки маски, канал B для выборки данных автомобиля, канал C для выборки заднего плана и канал D для записи нового изображения. При блите автомобиля на задний план мы должны использовать функцию, которая если бит в маске (выбираемой через канал A) включен, пересылает данные для автомобиля (из канала B), а если выключен, то пересылает тот же самый задний план (из канала C). Эта функция, называемая наложением по маске (cookie-cut) : AB+aC имеет код LF = $CA Для восстановления заднего плана используется функция копирования A=D ($F0) Если выбудете сдвигать данные и маску в новое место и повторять эти 3 шага снова и снова, автомобиль будет ехать перед задним планом (зданиями) ПРИМЕЧАНИЕ Это не самый эффективный применяемый метод анимации, но наложение по маске используется часто. Табл. 6-1 показывает некоторые наиболее употребляемые функции и их значения. Табл. 6-1: Список минитерм Логическое BLTCON0 Логическое BLTCON0 уравнение код LF Уравнение Код LF D = A $F0 D = AB $C0 D = a $0F D = Ab $30 D = B $CC D = aB $0C D = b $33 D = ab $03 D = C $AA D = BC $88 D = c $55 D = Bc $44 D = AC $A0 D = bC $22 D = Ac $50 D = ac $11 D = aC $0A D = A+b $F3 D = ac $05 D = a+b $3F D = A+B $FC D = A+c $FS D = a+B $CF D = a+c $5F D = A+C $FA D = B+c $DD D = a+C $AF D = b+c $77 D = B+C $EE D = AB+aC $CA D = b+C $BB КОНСТРУИРОВАНИЕ БАЙТА LF С ПОМОЩЬЮ ДИАГРАММЫ ВЕННА Другой путь создания функций это использование диаграммы Венна: рис. 6-3: Диаграмма Венна 1. Для создания функции D=A выберите только те минитермы, которые входят в круг A на диаграмме. Это минитермы 7, 6, 5 и 4. При записи 1 в позиции выбранных минитерм и 0 во все остальные позиции получаем следующие значения: Номер минитерма 7 6 5 4 3 2 1 0 Выбранные минитермы 1 1 1 1 0 0 0 0 --------------- F 0 равно $F0 2. Для создания функции, комбинирующей 2 источника используйте только те минитермы, которые находятся в области пересечения двух кругов. Например, для комбинации "A и B", общая область кругов A и B содержит минитермы 7 и 6. Номер минитерма 7 6 5 4 3 2 1 0 Выбранные минитермы 1 1 0 0 0 0 0 0 --------------- C 0 равно $C0 3. Для использования инверсных функций или операции "не" для одного из исходников, например "а", используйте минитермы не входящие в круг A. Для этого примера мы имеем минитермы 0, 1, 2 и 3 Номер минитерма 7 6 5 4 3 2 1 0 Выбранные минитермы 0 0 0 0 1 1 1 1 --------------- 0 F равно $0F 4. Для комбинации минитерм операцией "или", выполните операцию "или" над результатами операций "и". Например, отношение AB+BC вычисляется так: Номер минитерма 7 6 5 4 3 2 1 0 AB 1 1 0 0 0 0 0 0 BC 1 0 0 0 1 0 0 0 --------------- AB+BC 1 1 0 0 1 0 0 0 --------------- C 8 равно $C8 СДВИГИ И МАСКИ До настоящего времени мы использовали блиттер только для перемещения слов в памяти и объединения их логическими операциями. Это достаточно для перемещения графических изображений с точностью до 16 пикселей, т.к. картинка остается в той же самой позиции относительно начала слова. Если наше изображение автомобиля начинается со второго пикселя слева от начала слова, мы можем легко изобразить это на экране в любой позиции, где начало изображения находится в 2х пикселях от начала слова. Но часто необходимо изображать картинку с точностью до пикселя. Для этого каналы A и B имеют регистр сдвига, позволяющий сдвигать изображение на 1 - 15 пикселей. Операция сдвига полностью независима - она не требует дополнительного времени на выполнение, т.е. в отличие от 68000, блит со сдвигом выполняется столько-же времени, сколько и без сдвига. Сдвиг обычно выполняется вправо. Но если данные перемещается вправо, что выдвигается слева? Для первого слова блита - нули, для каждого последующего слова этого же блита, данные выброшенные из предыдущего слова Значение сдвига для канала А устанавливается битами 15 - 12 в регистре BLTCON0, для канала B - битами 15 - 12 регистра BLTCON1. Для большинства операций, значение сдвига будет одинаковым для обоих регистров. Сдвиги более чем на пятнадцать бит, осуществляются увеличением регистра - указателя приемника. Например, сдвиг на 100 бит осуществляется перемещением указателя приемника на 100/16 или 6 слов (12 байт), и сдвигом вправо на величину остатка (4 бита). Например, мы делаем блит, шириной три слова, высотой два слова, сдвинутый вправо на 4 бита методом прямого копирования A=D. Первое слово, записываемое в D - первое слово выбранное из A, смещенное вправо на четыре бита с нулями с левой стороны. Второе перемещенное слово будет смещенное на 4 бита второе слово, в котором левые 4 бита заполнены данными, выдвинутыми за пределы первого слова. Первое слово второй строки будет также сдвинуто на 4 бита, но его левые биты будут содержать данные, выдвинутые из последнего слова первой строки, и так далее до окончания блита. В результате, мы получаем нули слева первого слова первой строки. На всех других строках первые биты будут заполнены тем, что блиттер переместил с конца предыдущей строки. Для большинства программ это нежелательно. Поэтому блиттер может маскировать первое и последнее слово каждой строки проходящей через канал DMA. Таким образом, можно вырезать прямоугольные данные чьи правые и левые края находятся между границами слов. Для этого существуют два регистра, которые называются BLTAFWM и BLTALWM, для маскирования соответственно первого и последнего слова. Когда маски не используются, они должны содержать значение $FFFF. ПРИМЕЧАНИЕ Текстовые фонты на Амиге хранятся в виде упакованного битмапа. Отдельные символы извлекаются из фонта с помощью блиттера, маскирующего ненужные биты. Затем символ устанавливается в любую позицию, сдвигаясь в соответствующую позицию. Эти маски накладываются по операции "и" на исходные данные перед тем, как используется сдвиг. Только при наличии 1 в маске первого слова бит источника будет появляться в логической операции. Первое слово каждой строки накладывается по "и" с содержимым BLTAFWM, а последнее слово с содержимым BLTALWM. Если ширина строки - одиночное слово, то используются одновременно обе маски Маски также используются для извлечения определенного диапазона "столбцов". Например, имеется прямоугольник, содержащий текст и графику, шириной 23 пикселя. Левая граница прямоугольника - крайний левый бит битмапа, который имеет ширину два слова. Мы хотим разместить этот прямоугольник начиная с 5го пикселя в битмапе 320х200 без нарушения графики снаружи прямоугольника. |_________Исходный битмап, шириной 2 слова_____| | | |___ Вырезаем 23-бита _____| | | | | |__16ти битовое слово__| | | | | | | |______________________|_______|_______________| | | Источник | 00000000 00000000 00000000 00000000 | DMA B | 11111111 11111111 11111111 11111111 | | 10101010 01010101 10101010 01010101 | |______________________________________________| | | | | * \|/ \|/ \|/ \|/ ____V___________V_____ ___V___________V_____ | | | | Маска на | 11111111 11111111 | |11111110 00000000 | DMA A | Первое слово маски | | Второе слово маски | |______________________| |_____________________| | | | | _|_ _|_ \|/ \|/ \|/\|/ ____V____________V__________V__V______________ Конечное | | изображение | 00000000 00000000 00000001 11111111 | DMA D | 11111111 11111111 11111111 11111111 | (указатель | 10101010 01010101 10101011 11111111 | туда же, что |______________________________________________| и DMA C) ^ ^ ^ ^ ___ ___ ___ /|\ /|\ /|\ /|\ | | | | | | | ____|____________|_________|___|_____|___|___| ** изображение | | перед блитом | 11111111 11111111 11111111 11111111 | DMA C | 11111111 11111111 11111111 11111111 | (будет | 11111111 11111111 11111111 11111111 | переписано) |______________________________________________| * Источник проходит через те биты маски, которые равны 1, через нулевые биты проходит исходное изображение. ** Исходное изображение не меняется там, где маска 0. Рис. 6-4: Вырезание диапазона столбцов Для этого мы указываем канал B на битмап, содержащий исходное изображение, и каналы D и С на битмап экрана. Используем значение сдвига 5. Задаем ширину блита 2 слова. Нам нужна простая операция копирования, за исключением того, что мы хотим оставить нетронутыми первые пять бит первого слова, и последние четыре бита ( 2 * 16 - 23 - 5) последнего слова. На помощь приходит канал A. Мы загружаем в регистр данных канала А $FFFF и используем маску первого слова со старшими пятью битами равными 0 ($07FF) и маску последнего слова с младшими четырьмя битами равными 0 ($FFF0). Канал А DMA не включается, а включаются только каналы B, C, и D, так как мы хотим использовать канал А в качестве простой маски строки. Данные из канала B (источника) передаются там, где канал А = 1 (минитерм AB), а там, где канал А = 0 передаются биты исходного изображения (минитерм aC). В результате у нас получилась классическая функция наложения по маске = AB+aC или $CA. ПРИМЕЧАНИЕ Хотя канал А отключается, мы используем его в нашей логической функции и предзагружаем регистр данных. Отключение канала просто выключает выборку памяти для этого канала, все другие операции выполняются, только используется постоянное значение сохраненное в регистре данных этого канала. ПРИМЕЧАНИЕ Убедитесь что вы загрузили регистры данных блиттера после установки значения сдвига в BLTCON0/BLTCON1, так как загрузка регистров данных перед регистрами сдвига приводит к непредсказуемым результатам. Например, если последний раз, когда использовался сдвиг, BSHIFT был равен "4", и происходит загрузка байта, равного 1, а затем BSH1 изменяется на "2", в результате этого BDATA будет содержать "1<<4", а не "1<<2". Процесс загрузки регистров данных порождает сдвиг данных на значение BSH. РЕЖИМ УБЫВАНИЯ Cтандартное копирование памяти, используя блиттер работает прекрасно, если источник не накладывается на приемник. Но если мы хотим переместить изображение на одну строку вниз (по увеличению адресов ), то сталкиваемся с проблемой - вторая строка затирается прежде чем мы ее скопировали! Блиттер имеет специальный режим, называемый убывающим режимом, который решает эту проблему. Режим Убывания включается установки бита в BLTCON1 (называемый BLITREVERSE). При использовании режима убывания указатели адреса будут уменьшаться на два байта, а не увеличиваться. Значения модуля будут вычитаться, а не добавляться. Сдвиги - будут влево, а не вправо, маска первого слова будет маскировать последнее слово в строке (являющееся одновременно первым выбранным словом), и маска последнего слова будет маскировать первое слово в строке. Итак, для стандартного копирования памяти, единственное различие в установке регистров блиттера (без сдвиги и наложения маски) то, что регистры указателя адреса должны указывать на последнее слово в блоке, а не на первое слово. Значения модуля, размер, и другие параметры должны быть те же самые. ПРИМЕЧАНИЕ Это отличается от предекрементного и постинкрементного режимов в 68000, где адресный регистр будет инициализироваться для указания на слово, расположенное после последнего слова, а не на последнее слово. Режим Убывания также необходим для закраски области, которая будет описываться позже КОПИРОВАНИЕ ПРОИЗВОЛЬНЫХ ОБЛАСТЕЙ Одно из наиболее общих применений блиттера это перемещение произвольных прямоугольных данных с битплана на битплан, или в различных позициях внутри битплана. Эти области обычно имеют произвольные координатах, кроме того необходимы смещение и наложение маски. Все это может создать осложнения. Для полного понимания этого раздела может потребоваться неоднократное чтение и экспериментирование Исходное изображение, занимающее два слова после сдвига может занимать три слова. Например, наш прямоугольник, шириной 23 пикселя, при перемещении на 12 бит, будет занимать три слова. Точно также, изображение, занимающее три слова может занимать два при применении определенных сдвигов. Учитывая эти обстоятельства, размер в регистре BLTSIZE должен быть установлен на большее из двух возможных значений. Для маскировки нежелательных бит должно применяться соответствующее наложение маски Ниже изложены некоторые общие принципы для копирования произвольной области 1. Используйте выключенный канал А, предзагруженный данными, соответствующей маской и значениями сдвига, в качестве канала маски, канал B для выборки исходных данных, а канал С для выборки данных приемника. Канал D используется для записи результата. Функция, используемая при копировании, обычно наложение по маске ($CA). 2. При сдвиге, используйте режим возрастания если биты сдвигаются вправо и режим убывания, если биты сдвигаются влево ПРИМЕЧАНИЕ Сдвиги считаются относительно крайнего левого бита слова 3. Если источник и приемник перекрываются, используйте режим возрастания если приемник имеет более низкий адрес в памяти (выше на экране ) и режим убывания если наоборот 4. Если источник занимает больше слов чем приемник, используйте одинаковые значения сдвига для канала А и канала B и устанавливайте первое и последнее слово маски так, чтобы они маскировали данные источника B. 5. Если приемник занимает больше слов чем источник, используйте значение сдвига нуль для канала А и установите маски первого и последнего слова так, чтобы они маскировали данные приемника D. 6. Если источник и приемник занимают одинаковое число слов, используйте канал А чтобы маскировать или источник, как в 4, или приемник, как в 5. ПРИМЕЧАНИЕ Условия 2 и 3 могут быть противоречивы если, например, вы пробуете перемещать изображение на один пиксель вниз и направо. В этом случае, мы должны будем использовать режим убывания, чтобы наш приемник не перезаписался поверх источника прежде, чем мы используем источник, но в тоже время мы должны использовать режим возрастания для сдвига вправо. В некоторых ситуациях, можно обойти пункт 2 с помощью умного наложения маски. Но иногда одного наложения маски первого или последнего слова может быть не достаточно; иногда необходимо маскировать больше чем 16 бит на одном или другом конце. В этом случае маска для одной строки строится в памяти и включается канал А для выборки этой маски. При установке модуля 'минус' ширина маски, маска будет постоянно выбираться для каждой следующей строки. РЕЖИМ ЗАЛИВКИ Кроме копирования данных, блиттер может одновременно выполнять операцию заливки во время копирования. Операция заливки имеет только одно ограничение - заполняемая область должна быть определена выводом нетекстурированных линий с одним пикселем на каждой горизонтальной строке. Для этого существует специальный режим рисования линии. Можно использовать стандартное копирование или любую другую операцию, поскольку заливка происходит после всех сдвигов, масок и логической комбинации источников. Должен использоваться режим убывания. В регистре BLTCON1 установите бит заливки по OR (бит. 3 ) или заливки по XOR (бит. 4 ) Режим OR заполняет пустые промежутки между пикселами в строке, оставляя границы неповрежденными. Режим XOR заполняет пустые промежутки между пикселами, оставляя пиксели правой границы и удаляя пиксели левой границы. Заливка по XOR выдает заполненные изображения на один пиксель уже, чем тот же самый шаблон, заполненный по OR. Например, образец: 00100100-00011000 Залитый по OR будет: 00111100-00011000 А залитый по XOR будет 00011100-00001000 (Заливка всегда выполняется над полными словами). Есть еще один бит (FILL_CARRYIN - бит 3 в BLTCON1) который инвертирует режим заливки, т.е. заливка происходит вне контура. Вышеупомянутый пример, залитый по OR будет 11100111-11111111 А залитый по XOR будет 11100011-11110111 ДО ПОСЛЕ ____________________ ___________________ | | | | | 1 1 1 1 | | 11111 11111 | | 1 1 1 1 | | 11111 11111 | | 1 1 1 1 | | 1111 1111 | | 1 1 1 1 | | 111 111 | | 11 11 | | 11 11 | | 1 1 1 1 | | 111 111 | | 1 1 1 1 | | 1111 1111 | | 1 1 1 1 | | 11111 11111 | |____________________| |___________________| Рис. 6-5: Использование выключенного бита FCI Если бит FCI - 1, а не 0, заливка происходит снаружи контура. ДО ПОСЛЕ ____________________ ___________________ | | | | | 1 1 1 1 | |111 1111111 11| | 1 1 1 1 | |111 11111111 11| | 1 1 1 1 | |1111 111111111 11| | 1 1 1 1 | |11111 1111111111 11| | 11 11 | |1111111111111111111| | 1 1 1 1 | |11111 1111111111 11| | 1 1 1 1 | |1111 111111111 11| | 1 1 1 1 | |111 11111111 11| |____________________| |___________________| Рис. 6-6: Использование включенного бита FCI Если вы хотите получить очень острую вершину с одиночной точкой, должен использоваться режим XOR. Рисунок 6-7 показывает как получается одиночная точка при использовании режима XOR. ДО ПОСЛЕ ЗАЛИВКИ ПО XOR ____________________ ___________________ | | | | | 1 1 1 1 | | 1111 1111 | | 1 1 1 1 | | 111 111 | | 1 1 1 1 | | 11 11 | | 11 11 | | 1 1 | | 1 1 1 1 | | 11 11 | | 1 1 1 1 | | 111 111 | | 1 1 1 1 | | 1111 1111 | |____________________| |___________________| Рис. 6-7: Заливка по XOR Блиттер использует бит FCI как начальное значение пикселя для заливаемой строки. Для каждой встреченной "1" в исходном изображении этот блиттер изменяет состояние этого бита с 0 на 1 и наоборот и продолжает заливать приемник, используя содержимое этого бита. ФЛАГ "БЛИТТЕР ЗАКОНЧИЛ" Когда производится запись в регистр BLTSIZE, блиттер начинает работать. При этом процессор не останавливается и работает параллельно, что обеспечивает производительность Амиги. Однако, это требует соблюдения особой осторожности, поскольку повторный запуск блиттера, когда он еще не завершил предыдущую работу может вызвать сбой системы. Флаг "Блиттер закончил", также называемый флагом занятости блиттера расположен в регистре DMACONR и называется DMAF BLTDONE. Этот флаг установлен, когда блиттер находится в рабочем состоянии. ПРИМЕЧАНИЕ Если блиттер только начал работать, но доступ к памяти был закрыт, например, из-за выборки данных для экрана, этот бит может быть еще не установлен. С другой стороны, процессор может работать с полным быстродействием в Fast Ram или во встроенном кэше. Решение проблемы состoит в том, что можно прочитать chip память или регистр чипсета перед тестированием бита занятости. Это делается так: btst.b #DMAB_BLTDONE-8,DMACONR(a1) btst.b #DMAB_BLTDONE-8,DMACONR(a1) Где a1 содержит адрес чипсета. Первый "тест" бита занятости блиттера может возвратить неправильный результат, а второй точно даст правильный результат. ПРИМЕЧАНИЕ Начиная с Fat Agnus бит занятости блиттера устанавливается сразу после записи в регистр BLTSIZE, а не при получении блиттером первого цикла DMA. Однако, не все машины используют более новые чипы, так что лучше всего полагаться на вышеупомянутый метод тестирования. БЛИТТЕР И МНОГОЗАДАЧНОСТЬ Когда блиттер выполняет какое-либо действие, не должна производится запись ни в один из регистров блиттера. Для более подробного обсуждения доступа блиттера при работе в системе, читайте ROM Kenel Manual. В частности читайте описание функций OwnBlitter() и DisownBlitter(). Даже после выполнения функции OwnBlitter(), блиттер может еще заканчивать, так-что проверяйте флаг занятости блиттера перед первым использованием. Для этого рекомендуется использование функции WaitBlit(). Вы должны также проверять флаг занятости блиттера перед использованием результатов работы блиттера, поскольку операция может быть не закончена и данные не могут быть готовы. Это может вести к затруднениям вылавливания ошибок, потому что 68000 бывает настолько медленен, что блиттер успевает завершить операцию и проверка флага не нужна, а 68020, даже работая без кэша, может обогнать блиттер. Представим, что у нас есть подпрограмма, печатающая текст на некотором изображении. Эта подпрограмма должна выделить участок памяти для сохранения и последующего восстановления исходного изображения. На выходе из нее необходимо восстановить исходное изображение с помощью блиттера и освободить занятую память. Если память освобождается без проверки флага занятости, любой другой процесс может захватить эту память и сохранить в нее свои данные, разрушив источник, и, следовательно разрушив исходное изображение. ФЛАГ ПРЕРЫВАНИЯ Блиттер также имеет флаг прерывания, который устанавливается при окончании работы блиттера. Этот флаг, называемый INTF BLIT, может генерировать прерывания 68000, если они разрешены. Для подробностей см. главу 7 "Управление чипсетом" ФЛАГ НУЛЯ Флаг нуля блиттера - применяется для того, чтобы проверить, привела ли выбранная логическая операция к нулевому результату для всех бит приемника, даже если они не записаны из-за блокировки канала D. Эта возможность часто используется для обнаружения столкновений, выполнением логического "и" на двух исходных изображениях. Если изображения не накладываются, нулевой флаг будет давать истинный результат. Нулевой флаг действителен только после того, как блиттер завершил операцию и может быть прочитан из бита DMAF_BLTNZERO регистра DMACONR. КОНВЕЙЕРНЫЙ РЕГИСТР Блиттер выполняет большое количество операций в каждом цикле - сдвиги и наложение масок на источники, логические комбинации источников, заливка и проверка нуля выходе. Для быстрого выполнения такого множества дел блиттер имеет конвейер. Это означает что вместо того, чтобы выполнять все операции в одном цикле блиттера, операции распространяются на два цикла блиттера. (Слово "цикл" здесь используется для простоты.) Объяснение этому может выглядеть так, как будто блиттер состоит из двух последовательно соединенных чипов. Каждый цикл в первый чип приходит новый набор исходных и он начинает выполнять операции. Когда он выполнил первую половину операций над данными, то передает их во второй чип, который и заканчивает в течение следующего цикла, когда первый чип будет занят работой над следующим набором данных. Каждый набор данных обрабатывается два цикла, но новый набор данных поступает каждый цикл. Это означает то, что первые два набора исходных данных выбираются прежде, чем записаны первые результаты. Это позволяет вам, например, сдвигать битмап на расстояние до одного слова вправо, используя режим возрастания, даже если конечные данные будут перезаписывать источник перед выборкой. Табл. 6-2: Типичные последовательности циклов блиттера Использ. код из Активные BLTCON0 Каналы Последовательность циклов F A B C D A0 B0 C0 - A1 B1 C1 D0 A2 B2 C2 D1 D2 E A B C A0 B0 C0 A1 B1 C1 A2 B2 C2 D A B D A0 B0 - A1 B1 D0 A2 B2 D1 - D2 C A B A0 B0 - A1 B1 - A2 B2 B A C D A0 C0 - A1 C1 D0 A2 C2 D1 - D2 A A C A0 C0 A1 C1 A2 C2 9 A D A0 - A1 D0 A2 D1 - D2 8 A A0 - A1 - A2 7 B C D B0 C0 - - B1 C1 D0 - B2 C2 D1 - D2 6 B C B0 C0 - B1 C1 - B2 C2 5 B D B0 - - B1 D0 - B2 D1 - D2 4 B B0 - - B1 - - B2 3 C D C0 - - C1 D0 - C2 D1 - D2 2 C C0 - C1 - C2 1 D D0 - D1 - D2 0 none Примечания к таблице: o Нет закраски. o Нет мешающей активности шины. o Трех-словный blit. o Типичная операция выбирает все источники дважды, перед тем, как появляются первые результаты. Это делается с помощью внутреннего распараллеливания. Соблюдайте осторожность с возможным перекрытием исходных и конечных областей. ПРИМЕЧАНИЕ Эта таблица показывает только типичную последовательность циклов блиттера на шине. Циклы шины динамически распределяются блиттеру в зависимости от активности процессора, битпланов, других каналов DMA и других факторов. РЕЖИМ РИСОВАНИЯ ЛИНИИ Кроме всех функций, описанных выше, блиттер может рисовать линии. Режим рисования линии выбирается включением бита 0, называемого LINEMODE в регистре BLTCON1. При этом изменяется значение некоторых других битов в регистрах BLTCON0 и BLTCON1. В режиме рисования линии, блиттер может рисовать линии длинной до 1024 пикселей, различными режимами, текстурами, и специальным способом для последующей заливки. Многие регистры блиттера имеют другие значения в режиме рисования линий. Смотрите С Приложение A для более подробного описания этих регистров и их бит в режиме рисования линии. В режиме линии, блиттер рисует линию из одной указанной точки до другой, что может быть представлено в виде вектора. Направление вектора может лежать в любом из восьми октантов. (В диаграмме, используется стандартное соглашение Амиги: x увеличивается вправо, а y увеличивается вниз) Число в круглых скобках - номер октанта; другое число - это значение, которое должно помещаться в биты 2-4 в регистре BLTCON1. рис 6-8: Октанты для рисования линии (катинка отсутствует) Рисование линии основанное на октантах - упрощение, которое пользуется преимуществом симметрии между x и -x, y и -y. Следующая таблица показывает номер октанта и соответствующее значение: Таблица 6-3: BLTCON1 Коды октантов для рисования линии Код в BLTCON1 Номер октанта 0 1 1 2 1 1 1 3 1 0 1 4 0 1 0 5 0 0 0 6 1 0 0 7 Необходимо проинициализировать биты 2-4 регистра BLTCON1 согласно вышеупомянутой таблице. Затем вычисляем переменные dx и dy, берем их по модулю. Dx = abs ( x2 - x1 ) Dy = abs ( y2 - y1 ) Затем, если dx < dy, то меняем их местами. if (dx < dy) { temp = dx; dx = dy; dy = temp; } Таким образом, dx и dy устанавливаются следующим образом: dx = max(abs(x2 - x1), abs(y2 - y1)) ; dy = min(abs(x2 - x1), abs(y2 - y1)) ; Эти вычисления нормализуют линию в нулевой октант и поскольку мы уже задали блиттеру реальный октант расположения линии он имеет реальное представление о направлении линии Значение указателя канала А устанавливается как 4 * dy - 2 * dx. Если это значение отрицательно, устанавливается бит знака ( SIGNFLAG в регистре BLTCON1 ), иначе мы бит знака очищается. Регистр модуля А устанавливается равным 4 * (dy - dx) и регистр модуля B к 4 * dy. Регистр данных канала А должен предзагружаться значением $8000. Обе маски должны быть равны $FFFF, значение сдвига канала А должно быть установлено равным координате x (x1) первой точки по модулю 15. Регистр данных канала B задает образец текстуры или $FFFF для нормальной линии. Значение сдвига канала B должно быть равно начальному номеру бита в текстуре. (нуль означает последний значащий бит.) Указатели каналов C и D должны указывать на слову, содержащее первый пиксель линии; Регистры модуля каналов C и D должны быть равны ширине битплана в байтах. Биты регистра BLTCON0 SRCA, SRCC и DEST должны быть включены, бит SRCB должен быть нуль. OVFLAG должен также быть 0. Если нужен только один включенный бит на горизонтальную линию,(например для последующей заливки) бит ONEDOT регистра BLTCON1 должен быть установлен, иначе - очищен. Логические функции остаются. Канал C представляет источник, канал А - бит для установки в линии, и канал B - образец закраски. Таким образом, для рисования линии наиболее общая функция AB + AC. Чтобы рисовать линию по XOR, так чтобы ее можно было стереть повторным рисованием, можно использовать функцию ABC + AC. Размеры операции устанавливаются так: высота равна длине линии, равной dx + 1, ширина должна быть равна двум. (Регистр BLTSIZE регистр должен быть записан самым последним, после задания всех других регистров) ОБОБЩЕНИЕ ЗНАЧЕНИЙ РЕГИСТРОВ В РЕЖИМЕ РИСОВАНИЯ ЛИНИИ Вычисления: Линия рисуется из (x1 ,y1) в (x2,y2). dx = max (abs (x2 - x1), abs (y2 - y1) ) dy = min (abs (x2 - x1), abs (y2 - y1) ) Установка регистров: BLTADAT = $8000 BLTBDAT = образец текстуры линии ($FFFF нормальной линии) BLTAFWM = $FFFF BLTALWM = $FFFF BLTAMOD = 4 * (dy-dx) BLTBMOD = 4 * dy BLTCMOD = ширина битплана в байтах BLTDMOD = ширина битплана в байтах BLTAPT = (4 * dy) - (2 * dx) BLTBPT = не используется BLTCPT = слово, содержащее первый пиксель линии BLTDPT = слово, содержащее первый пиксель линии BLTCON0 биты 15-12 = x1 по модулю 15 BLTCON0 биты SRCA, SRCC, and SRCD = 1 BLTCON0 бит SRCB = 0 Режим XOR : байт LF регистра BLTCON0 = ABc + aC Норм. режим: байт LF регистра BLTCON0 = AB + aC BLTCON1 бит LINEMODE = 1 BLTCON1 бит OVFLAG = 0 BLTCON1 биты 4-2 = номер октанта по таблице BLTCON1 биты 15-12 = начальный бит для текстуры (0 = последний значащий бит) Если (((4 * dy) - (2 * dx)) < 0): то BLTCON1 бит SIGNFLAG = 1 иначе BLTCON1 бит SIGNFLAG = 0 Если нужен один пиксель на горизонтальную строку то BLTCON1 бит ONEDOT = 1 иначе BLTCON1 бит ONEDOT = 0 BLTSIZE биты 15-6 = dx + 1 BLTSIZE биты 5-0 = 2 ПРИМЕЧАНИЕ Регистр BLTSIZE устанавливается последним и запускает блиттер. БЫСТРОДЕЙСТВИЕ БЛИТТЕРА Быстродействие блиттера зависит от того, сколько каналов DMA активно. допускаются. Вы можете использовать канал DMA как константу, но если он не включен, это не увеличивает затраты времени. Минимальный цикл блиттера - четыре тика; максимальный - восемь тиков. Использование регистра А включается в эти значения. Использование регистра B всегда добавляет два тика к циклу блиттера. Использование или C или D не прибавляет времени, но использование обоих добавляет еще два тика. Таким образом, цикл копирования, использующий A и D, занимает четыре тика на цикл; цикл копирования, использующий B и D занимает шесть тиков на цикл, и в общем случае копирование, использующее B, C, и D занимает восемь тиков на цикл. В режиме рисования линии, каждый пиксель расходует восемь тиков. Скорость системных часов для Амиг с NTSC - 7.16 мегагерц (для Амиг с PAL - 7.09 мегагерц). Блиттер пользуется системными часами. Для вычисления общего времени работы блиттера в микросекундах, исключая установку регистров и конкуренцию между DMA, используйте уравнение (для NTSC): n * H * W t = --------- 7.16 Для PAL: n * H * W t = --------- 7.09 Где t - время в микросекундах, n - число тиков на цикл, и H и W - высота и ширина области (в словах). Например, для копирования одного битплана 320 на 200 на другой битплан, мы можем использовать каналы A и D. Это потребует четырех тиков на цикл блиттера, для всего битплана: 4 * 200 * 20 ------------ = 2235 микросекунд. 7.16 Эти вычисления не принимают во внимание время, требуемое на вычисление и загрузку регистров блиттера и конкуренцию между DMA ОПЕРАЦИИ БЛИТТЕРА И СИСТЕМНЫЕ DMA Операции блиттера воздействуют на производительность остальной системы. Следующие разделы объясняют как воздействуют на производительность системы приоритет прямого доступа блиттера в память, распределение времени DMA, разделение шины между 68000 и дисплейным железом, операции блиттера и коппера, и различные размеры экранов. Блиттер выполняет различную выборку данных, операции изменения и сохранения с помощью DMA. Он использует доступ к памяти совместно с другими устройствами в системе. Каждое устройство, которое обращается к памяти имеет уровень приоритета, который указывает важность этого устройства относительно других устройств. DMA диска, звука, экрана, и спрайтов имеют самый высокий уровень приоритета. При определенных обстоятельствах, DMA экрана имеет приоритет над DMA спрайтов. Каждому из этих четырех устройств отведено некоторое время в течение каждого горизонтального хода видео луча. Если устройство не запрашивает один из отведенных слотов времени, слот открывается для других устройств. Эти устройства имеют первый приоритет потому что пропуск циклов DMA может вызывать потерю данных, шум в при выводе звука, или прерывание изображения экрана. Коппер имеет приоритет чуть ниже, потому что он должен выполнять операции синхронно с видео лучем в одно и то же время в каждом кадре изображения Самые низкие приоритеты имеют блиттер и 68000, в таком порядке. Блиттеру дают более высокий приоритет потому что он выполняет операции с экраном быстрее 68000 В течение горизонтальной строки развертки (примерно 63 микросекунды), выполняются 227.5 циклов доступа к памяти. Один цикл памяти - приблизительно 280ns. Общее количество циклов 227.5 на горизонтальную строку включает и время изображения и время, когда изображение не выводится. Из этого общего времени, 226 циклов доступны для распределения между различными устройствами, которые нуждаются в доступе к памяти. Распределение слота времени на горизонтальную строку - 4 цикла для регенерации памяти 3 цикла для дискового DMA 4 цикла для звукового DMA (2 байта на канал ) 16 циклов для DMA спрайтов (2 слова на канал) 80 циклов для DMA битпланов (четные или нечетные слоты согласно используемому размеру дисплея ) Рисунок 6-9 показывает распределение циклов на одной полной горизонтальной строке развертки |
РИС. 6-9: Распределение времени DMA. 68000 использований только четные циклы доступа к памяти. 68000 тратит приблизительно половину полного времени выполнения команды на выполнение операции, а другую половину на доступ к памяти. Следовательно, распределение альтернативных циклов памяти к 68000 заставляет их появляться для 68000 и он имеет доступ к памяти все время, что позволяет ему выполняться с максимальным быстродействием. Некоторые команды 68000 совершенно не соответствуют распределению четных циклов служат причиной пропуска циклов. Если цикл пропущен, 68000 должен ждать прихода следующего цикла. Однако, больше всего команд не приводят к пропуску циклов, и 68000 выполняется с максимальным быстродействием большую часть времени, если только не вмешивается блиттер. Рисунок 6-10 показывает нормальный цикл 68000. ПРИМЕЧАНИЕ Команда TAS 68000 не должна никогда использоваться в Амиге; неделимый цикл чтения-изменения-записи, который используется только в этой команде не будет работать в слоте доступа к памяти DMA. ------------------------------------------------------------- | <---- Средний цикл 68000 ----> | | | | <--- часть ---> | <--- часть ---> | | внутренних | доступа | | операций | к памяти | | | | | нечетный цикл | четный цикл | | используется | доступен | | другими устройствами | 68000 | ------------------------------------------------------------- Рис. 6-10: Нормальный цикл 68000 Если дисплей содержит четыре или меньше битпланов с низкой разрешающей способностью, 68000 предоставляются все циклы памяти (если он готов к запросу о предоставлении цикла и имеет наивысший приоритет в данный момент времени). Однако, если экран содержит больше чем четыре битплана, DMA битпланов будет захватывать циклы из времени, предназначенного для 68000 во время изображения экрана. Во время изображения экрана с шестью битпланами (низкое разрешение, 320 пикселей шириной), 160 слотов будут отобраны у процессора для каждой горизонтальной строки. Как вы можете видеть на Рисунке 6-11, DMA битпланов захватывает 50 процентов открытых слотов которые процессор мог бы использовать если изображались бы только четыре битплана. T -TIMING CYCLE- T+7 + * + * --------------------------------- | | 4 | 6 | 2 | | 3 | 5 | 1 | --------------------------------- Рис. 6-11: Распределение слотов при 4х битплановом экране Если включен экран с четырьмя битпланами в высоком разрешении (640 пикселей шириной), DMA битпланов нуждается во всех доступных слотах времени в течение изображения дисплея для того, чтобы выбирать 40 слов данных для каждой строки (40х4 = 160 слотов). Это блокирует доступ 68000 (также как блиттер или Copper) к памяти во время формирования изображения, за исключением периодов горизонтального и вертикального гашения. T -TIMING CYCLE- T+7 --------------------------------- | 4 | 2 | 3 | 1 | 4 | 2 | 3 | 1 | --------------------------------- Рис. 6-12: Распределение слотов в высоком разрешении Каждая горизонтальная строка в нормальном, полноразмерном экране содержит 320 пикселей в низком разрешении или 640 пикселей в высоком разрешении. Таким образом, во время изображения горизонтальной строки будут выбираться 20 или 40 слов. Если вы хотите скроллировать экран, необходимо выбирать на одно слово больше. Размер экрана может быть изменен (см. Главу 3, "Экраны"), при этом DMA битпланов берет старшинство над DMA спрайтов. Как показано на Рисунке 6-9, широкие экраны, а тем более со скроллированием могут выключать один или несколько спрайтов, начиная со спрайтов с более высокими номерами. Как сказано выше, при захвате циклов DMA блиттер обычно имеет более высокий приоритет чем процессор. Но в определенных случаях, блиттер и 68000 могут совместно использовать циклы шины. Если блиттеру разрешено, то он будет захватывать все доступные циклы памяти. Дисплей, диск, и звук имеют старшинство над блиттером, так что они не блокируются им при доступе к шине. В зависимости от установки бита режима работы DMA блиттера, который обычно называется "гадкий блиттер", процессору может быть блокирован доступ к шине. Этот бит называется DMAF BLITHOG и находится в регистре DMACON. Если бит DMAF_BLITHOG - 1, блиттер будет захватывать шину каждый доступный цикл памяти. Потенциально это могут быть все циклы. Если бит DMAF_BLITHOG - 0, контроллер DMA будет отслеживать запросы 68000 на использование шины. Если 68000 будет неудовлетворен три раза подряд, у блиттера будет отбираться шина для одного цикла процессора. БЛОК-СХЕМА БЛИТТЕРА Рисунок 6-13 показывает основные стандартные блоки для одного бита в 16ти битной операции блиттера. Механизм рисования линий не показан. * В верхнем левом углу показывается как накладываются маски первого и последнего слова на данные, входящие из источника А. * Сдвигающее устройство (вверху справа и в центре слева) иллюстрирует как 16 битов данных помещаются в определенной позиции внутри 32х битного регистра, основываясь на значениях сдвига каналов А или B, заданных в регистрах BLTCON0 и BLTCON1. * Генератор минитермов (в центре справа) иллюстрирует как биты выбора минитерма разрешают или запрещают использование данного минитерма. * Рисунок показывает как операция заливки работает на данных, сгенерированных комбинациями минитермов. Операции заливки могут выполняться одновременно с другими логическими операциями. * В нижней части рисунка показывает что данные сгенерированные для адресата могут быть не записаны в приемник, с помощью одного из служебных битов блиттера. * На этой диаграмме не показана логика для активизации флага нуля, которая проверяет каждый бит сгенерированный для приемника. Если хоть один сгенерированный бит равен 1, флаг нуля показывает, что на выходе была хотя бы одна единичка. СМ. РИСУНОК 6-13: Блок-схема Блиттера КЛЮЧЕВЫЕ ТОЧКИ БЛИТТЕРА Это - список некоторых ключевых моментов, которые нужно поминать при программировании блиттера. * BLTSIZE записывается самым последним; запись в этот регистр запускает блиттер. * Модули и указатели задаются в байтах; ширина задается в словах, а высота задается в пикселях. Самый младший бит всех указателей и модулей игнорируется. * Порядок операций в блиттере: наложение маски, сдвиг, логическая комбинация источников, заливка и установка флага нуля * В режиме возрастания блиттер увеличивает указатели, добавляет модули и сдвигает вправо * В режиме убывания, блиттер уменьшает указатели, вычитает модули, и сдвигает влево * Заливка работает правильно в убывающем режиме. * Проверьте состояние флага BLTDONE перед записью регистров блиттера или использованием результатов работы блиттера. * Сдвиги выполняются немедленно после загрузки. ПРИМЕР: Очистка памяти ; ; Пример использования блиттера - очистка памяти ; include 'exec/types.i' include 'hardware/custom.i' include 'hardware/dmabits.i' include 'hardware/blit.i' include 'hardware/hw examples.i" xref _custom ; ; Ждем окончания предыдущей операции блиттера ; waitblit: btst.b #DMAB_BLTDONE-8,DMACONR(a1) waitblit2: btst.b #DMAB_BLTDONE-8,DMACONR(a1) bne waitblit2 rts ; ; Эта подпрограмма использует побочный эффект в блиттере. Когда ;операция блиттера заканчивается, указатель указывает на следующее ;слово. ; Когда происходит возврат из этой подпрограммы, последняя операция ;блиттера начинается и может быть не закончена, так что убедитесь, что ;вызывали waitblit перед продолжением работы с блиттером ; A0 указатель на первое слово для очистки ; d0 - количество байт для очистки (должно быть четным) xdef clearmem clearmem: lea custom,a1 ; Указатель на регистры чипсета bsr waitblit ; Ждем окончания предыдущего блита move.l a0,BLTDPT(a1) ; Устанавливаем указатель D на место ; для очистки clr.w BLTDMOD(a1) ; Очищаем модуль D (не пропускаем байты) asr.l #1,d0 ; Получаем число слов из числа байт clr.w BLTCON1(a1) ; Нет специальных режимов move.w #DEST,BLTCON0(a1); Включаем только приемник ; ; Начинаем с маленького блита ; d0%00001010 10101010 10101010 10101010 moveq #$3f,d1 ; Кладем маску в 64 слова в d1 d1%00000000 00000000 00000000 00111111 and.w d0,d1 ;получаем количество слов не кратных 64 d1%00000000 00000000 00000000 00101010 beq dorest ;таких нет? хорошо, поехали кидать ; большие куски sub.l d1,d0 ;получаем количество слов кратных 64 d0%00001010 10101010 10101010 10000000 or.l #$40,d1 ; устанавливаем высоту 1, ширину d1 move.w d1,BLTSIZE(a1) ; поехали ; ; теперь кидаем остатки кусками по 128k ; dorest: move.w #$ffc0,d1 ; маска для старших 10 бит ;d1%00000000 00000000 11111111 11000000 and.w d0,d1 ; выделяем 10 старших бит ;d1%00000000 00000000 10101010 10000000 beq dorest2 ; если нечего кидать проверим старшее ; слово sub.l d1,d0 ; задаем размер 64х1024 ;d0%00001010 10101010 00000000 00000000 bsr waitblit ; ждем окончания предыдущего блита move.w d0,BLTSIZE(a1) ; поехали dorest2: swap d0 ; проверяем старшее слово ;d0%00000000 00000000 00001010 10101010 beq done ; если пусто, то выход. clr.w d1 ; задаем размер 64х1024 (128K) ;d1%00000000 00000000 00000000 00000000 keepon: bsr waitblit ; ждем move.w d1,BLTSIZE(a1) ; и снова блит subq.w #1,d0 ; каждый блит в старшем слове ; вычитает из него 1 ;d0%00000000 00000000 00001010 10101010-1 bne keepon ; до тех пор, пока старшее слово не 0. done: rts ; закончили. блиттер еще работает. end ПРИМЕР: Простая линия ; ; Этот пример использует режим рисования линии. Рисуется ; сплошная линия с простым наложением по 'или' ; ; На входе: d0=x1 dl=y1 d2=x2 d3=y2 d4=width a0=aptr ; include 'exec/types.i' include 'hardware/custom.i' include 'hardware/blit.i' include 'hardware/dmabits.i' include 'hardware/hw_examples.i' ; xref _custom ; xdef simpleline ; ; simpleline: lea custom,a1 ; указатель на базу чипсета sub.w d0,d2 ; вычисляем dx bmi xneg ; если <0 октант один из [3,4,5,6] sub.w d1,d3 ; вычисляем dy октант один из [1,2,7,8] bmi yneg ; если <0 октант один из [7,8] cmp.w d3,d2 ; cmp |dx|,|dy|октант один из [1,2] bmi ygtx ; если y>x, октант 2 moveq.l #OCTANT1+LINEMODE,d5 ; иначе октант 1 bra lineagain ; переход в общую программу ygtx: exg d2,d3 ; X должен быть > Y moveq.l #OCTANT2+LINEMODE,d5 ; мы во втором октанте bra lineagain ; и снова в общую программу. yneg: neg.w d3 ; вычисляем abs(dy) cmp.w d3,d2 ; cmp |dx|,|dy|, октант [7,8] bmi ynygtx ; если y>x, октант 7 moveq.l #OCTANT8+LINEMODE,d5 ; иначе октант 8 bra lineagain ynygtx: exg d2,d3 ; X должен быть > Y moveq.l #OCTANT7+LINEMODE,d5 ; мы в октанте 7 bra lineagain xneg: neg.w d2 ; dx <0 ! октант [3,4,5,6] sub.w d1,d3 ; вычисляем dy bmi xyneg ; если <0 октант один из [5,6] cmp.w d3,d2 ; иначе один из [3,4] bmi xnygtx ; если y>x, октант 3 moveq.l #OCTANT4+LINEMODE,d5 ; иначе 4 bra lineagain xnygtx: exg d2,d3 ; X должен быть > Y moveq.l #OCTANT3+LINEMODE,d5 ; мы в октанте 3 bra lineagain xyneg: neg.w d3 ; y <0, октант один из [5,6] cmp.w d3,d2 ; y>x? bmi xynygtx ; если да, октант 6 moveq.l #OCTANT5+LINEMODE,d5 ; иначе октант 5 bra lineagain xynygtx: exg d2,d3 ; X должен быть > Y moveq.l #OCTANT6+LINEMODE,d5 ; мы в октанте 6 6 lineagain: mulu.w d9,d1 ; вычисляем y1 * width ror.l #4,d0 ; перемещаем верхние 4 бита в ; старшее слово add.w d0,d0 ; умножаем на 2 add.l d1,a0 ; ptr += (xl >> 3) add.w d0,a0 ; ptr += yl * width swap d0 ; получаем 4 бита xl or.w #$BFA,d0 ; объединяем по 'или' VSEA, USEC, ; USED, F=A+C lsl.w #2,d3 ; y = 4 * y add.w d2,d2 ; X = 2 * X move.w d2,d1 ; копируем lsl.w #5,d1 ; сдвигаем на 5 бит add.w #$42,d1 ;и прибавляем 1 к высоте, 2 к ширине btst #DMAB_BLTDONE-8,DMACONR(al) ; тест безопасности waitblit: btst #DMAB_BLTDONE-8,DMACONR(a1) ; ждем окончания блита bne waitblit move.w d3,BLTBMOD(a1) ; B mod = 4 * Y sub.w d2,d3 ext.l d3 move.l d3,BLTAPT(a1) ; A ptr = 4 * Y - 2 * X bpl lineover ; если <0 or.w #SIGNFLAG,d5 ; устанавливаем бит знака в conl lineover: move.w d0,BLTCON0(a1) ; записываем управляющие регистры move.w d5,BLTCON1(a1) move.w d4,BLTCMOD(a1) ; C mod = ширина битплана move.w d4,BLTDMOD(a1) ; D mod = ширина битплана sub.w d2,d3 move.w d3,BLTAMOD(a1) ; A mod = 4 * Y - 4 * X move.w #$8000,BLTADAT(a1) ; A data = 0x8000.html moveq.l #-1,d5 ; маски $ffff move.l d5,BLTAFWM(a1) ; ставим обе маски как одну move.l a0,BLTCPT(a1) ; Указатель на первый пиксель move.l a0,BLTDPT(a1) move.w d1,BLTSIZE(a1) ; поехали rts ; возвращаемся, блиттер еще работает. Пример: Поворот строки ; ; Здесь мы вращаем биты. программа берет одну строку растра в ;битплане и "вращает" ее в массив 16ти битных слов, устанавливая один ;бит в каждом слове массива в соответствии соответствующему биту ;растровой строки. Используется режим рисования линии. ; На входе: d0 содержит длину растровой строки в словах. D1 содержит ;номер бита, по которому будет проходить линия ( 0 ..15 ). A0 содержит ;указатель на строку данных и a1 содержит указатель на заполняемый ;массив, который должен быть размером как минимум (d0)*16 слов ; ;действие этой программы можно представить так: ;00111100 - исходная строка ;*000 0 0000 строка поворачивается на 90 градусов ;000 0 0000 d1 содержит номер бита, в данном случае 4 (вроде-бы) ;000 1 0000 d0 содержит длину, в данном случае 0.5 :) ;000 1 0000 a0 содержит начало исходной строки ;000 1 0000 a1 содержит первый байт массива - * ;000 1 0000 ;000 0 0000 ;000 0 0000 include 'exec/types.i' include 'hardware/custom.i' include 'hardware/blit.i' include 'hardware/dmabits.i' include 'hardware/hw_examples.i' xref _custom ; xdef rotatebits ; rotatebits: lea custom,a2 ; Указатель на регистры чипсета tst d0 ; если нет слов, выход beq gone lea DMACONR(a2),a3 ; запоминаем адрес dmaconr moveq.l #DMAB BLTDONE-8,d2 ; запоминаем номер бита BLTDONE btst d2,(a3) ; проверка готовности wait1: tst d2,(a3) ; еще разок. bne wait1 ; не готов? подождем moveq.l #-30,d3 ; режим линии: aptr = 4Y-2X, Y=0; X15 move.l d3,BLTAPT(a2) ; move.w #-60,BLTAMOD(a2) ; amod = 4Y-4X clr.w BLTBMOD(a2) ; bmod = 4Y move.w #2,BLTCMOD(a2) ; cmod = ширина битмапа (2) move.w #2,BLTDMOD(a2) ; то же ror.w #4,d1 ; берем 4 бита из номера бита and.w #$f000,d1 ; маскируем остальные or.w #$bca,d1 ; USEA, USEC, USED, F=AB+-AC move.w d1,BLTCON0(a2) ; сохраняем move.w #$f049,BLTCON1(a2) ; BSH=15, SGN, LINE move.w #$8000,BLTADAT(a2) ; инициализируем данные канала А move.w #$ffff,BLTAFWM(a2) ; инициализируем маски move.w #$ffff,BLTALWM(a2) move.l a1,BLTCPT(a2) ; инициализируем указатели move.l a1,BLTDPT(a2) lea BLTBDAT(a2),a4 ; Для быстрого доступа, забираем 2 lea BLTSIZE(a2),a5 ; адреса move.w #$402,d1 ; ставим bltsize; ширина-2, высота 16 move.w (a0)+,d3 ; берем следующее слово данных bra inloop ; цикл again: move.w (a0)+,d3 ; берем следующее слово данных btst d2,(a3) ; проверяем окончание блита wait2: btst d2,(a3) ; еще раз bne wait2 ; не готов, ждем inloop: move.w d3,(a4) ; кладем следующее слово в BLTBDAT ; (текстура для линии) move.w d1,(a5) ; запуск блиттера ширина-2 высота-16 subq.w #1,d0 ; это было последнее слово? bne again ; если нет, цикл gone: rts end |