Се начнем повесть сию... ;D
Итак, уважаемые, позвольте мне представить мой туториал №1.
Он посвящен основам программирования графики на паскалевском ассемблере,и предназначен для тех, кого достала тормознутость графики на пасе (а работать с графикой с его процедурами я бы не советовал...), кто хотел бы написать БЫСТРУЮ игру, да и для тех, кому вообще интересен asm.
Внимание: Более-менее непонятные термины будут объясняться в глоссарии(в конце туториала).
Данные эксперименты не совсем совместимы с библиотечкой Graph, поэтому крайне нежелательно ее подключать. Конкретнее, Graph не признает вручную(без использования процедуры InitGraph) включенный режим, и не будет с ним работать.
Данный документ писался для людей с разной степенью подготовки, и поэтому здесь могут разбираться слишком элементарные вещи.
Для использования примеров вам необходима карточка VGA(хе хе, сейчас это любой видеоадаптер), поддерживающая режим 320*200, TP версии 7.0, и желание разобраться.
Начну с благодарностей: спасибо моей маме, моим учителям, авторам интересной литературы, этому форуму, лично Gluck'у и Shadow. ПРЕОГРОМНОЕ спасибо!!!
В этой, первой,(и, надеюсь, не последней) части я расскажу о том, как врубить режим 320*200*256цв., и как с ним начать работать. Этот режим в литературе можно втретить под названием MCGA-режима. (Multi Color Grafic Adapter).
Он имеет номер 13 в шеснацатеричной системе счисления или 19 в десятичной. В дальнейшем 16-теричный вид будет отмечаться буквой h или символом $ (Например 13h=$13) а десятичный отмечатся не будет (19).
Несколько общих моментов:
Начиная со стандарта VGA, видеопамять реализована в виде адресного пространства, доступ к которой возможен при помощи одной команды, тогда как для стандартов EGA и CGA характерна сложная организация видеопамяти, где простая операция записи в нее или чтения из нее невозможна, для этого требуется около десятка команд и необходимо работать с портами.
Видеобуфер реализован в виде ЛИНЕЙНОГО пространства,т.е. видеокарточка не понимает что такое координаты (представте себе одномерный массив).
1. В режиме 13h задействуется один байт памяти на одну точку, т.е. 8 бит.
2. Раз на каждую ячейку памяти приходится одна точка, то формула для рисования точки по координатам х,у выглядит так:
P(x,y)= x+y*(MaxX+1) (В нашем случае MaxX будет 319 т.е. P(x,y)=x+y*320)
3. Раз используем 8-битный (однобайтный) режим, то мы можем работать с 256 цветами (в отличие от 16 цветов в пасе)!!!!!!!!!
4. Адрес видеопамяти, начиная с которого изображение в графических режимах выводится на монитор, равен 0A000:0000h. следующие 64000 (320*200) байт в данном режиме как раз и выводятся на экран.
5. Для закрытия графического режима 13h я буду использовать текстовый режим 3(80*25*16)
Ну так вот, для того, чтобы менять режимы будем использовать функцию BIOS установки режима:
------------------------------------------------------------------------
Установка видеорежима(прерывание 10h):
На входе:
ah=00h ; Установить режим
al= ; Номер режима
Используемые регистры: ax.
------------------------------------------------------------------------
В нашем случае:
------------------------------------------------------------------------
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 - возможно, скажете вы, - но стандартные средства паскаля использовать не рекомендуют, так что же нам здесь делать?
Ну... для начала давайте покрасим экран в какой-нибудь цвет:
Это очень просто: адрес нам известен - $A000:0000, следующие 64000 байт - наш экран, поэтому этим 64000 байт просто присваиваем номер нужного нам цвета...
------------------------------------------------------------------------
procedure clscr(col:byte);
begin
asm
mov ax,0A000h
mov es,ax
xor di,di
mov al,[col]
mov cx,64000
@l1:
mov byte ptr es:[di],al
inc di
loop @l1
end;
end;
Используемые регистры: ax,es,di,cx.
------------------------------------------------------------------------
Итак, введя этот код вы получите процедуру закраски экрана.
А теперь, давайте я расскажу о ней поподробнее...
mov ax,0A000h
mov es,ax {es=$A000}
xor di,di {di=0}
Тремя этими командами мы помещаем в связку регистров es:di адрес видеопамяти.
mov al,[col]
Здесь я помещаю в al номер цвета закраски фона.
mov cx,64000
@l1:
mov byte ptr es:[di],al
inc di
loop @l1
Команда цикла loop повторяет команды,находящиеся между меткой(@l1) и самой командой. Количество повторов помещается в регистр CX.
Команда пересылки mov записывает байт из регистра al в ячейку памяти по адресу es:di
И, наконец, команда inc увеличивает di на 1, тем самым обеспечивая перемещение по пространству памяти.
Есть специальная команда, которая сразу выполняет за нас работу по пересылке байта из al в ячейку памяти es:[di] и инкрементации di - НА СЦЕНУ ПРИГЛАШАЕМ КОМАНДУ STOSB.
И ВОТ ОНА - ВОЛШЕБНАЯ!!!!!!!!! Таким образом мы можем заменить две команды
mov byte ptr es:[di],al
inc di
на одну
stosb
т.е. смотрите -
mov cx,64000
@l1:
stosb
loop @l1
Если посмотреть в умную книжку по ассемблеру, то можно увидеть что есть и другой цикл - rep, и с ним наша программа будет выглядеть еще элегантнее -
mov cx,64000
rep stosb
Я немного извиняюсь :-[, но это все что я сделал в первом туториале, но надеюсь что это еще не все, и я перейду в такой режим работы над туториалами, когда я смогу давать больше материала и по качеству гораздо лучше ;D; несомненно есть много людей, которые намного лучше меня во всем этом разбираются, но и у меня все впереди... Я НЕ ВОЛШЕБНИК, Я ТОЛЬКО УЧУСЬ!!!
:-[Извините если слишком всего много или наоборот мало. :-[
До новых встреч.
Заключительный Пример:
uses crt;
procedure clscr(col:byte);
begin
asm
mov ax,0a000h
mov es,ax
xor di,di
mov cx,64000
mov al,col
@l1:
mov byte ptr es:[di],al
inc di
loop @l1
end;
end;
procedure clscr1(col:byte);
begin
asm
mov ax,0a000h
mov es,ax
xor di,di
mov cx,64000
mov al,col
@l1:
stosb
loop @l1
end;
end;
procedure initgr;
begin
asm
mov ax,0013h
int 10h
end;
end;
procedure closegr;
begin
asm
mov ax,0003h
int 10h
end;
end;
begin
randomize;
initgr;
repeat
clscr(random(255));
until keypressed;
readkey;
repeat
clscr1(random(255));
until keypressed;
readkey;
closegr;
end.
Happy codding!!!!!!!!!!!!!
Анекдот напоследок: Стоят два хакера и ругаются на ассемблере... ;D
Глоссарий.
1.Команда mov устроена таким образом, что она может пересылать данные из регистров или памяти в регистр или память, но у нее следующие исключения и возможности:
Запись вида mov ax,bx обозначает пересылку значения из регистра bx в регистр ax
Запись вида mov ax,[bx] обозначает пересылку значения из ячейки памяти по адресу
ds:[bx] в регистр ax
Иногда необходима пересылка с указанием типа, т.к. в некоторых случаях компилятор может непонять, что имеется в виду: пересылка слова или байта : mov ax,[bx]
для этого используют специальный оператор указания типа ptr:
mov ax,byte ptr [bx] - пересылка байта
mov ax,word ptr [bx] - пересылка слова
А. Нельзя передавать значение одного сегментного регистра в другой:
mov es,ds
Б. Нельзя с ее помощью записать в сегментный регистр значение из памяти или константу:
mov es,0A000h
или
mov es,[seg].
В. Нельзя передавать значение из одной области памяти в другую:
mov es,ds
[/color=Blue]
Г. В качестве первого оператора не может выступать сегментный регистр cs:
[color=Blue]
mov cs,ax.
В случаях А,Б и В нужно использовать промежуточный объект - регистр или стек:
mov ax,[seg] или push [seg] push ds
mov es,ax pop es ; pop es
2. Стек - область памяти, специально выделенная для временного хранения работы программы. По принципу доступа он реализован в виде LIFO - последний пришел - первый ушел (Last in First Out).Команды для работы с ним:
push [что] - сохранить в стеке
pop [куда] - восстановить из стека
Пример:
push ax
pop bx
Помните: вытаскивайте в обратном порядке сохранения в стек:
push ax
push bx
push cx
...
pop cx
pop bx
pop ax
Возможно сразу сохранение всех регистров:
pusha - сохраняет ax,cx,dx,bx,sp,bp,si,di
popa - востанавливает di,si,bp,sp,bx,dx,cx,ax
3.
В ПК термином "адрес" обозначают разные вещи. Часто под адресом понимается
16-битовое смещение (offset) - адрес ячейки,отсчитанный от начала сегмента
(области) памяти, которому принадлежит эта ячейка. В этом случае под адрес
отводится слово памяти.
В другом случае под "адресом" понимается 20-битовый абсолютный адрес
некоторой ячейки памяти. В силу ряда причин в ПК такой адрес зада-
ется не как 20-битовое число, а как пара "сегмент:смещение", где "сег-
мент" (segment) - это первые 16 битов начального адреса сегмента памяти,
которому принадлежит ячейка, а "смещение" - 16-битовый адрес этой
ячейки, отсчитанный от начала данного сегмента памяти (величина
16*сегмент+смещение дает абсолютный адрес ячейки). Такая пара записы-
вается в виде двойного слова: в первом слове размещается смещение,
а во втором - сегмент.
(Язык макроассемблера для IBM. Составитель В.Н.Пильщиков (МГУ, ВМК) 1992г ) -
Электронная версия, кому надо - дам...
Всего хорошего...
Извиняюсь за огрехи с цветом - время заканчивается...
На тему ассемблер по темам - я так и собирался, взялся за графику т.к. именно через нее начал изучать ассемблер...
И еще раз простите за такую тягомотину со временем... Спасибо Alesha_GA за информацию...
Я уже стараюсь со вторым туториалом... когда выйдет - уже боюсь предсказывать... ;D
___ALex___
13.07.2003 18:29
абсолютно верно как-то Gluck тебе сказал - если тему какую-то затрагиваешь - то объясняй её популярно или вообще не затрагивай вот к примеру говоришь что mov cs, 7 нельзя, так а как можно?!
На тему именно cs:
Г. В качестве первого оператора не может выступать сегментный регистр cs:
mov cs,ax
Это значит, что этого не может быть никогда, т.к. CS:IP - текущий адрес выполняемой команды, т.о. изменяя CS или IP мы получаем процедуру прыжка на другую команду, а зачем это надо, если есть стандартные...?!!!
На тему второго туториала: УЖЕ ПРОХОДИТ СТАДИЮ ОТЛОВА БЛОХ, т.е. почти завершен.
___ALex___
18.07.2003 1:06
не ТЕКУЩЕЙ, а СЛЕДУЮЩЕЙ команды
поэтому, к примеру, в команде jmp смещение и отсчитывается от следущей за jmp командой до метки