Итак, уважаемые, позвольте мне представить мой туториал №1. :D
Он посвящен основам программирования графики на паскалевском ассемблере. Он предназначен для тех, кого достала тормознутость графики на пасе (а работать с графикой с его процедурами я бы не советовал - мееедленно...), кто хотел бы написать БЫСТРУЮ игру, да и для тех, кому вообще интересен асм.
Внимание: Данные эксперименты не совсем совместимы с модулем Graph, поэтому крайне нежелательно его включать.
Для использования примеров вам необходима карточка VGA, имеющая режим 320*200, TP версии 6.0 и выше, и желание разобраться.
В сегодняшней, первой части, я расскажу о том, что из себя представляет режим 320*200 8 бит, как его врубить, и как с ним работать.
Этот режим имеет номер 13 в шеснацатеричной системе счисления или 19 в десятичной. В дальнейшем 16-теричный вид будет отмечаться буквой h (Например 13h) а десятичный отмечатся не будет (19).
Немного теории:
Раз у нас 8-битный режим, то
1. На каждую ячейку(я.п.) памяти приходится по одной точке! Это просто чудесно! т.к. не рассматриваются случаи, когда в один байт картинки вмещается 2 точки (в 16ти цветных режимах), а то работа по разделению байта - просто геморой.
2.Мы можем работать с 2^8=256 цветами (в отличие от 16 в пасе)!!!!!!!!!
3. Базовый адрес памяти, начиная с которого изображение в графических режимах выводится на монитор, равен 0A000:0000h. следующие 64000(320*200) байта в данном режиме как раз и выводятся на экран.
5. Для возврата из графического режима я буду использовать текстовый режим № 3(80*25*16)
Ну так вот, для того, чтобы менять режимы будем использовать функцию BIOS установки режима:
------------------------------------------------------------------------
Установка видеорежима(прерывание 10h):
На входе:
ah=0 ; Установить режим
al = ; Номер режима
------------------------------------------------------------------------
В нашем случае:
procedure Set13h;
begin
asm
mov ah,00h ; Установить режим
mov al ,13h ; Номер режима 320*200*256цв
int 10h ; Номер прерывания
end;
end;
procedure Close13h;
begin
asm
mov ah,00h ; Установить режим
mov al ,03h ; Текстовый режим 80*25*16цв
int 10h ; Номер прерывания
end;
end;
Хорошо, вот мы и попали в режим 320*200*256 - возможно, скажете вы, - но Graph использовать не рекомендуют, так что же нам здесь делать?
Ну... для начала давайте очистим экран
procedure clscr(col:byte);
begin
asm
mov ax,0A000h
mov es,ax
xor di,di
mov al,[col]
mov cx,64000
rep StosB
end;
end;
Итак, введя этот код вы получите процедуру закраски экрана.
А теперь, давайте я пасскажу о ней поподробнее...
Сегмент - это часть адреса, которая указывает от какой ячейки начинать отсчет смещения. Он имеет размер 64Кб (65536 байт).
В языках программирования используют несколько переменных, которые содержат сегменты, это cs,ds,es,ss,gs,fs. В паскале реально используются лишь первые 4.
cs - сегмент кода, обычно не трогается, ds - сегмент данных, здесь размещаются данные, после использования в паскале желательно восстанавливать. ss - сегмент стэка, в этом сегменте хранится то, что заносится в стек(в ручную или при вызове процедур). Стек - что-то типа временной памяти с последовательным доступом. es,fs,gs - дополнительные регистры, на 'всякий случай'. ;D
Смещение - это вторая часть адреса, которая указывает на я.п. от начала сегмента. Принимает значения от 0 до 65535(по кол-ву байт в сегменте).
Обычно, для адресации я.п. используют индексные регистры di и si, но можно использовать и любые другие.
Сегмент и смещение занимают по 16 бит(2 байта) и преобразуются в 20-ти битный адрес.
mov ax,0a000h
mov es,ax
Двумя этими командами мы помещаем в регистр es сегмент адреса видеопамяти(A000). Напрямую помещать адрес нельзя, т.е. запись типа mov es,0a000h является неверной!! По-моему это связано с отсутсвием кода команд в системе операций процессора.
xor di,di
Эта команда очищает регистр индекса di, для того, чтобы в es:di лежал полный адрес начала выводимой памяти... Индекс di используется для "скольжения" по сегменту, т.е. он адресует ячейку памяти с номером, указанную в нем.
Внимание!
Запись вида mov di,5 обозначает адресацию 5-ой ячейки, а
запись вида mov [di],5 обозначает что в ячейку es:di будет помещено значение 5. Правда, в паскале это не так. В паскале для помещения значения 5 по адресу es:di оное значение помещается в регистр, допустим, аl и используется запись вида mov es:[di],al.
mov al,[col]
Здесь я помещаю в al номер цвета закраски фона.
mov cx,64000
rep StosB
команда цикла rep повторяет следующую команду. количество повторов лежит в регистре CX.
Ее можно заменить на команду цикла loop:
@l1:
StosB
loop @l1
Команда rep сначала проверяет регистр cx на равенство 0, а затем, если он не равен, убавляет его на 1, если равен, то цикл прекращается и программа идет дальше, в отличие от команды loop, которая сначала уменьшает cx на 1, а затем проверяет его на 0. Т.е. если вы поместите в cx 0, то команда rep не выполнится ни разу, а команда loop будет выполняться 65535 раз(по максимальному размеру cx)
команда STOSB - es:[di]=al; di=di?1.
Помещает содержимое al в я.п. по адресу es:di.
В зависимости от df (флаг направления) уменьшает/увеличивает индекс di на 1. Если df = 0 то di увеличивается а если df=1, то di уменьшается. Поэтому я и указал в описании команды знак ?.
Устанавливается df (df=1) командой std, а очищается - командой cld.
Пример:
program darktut;
uses crt;
procedure set13h;
begin
asm
mov ax,0013h
int 10h
cld
end;
end;
procedure close13h;
begin
asm
mov ax,0003h
int 10h
end;
end;
procedure clscr(col:byte);
begin
asm
push 0a000h
pop es
xor di,di
mov cx,64000
mov al,col
rep stosb
end;
end;
begin
randomize;
set13h;
repeat
clscr(random(256));
delay(20000);
until keypressed;
close13h;
end.
Happy codding!!!!!!!!!!!!! ;D
З.Ы. Если вы хотите немного оптимизировать процедуру очистки экрана - то можете уменьшить значение
счетчика в 2 раза и пересылать сразу по 2 байта:
mov ah,al ;расширяю цвет...
mov cx,32000
rep StosW
команда StosW: es[di]=ax; di=di+2;
З.Ы.Ы. Если вы хотите посмотреть, как будет выполнятся программа, можете ее прогнать пошагово, открыв окно Debug->Registers и нажимая F7.
З.Ы.Ы.Ы. Просьба, если заметите неточности, или у вас есть предложения/просьбы/коментарии - высказывайте все либо на форуме http://forum.pascal.net.ru, либо лично мне по почте.
Copyright by Dark.
Моя почта: darkmaze@yandex.ru ;D