
          ͻ
                    Tutorial de Assembler de Adam Hyde 1.0        Ŀ
                                                                   
                                  PARTE III                        
                      Traduzido por Renato Nunes Bastos            
          ͼ 
            


Verso   :  1.1
Data     :  27-02-1996
Contato  :  blackcat@vale.faroc.com.au
            http://www.faroc.com.au/~blackcat
;Renato  :  bastos@lci.ufrj.br
            krull@geocities.com
            http://www.geocities.com/SiliconValley/Park/3174


 

Bem-vindos ao terceiro tutorial da srie. No ltimo tutorial eu disse que 
estaramos discutindo mais algumas instrues, flags e um verdadeiro programa
em Assembly.

Durante este tutorial, voc achar os livros "Peter Norton's Guide to
Assembler", "Peter Norton's Guide to the VGA Card", ou qualquer
um dos livros "Peter Norton's Guide to..." muito teis. Voc no pode
programar em Assembler sem saber pra que so todas as interrupes 
e o que so todas as subfunes.

Eu lhe recomendo conseguir uma cpia desses livros assim que possvel.


 

 Um Programa Assembly
-----------------------

Eu geralmente no escrevo cdigo 100% em Assembly.  muito mais conveniente
usar uma linguagem de alto nvel como C ou Pascal, e usar Assembly para
acelerar os bits lentos. Contudo, voc pode querer se torturar e escrever uma
aplicao completamente em Assembly, ento aqui vai a configurao bsica:

   
    DOSSEG     - diz  CPU como organizar o segmento
   
    MODEL      - declara o modelo que vamos usar
   
    STACK      - quanta pilha vamos alocar?
   
    DATA       - o qu vai no  segmento de dados
   
    CODE       - o qu vai no segmento de cdigo
   
    START      - o incio do seu cdigo
   
    END START  - o fim do seu cdigo
   

FATO ENGRAADO: Eu sei de algum que escreveu um clone de Space Invaders (9K),
                todo em Assembly. Eu tenho o cdigo fonte, se algum estiver
                interessado...

Okay, agora vamos dar uma olhada no programa de exemplo em que eu no
farei absolutamente nada!

    DOSSEG
    .MODEL SMALL
    .STACK 200h
    .DATA
    .CODE

START:
    MOV   AX, 4C00h   ; AH = 4Ch, AL = 00h
    INT   21h
END START

Vamos ver em detalhes. Abaixo, cada uma das frases acima est explicada.

    DOSSEG     - isto ordena os segmentos na ordem:

                  Segmentos de Cdigo;
                  Segmentos de Dados;
                  Segmentos de Pilha.

                  No se preocupe muito com isso por enquanto, apenas inclua
                  at que voc saiba o que est fazendo.

    MODEL      - isso permite  CPU determinar como seu programa est
                  estruturado. Voc pode ter os seguintes MODELos:

                  1) TINY    - tanto cdigo quanto dados se encaixam
                               no mesmo segmento de 64K.

                  2) SMALL   - cdigo e dados esto em segmentos diferentes,
                               embora cada um tenha menos de.

                  3) MEDIUM  - cdigo pode ser maior que 64K, mas os dados
                               tm que ter menos que 64K.

                  4) COMPACT - cdido  menos de 64K, mas dados podem ter
                               mais que 64K.

                  5) LARGE   - cdigo e dados podem ter mais que 64K, embora
                               arrays no possam ser maiores que 64K.

                  6) HUGE    - cdigo, dados e arrays podem ter mais de 64K.

    STACK      - isso instrui ao PC para arrumar uma pilha to grande quanto
                  for especificado.

    DATA       - permite a voc criar um segmento de dados.  Por exemplo:

                  MySegment SEGMENT PARA PUBLIC 'DATA'

                      ; Declare alguns bytes, words, etc.

                  MySegment ENDS

                  Isso  similar a CONSTANTES in Pascal.

    CODE       - permite a voc criar um segmento de cdigo.  Ex.:

                  MyCodeSegment SEGMENT PARA PUBLIC 'CODE'

                      ; Declare algo

                  MyCodeSegment ENDS

    START      - Apenas um label para dizer ao compilador onde a parte 
                  principal do seu programa comea.

       MOV   AX, 4C00h   ; AH = 4Ch, AL = 00h

      Isso move 4Ch para ah, que coincidentemente nos traz de volta ao DOS.
      Quando a interrupo 21h  chamada e AH = 4Ch, de volta ao DOS l vamos
      ns.

       INT   21h

    END START  - Voc no tem imaginao?

Okay, Espeo que voc tenha entendido tudo isso, porque agora ns vamos mesmo
fazer algo.  Ficou excitado?  :)

Neste examplo ns vamos usar a interrupo 21h, (a interrupo do DOS), para
imprimir uma string. Para ser preciso, vamos usar a subfuno 9h, e ela se
parece com isso:

    INTERRUPO 21h
    SUBFUNO 9h

   Requer:

    AH     = 9h
    DS:DX  = ponteiro FAR para a string a ser impressa. A string deve ser
              terminada com um sinal $.

Assim, aqui est o exemplo:

    DOSSEG
    .MODEL SMALL
    .STACK 200h
    .DATA

OurString   DB  "Isto  uma string de caracteres.  "
            DB  "Voc no tem imaginao? Coloque algo interessante aqui!$"

    .CODE

START:
    MOV   AX, SEG OurString     ; Move o segmento onde OurString est 
    MOV   DS, AX                ; para AX, e agora para DS

    MOV   DX, OFFSET OurString  ; Offset de OurString -> DX
    MOV   AH, 9h                ; Subfuno de imprimir strings
    INT   21h                   ; Gera a interrupo 21h

    MOV   AX, 4C00h             ; Subfuno de sada para o DOS
    INT   21h                   ; Gera a interrupo 21h
END START


Se voc assemblar isso com TASM - TASM SEJALADOQUEVOCECHAMOUELE.ASM ento
linkar com TLINK - TLINK SEJALADOQUEVOCECHAMOUELE.OBJ  voc vai conseguir
um arquivo EXE de cerca de 652 bytes. Voc pode usar estes programas no DEBUG
com algumas modificaes, mas eu vou deixar isso contigo. Para trabalhar com
Assembler puro voc _precisa_ de TASM e TLINK, embora eu ache que MASM <aahh!>
faria o mesmo trabalho muito bem.

Agora vamos ao cdigo com um pouco mais detalhado:

    MOV   AX, SEG OurString     ; Move o segment onde OurString est
    MOV   DS, AX                ; para AX, e agora para DS

    MOV   DX, OFFSET OurString  ; Move o offset onde OurString est localizado
    MOV   AH, 9h                ; Subfuno de escrita de strings
    INT   21h                   ; Gera a interrupo 21h

Voc vai notar que tivemos que usar AX para pr o endereo do segmento de
OurString em DS. Voc vai descobrir que no d pra referenciar um registrador
de segmento diretamente em Assembler. Na procedure PutPixel do ltimo
tutorial, eu movi o endereo da VGA para AX, e ento para ES.

A instruo SEG  tambm introduzida. SEG retorna o segmento onde a string
OurString est localizada, e OFFSET retorna, adivinha o qu?, o offset do
incio do segmento para onde a string termina.

Note tambm que ns usamos DB. DB no  nada de especial, e significa Declare
Byte, que  o que tudo o que ela faz.  DW, Declare Word e DD, Declare Double
Word tambm existem.


Voc poderia ter tambm colocado OurString segmento de cdigo, a vantagem 
que estaria CS apontando para o mesmo segmento que OurSting, de modo que
voc no tem que se preocupar em procurar o segmento em que OurString est.

O programa acima no segmento de cdigo seria mais ou menos assim:

    DOSSEG
    .MODEL SMALL
    .STACK 200h
    .CODE

OurString     DB  "Abaixo o segmento de dados!$"

START:
    MOV   AX, CS
    MOV   DS, AX

    MOV   DX, OFFSET OurString
    MOV   AH, 9
    INT   21h

    MOV   AX, 4C00h
    INT   21h
END START

Simples, no?

Ns no vamos ver muitos programas s em Assembly de novo, mas a maioria das
tcnicas que usaremos podem ser implementadas em programas s em Assembler.


 

 Ento, o que so flags?
--------------------------

Esta parte  para meu companheiro Clive que tem me perguntado sobre flags,
ento l vamos ns Clive, com FLAGS.

Eu no me lembro se j introduzimos a instruo CMP ou no, CMP - (COMPARE),
mas CMP compara dois nmeros e reflete a comparao nos FLAGS.  Para
us-la voc faria algo desse tipo:

    CMP   AX, BX

ento seguir com uma instruo como essas abaixo:


 COMPARAES SEM SINAL:
------------------------

    JA      - pula (jump) se AX foi MAIOR que BX;
    JAE     - pula se AX foi MAIOR ou IGUAL a BX;
    JB      - pula se AX foi MENOR que BX;
    JBE     - pula se AX foi MENOR ou IGUAL a BX;
    JNA     - pula se AX foi NO MAIOR que BX;
    JNAE    - pula se AX foi NO MAIOR ou IGUAL a BX;
    JNB     - pula se AX foi NO MENOR que BX;
    JNBE    - pula se AX foi NO MENOR ou IGUAL a BX;
    JZ      - pula se o flag de ZERO est setado - o mesmo que JE;
    JE      - pula se AX for IGUAL a BX;
    JNZ     - pula se o flag de ZERO NO est setado - o mesmo que JNE;
    JNE     - pula se AX NO for IGUAL a BX;


 COMPARAES COM SINAL:
------------------------

    JG      - pula (jump) se AX foi MAIOR que BX;
    JGE     - pula se AX foi MAIOR ou IGUAL a BX;
    JL      - pula se AX foi MENOR que BX;
    JLE     - pula se AX foi MENOR ou IGUAL a BX
    JNG     - pula se AX foi NO MAIOR que BX
    JNGE    - pula se AX foi NO MAIOR ou IGUAL a BX;
    JNL     - pula se AX foi NO MENOR que BX;
    JNLE    - pula se AX foi NO MENOR ou IGUAL a BX;
    JZ      - pula se o flag de ZERO est setado - o mesmo que JE;
    JE      - pula se AX for IGUAL a BX;
    JNZ     - pula se o flag de ZERO NO est setado - o mesmo que JNE;
    JNE     - pula se AX NO for IGUAL a BX;


 NO TO COMUNS:
-----------------

    JC      - pula se o flag de CARRY est setado;
    JNC     - pula se o flag de CARRY NO est setado;
    JO      - pula se o flag de OVERFLOW est setado;
    JNO     - pula se o flag de OVERFLOW NO est setado;
    JP      - pula se o flag de PARIDADE est setado;
    JNP     - pula se o flag de PARIDADE NO est setado;
    JPE     - pula se a PARIDADE for PAR - o mesmo que JP;
    JPO     - pula se a PARIDADE for MPAR - o mesmo que JNP;
    JS      - pula se o flag de SINAL NO est setado;
    JNS     - pula se o flag de SINAL est setado.

Ufa! Meus olhos quase secaram depois de olhar pra essa tela por tanto tempo!


De qualquer modo, aqui est com o que eles se parecem:

              Ŀ
               Flag  SF  ZF  --  AF  --  PF  --  CF 
              Ĵ
               Bit   07  06  05  04  03  02  01  00 
              

   Legenda:
  ----------

  SF - Flag de Sinal;
  ZF - Flag de Zero;
  AF - Flag Auxiliar;
  PF - Flag de Paridade.
  CF - Flag de Carry (vai um).

Nota: H MUITO MAIS FLAGS PARA APRENDER. Eles sero vistos num Tutorial mais
       frente.


 

COISAS PARA FAZER:

 1) Volte ao frame da configurao bsica de Assembler e memorize-o.
 2) Tenter escreer um programa simples que mostre alguns comentrios
    _criativos_.
 3) Aprenda as instrues JUMP menos criptogrficos de cor.


 

Okay, no ltimo tutorial eu lhe dei algumas procedures, e pedi para voc 
coment-las. Eu no queria uma explicao detalhada do que eles faziam
- no se espera que voc saiba isso ainda - apenas um sumrio do que cada
comando faz.

Ex.:

   MOV   AX, 0003h   ; AX agora  igual a 03h;
   ADD   AX, 0004h   ; AX agora  igual a 07h;

Ento, aqui vai o conjunto completo das procedures com comentrios:


{ Esta procedure limpa a tela em modo texto }

Procedure ClearScreen(A : Byte; Ch : Char);   Assembler;

Asm     { ClearScreen }
  mov   ax, 0B800h    { Move o endereo de vdeo para AX    }
  mov   es, ax        { Aponta ES para o segmento de vdeo  }
  xor   di, di        { Zera  DI                            }
  mov   cx, 2000      { Move 2000 (80x25) para CX           }
  mov   ah, A         { Move o atributo para AH             }
  mov   al, &Ch       { Move o caracter a usar para AL      }
  rep   stosw         { Faz isso                            }
End;    { ClearScreen }


Explicao:

Ns zeramos DI, logo  igual a 0 - o canto esquerdo da tela. Isto  de onde 
vamos comear a encher a tela.

Movemos 2000 para CX porque vamos colocar 2000 caracteres na tela.


{ Esta procedure move o cursor para a posio X, Y }

Procedure CursorXY(X, Y : Word);   Assembler;

Asm    { CursorXY }
   mov   ax, Y              { Move o valor Y para AX               }
   mov   dh, al             { Y vai para DH                        }
   dec   dh                 { rotina baseada em ajustar para zero  }
   mov   ax, X              { Move o valor de X para AX            }
   mov   dl, al             { X vai para  DL                       }
   dec   dl                 { rotina baseada em ajustar para zero  }
   mov   ah, 2              { Chama a funo correspondente        }
   xor   bh, bh             { Zera  BH                             }
   int   10h                { faz isso (pe o cursor na posio)   }
End;    { CursorXY }


Explicao:

A ' rotina baseada em ajustar para zero'  realizada porque a BIOS refere-se 
posio (1, 1) como (0, 0), e igualmente (80, 25) como (79, 24).



Procedure PutPixel(X, Y : Integer; C : Byte; Adr : Word);   Assembler;

Asm     { PutPixel }
   mov   ax, [Adr]          { Move o endereo do VGA em  AX       }
   mov   es, ax             { Joga AX em ES                       }
   mov   bx, [X]            { Move o valor de X para BX           }
   mov   dx, [Y]            { Move o valor de Y para DX           }
   xchg  dh, dl             { Daqui pra frente calcula o          }
   mov   al, [C]            { offset do pixel a ser plotado       }
   mov   di, dx             { e pe este valor em DI.  Vamos      }
   shr   di, 2              { ver isso mais tarde - prximo tutorial}
   add   di, dx             { quando falarmos sobre shifts         }
   add   di, bx             { versus muls                          }
   stosb                    { Guarda o byte em ES:DI               }
End;    { PutPixel }


NOTA:  Eu estaria muito interessado em achar uma procedure PutPixel mais
       rpida que essa. Eu j vi uma inline que faz isso em metade do tempo,
       mas mesmo assim, essa  muito quente.


{ Esta procedure  uma funo de delay independente de CPU }

Procedure Delay(ms : Word);   Assembler;

Asm     { Delay }
   mov   ax, 1000           { Move o nmero de ms em um segundo para AX   }
   mul   ms                 { Faz AX = nmero de ms a esperar             }
   mov   cx, dx             { Prepara para o delay - pe nmero de ms     }
   mov   dx, ax             { onde necessrio                             }
   mov   ah, 86h            { Cria o delay                                }
   int   15h
End;    { Delay }


 

Quase todo o fluido saiu do meus olhos agora -  quase meia-noite - ento
eu acho melhor parar. Desculpe se os comentrios so um pouco curtos, mas eu
preciso dormir!

No prximo tutorial vamos ver:

    Shifts - o que so eles?
    Alguns exemplos de CMP/JMP.
    Como a memria VGA  arrumada, e como acess-la.
    hum, algum outro grande tpico.

Na prxima semana eu vou fazer um esforo para te mostrar com acessar
a memria rapidamente, isto , o VGA, e lhe dar alguns exemplos.

Se voc deseja ver um tpico discutido num tutorial no futuro, escreva-me, e
eu vou ver o que eu posso fazer.


 


No perca!!! Baixe o tutorial da prxima semana na minha homepage:

   http://www.faroc.com.au/~blackcat
   http://www.geocities.com/SiliconValley/Park/3174

Vejo vocs na prxima semana!

- Adam.
- Renato Nunes Bastos
