IPB
ЛогинПароль:

> Tutorial.Temp, в будущем будет продолжен...
Dark
сообщение 13.05.2003 0:25
Сообщение #1


Знаток
****

Группа: Пользователи
Сообщений: 408
Пол: Мужской

Репутация: -  3  +


Се начнем повесть сию...

Итак, уважаемые, позвольте мне представить мой туториал №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.pascalnet.ru, либо лично мне по почте.

Copyright by Dark.
Моя почта: darkmaze@yandex.ru ;D


--------------------
- Где я?
- Во тьме.
- В какой тьме?
- Во тьме твоего мозга.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
 
 Ответить  Открыть новую тему 
Ответов
Dark
сообщение 13.07.2003 13:55
Сообщение #2


Знаток
****

Группа: Пользователи
Сообщений: 408
Пол: Мужской

Репутация: -  3  +


Се начнем повесть сию...   ;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г ) -

Электронная версия, кому надо - дам...

Всего хорошего...


--------------------
- Где я?
- Во тьме.
- В какой тьме?
- Во тьме твоего мозга.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

Сообщений в этой теме
Dark   Tutorial.Temp   13.05.2003 0:25
___ALex___   Re: Tutorial.Temp   13.05.2003 10:19
GLuk   Re: Tutorial.Temp   13.05.2003 17:46
Dark   Re: Tutorial.Temp   13.05.2003 23:13
Dark   Re: Tutorial.Temp   13.05.2003 23:16
Dark   Re: Tutorial.Temp   16.05.2003 23:44
GLuk   Re: Tutorial.Temp   17.05.2003 18:32
___ALex___   Re: Tutorial.Temp   17.05.2003 19:21
Shadow   Re: Tutorial.Temp   17.05.2003 20:29
___ALex___   Re: Tutorial.Temp   17.05.2003 22:03
GLuk   Re: Tutorial.Temp   17.05.2003 22:04
___ALex___   Re: Tutorial.Temp   17.05.2003 22:07
GLuk   Re: Tutorial.Temp   17.05.2003 22:14
___ALex___   Re: Tutorial.Temp   17.05.2003 22:25
GLuk   Re: Tutorial.Temp   17.05.2003 22:28
___ALex___   Re: Tutorial.Temp   17.05.2003 22:31
___ALex___   Re: Tutorial.Temp   17.05.2003 22:34
Dark   Re: Tutorial.Temp   18.05.2003 2:29
Dark   Re: Tutorial.Temp   18.05.2003 2:32
GLuk   Re: Tutorial.Temp   18.05.2003 5:49
Dark   Re: Tutorial.Temp   19.05.2003 0:08
GLuk   Re: Tutorial.Temp   19.05.2003 15:44
Wasana   Peercft shot! Thanks for your post!   19.11.2012 17:58
Dark   Re: Tutorial.Temp   21.05.2003 1:20
Dark   Re: Tutorial.Temp   31.05.2003 15:50
Dark   Re: Tutorial.Temp   31.05.2003 15:54
GriKo   Re: Tutorial.Temp   8.06.2003 14:57
GLuk   Re: Tutorial.Temp   8.06.2003 17:33
___ALex___   Re: Tutorial.Temp   4.07.2003 23:44
Alesha_GA   Re: Tutorial.Temp   6.07.2003 1:39
GLuk   Re: Tutorial.Temp   6.07.2003 5:34
___ALex___   Re: Tutorial.Temp   6.07.2003 16:34
GLuk   Re: Tutorial.Temp   6.07.2003 21:13
Noname   Re: Tutorial.Temp   6.07.2003 21:18
Jessica   This is the perfect way to break down this inofrai...   19.11.2012 13:34
GLuk   Re: Tutorial.Temp   6.07.2003 21:28
AlaRic   Re: Tutorial.Temp   7.07.2003 6:03
___ALex___   Re: Tutorial.Temp   7.07.2003 13:30
___ALex___   Re: Tutorial.Temp   7.07.2003 13:31
GLuk   Re: Tutorial.Temp   7.07.2003 14:25
AlaRic   Re: Tutorial.Temp   7.07.2003 14:31
GLuk   Re: Tutorial.Temp   7.07.2003 15:56
___ALex___   Re: Tutorial.Temp   7.07.2003 16:39
Noname   Re: Tutorial.Temp   7.07.2003 16:46
___ALex___   Re: Tutorial.Temp   7.07.2003 17:11
AlaRic   Re: Tutorial.Temp   11.07.2003 19:55
GLuk   Re: Tutorial.Temp   11.07.2003 20:12
AlaRic   Re: Tutorial.Temp   12.07.2003 8:24
___ALex___   Re: Tutorial.Temp   12.07.2003 12:20
Noname   Re: Tutorial.Temp   12.07.2003 12:36
AlaRic   Re: Tutorial.Temp   12.07.2003 13:14
Noname   Re: Tutorial.Temp   12.07.2003 13:41
AlaRic   Re: Tutorial.Temp   13.07.2003 10:13
Dark   Re: Tutorial.Temp   13.07.2003 13:41
Dark   Re: Tutorial.Temp   13.07.2003 13:55
Dark   Re: Tutorial.Temp   13.07.2003 14:01
___ALex___   Re: Tutorial.Temp   13.07.2003 14:29
___ALex___   Re: Tutorial.Temp   13.07.2003 14:30
Dark   Re: Tutorial.Temp   16.07.2003 20:16
___ALex___   Re: Tutorial.Temp   17.07.2003 18:03
Shadow   Re: Tutorial.Temp   17.07.2003 19:15
___ALex___   Re: Tutorial.Temp   17.07.2003 21:06
Shadow   Re: Tutorial.Temp   18.07.2003 4:04


 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 5.11.2024 20:48
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"