
                               ASSEMBLY
                             Manipulao de Memria
                                Aula nr. 17 de 26

    Eis  o  arquivo  .ASM com as rotinas para manipulao da memria
expandida:

 Ŀ
   IDEAL                                                         
   MODEL LARGE,PASCAL                                            
   LOCALS                                                        
   JUMPS                                                         
                                                                 
   GLOBAL  emmGetVersion : PROC                                  
   GLOBAL  emmGetPageFrameSegment : PROC                         
   GLOBAL  emmGetAvailablePages : PROC                           
   GLOBAL  emmAllocPages : PROC                                  
   GLOBAL  emmFreePages : PROC                                   
   GLOBAL  emmMapPage : PROC                                     
   GLOBAL  emmGetError : PROC                                    
                                                                 
   DATASEG                                                       
                                                                 
   emmVersion  dw  0                                             
   emmError    db  0       ; Nenhum erro ainda... :)             
                                                                 
   CODESEG                                                       
                                                                 
   ; Obtm a verso do EMM.                                      
   ; Devolve no formato 0x0X0Y (onde X  verso e Y reviso).    
   ; Prottipo em C:                                             
   ;   unsigned pascal emmGetVersion(void);                      
   PROC    emmGetVersion                                         
       mov     [emmError],0    ; Inicializa flag de erro...      
       mov     ah,46h                                            
       int     67h             ; Invoca o EMM                    
       or      ah,ah           ; Testa o sucesso da funo...    
       jz      @@no_error                                        
       mov     [emmError],ah   ; Poe erro no flag...             
       mov     ax,-1           ; ... e retorna != 0.             
       jmp     @@done                                            
       mov     ah,al           ; Prepara formato da verso.      
       and     ax,111100001111b ; A funo 46h do EMM devolve    
       mov     [emmVersion],ax  ; no formato BCD... por isso     
   @@done:                      ; precisamos formatar...         
       ret                                                       
   ENDP                                                          
                                                                 
   ; Funo: Obtm o segmento do Page Frame.                     
   ; Prottipo em C:                                             
   ;   unsigned pascal emmGetPageFrameSegment(void);             
   PROC    emmGetPageFrameSegment                                
       mov     ah,41h      ; Usa a funo 41h do EMM             
       int     67h         ; Chama o EMM                         
       mov     ax,bx       ; Poe o segmento em AX                
                           ; Funo 41h coloca o segmento do     
                           ; "Page Frame" em BX.                 
       ret                                                       
   ENDP                                                          
                                                                 
   ; Funo: Obtm o nmero de pginas disponveis na memria.   
   ; Prottipo em C:                                             
   ;   unsigned pascal emmGetAvailablePages(void);               
   ; Obs:                                                        
   ;   No verifica a ocorrencia de erros... modifique se quiser 
   PROC    emmGetAvailablePages                                  
       mov     ah,42h                                            
       int     67h     ; Invoca o EMM.                           
       mov     ax,bx   ; Poe pginas disponiveis em AX.          
       ret                                                       
   ENDP                                                          
                                                                 
   ; Aloca pginas e devolve handle.                             
   ; Prottipo em C:                                             
   ;   int pascal emmGetAvailablePages(unsigned Pages);          
   ; Obs: Devolve -1 se houve erro na alocaao e seta            
   ;      a varivel emmError.                                   
   PROC    emmAllocPages                                         
   ARG     Pages:WORD                                            
       mov     [emmError],0    ; Inicializa flag de erros...     
       mov     bx,[Pages]      ; BX = nmero de pginas a alocar 
       mov     ah,43h                                            
       int     67h             ; Invoca o EMM.                   
       or      ah,ah           ; Verifica erro do EMM.           
       jz      @@no_error                                        
       mov     [emmError],ah   ; Poe erro na varivel emmError   
       mov     dx,-1                                             
   @@no_error:                                                   
       mov     ax,dx           ; retorna cdigo de erro.         
                               ; ou o handle.                    
       ret                                                       
   ENDP                                                          
                                                                 
   ; Libera pginas alocadas.                                    
   ; Prottipo em C:                                             
   ;   void pascal emmFreePages(int handle);                     
   ; Obs: No verifica erros... modifique se quiser...           
   PROC    emmFreePages                                          
   ARG     handle:WORD                                           
       mov     dx,[handle]                                       
       mov     ah,45h                                            
       int     67h                                               
       ret                                                       
   ENDP                                                          
                                                                 
   ; Mapeia uma pgina no Page Frame.                            
   ; Prottipo em C:                                             
   ;   int pascal emmMapPage(int handle,                         
   ;                         unsigned char pfPage,               
   ;                         unsignec PageNbr);                  
   ; Onde: handle  o valor devolvido pela funo de alocao de 
   ;       pginas.                                              
   ;       pfPage  o nmero da pgina do Page Frame (0 at 3).  
   ;       PageNbr   o nmero da pgina a ser colocada no       
   ;       Page Frame (0 at mximo - 1).                        
   ; Devolve -1 se ocorreu erro e seta a varivel emmError.      
   PROC    emmMapPage                                            
   ARG     handle:WORD, pfPage:BYTE, PageNbr:WORD                
       mov     [emmError],0                                      
       mov     ah,44h                                            
       mov     al,[pfPage]                                       
       mov     bx,[PageNbr]                                      
       mov     dx,[handle]                                       
       int     67h                                               
       or      ah,ah                                             
       jz      @@no_error                                        
       mov     [emmError],ah                                     
       mov     ah,-1                                             
   @@no_error:                                                   
       mov     al,ah                                             
       ret                                                       
   ENDP                                                          
                                                                 
   ; Retorna com o erro do EMM.                                  
   ; Prottipo:                                                  
   ;   int pascal emmGetError(void);                             
   PROC    emmGetError                                           
       mov     ax,[emmError]                                     
       ret                                                       
   ENDP                                                          
                                                                 
   END                                                           
 

    Esta    uma   implementao   simplificada,   mas  para  nossos
propsitos serve muito bem.  Algumas consideraes:  A  alocao  de
memria  via  EMM no  feita da mesma maneira que a funo malloc()
de C ou GetMem() do  TURBO  PASCAL.  No  devolvido nenhum pointer.
Isto se torna bvio a partir do momento que entendemos como funciona
o EMM: Toda a manipulao de bancos de  memria    feita  de  forma
indireta pelo Page Frame.  A funo de alocao deve apenas devolver
um handle para que possamos  manipular as pginas alocadas.  Entenda
esse handle da mesma forma com que os  arquivos  so  manipulados...
Se  quisermos  usar um banco alocado precisamos informar ao EMM qual
dos bancos queremos usar, fazendo  isso  via o handle devolvido pelo
prprio EMM.

    Suponha que queiramos alocar  128kb  da memria expandida para o
nosso programa.  Precisamos alocar 8 pginas  lgicas  (8  *  16k  =
128k).  Chamariamos a funo emmAllocPages() em C da seguinte forma:

 Ŀ
   #include <conio.h>                                            
   #include <stdlib.h>                                           
                                                                 
   int emm_handle;                                               
                                                                 
   void f(void)                                                  
   {                                                             
       /* ... */                                                 
       if ((emm_handle = emmAllocPages(8)) == -1) {              
           cprintf("EMM ERROR #%d\r\n", emmGetError());          
           exit(1);                                              
       }                                                         
       /* ... */                                                 
   }                                                             
 

    Na  funo  emmAllocPages() optei por devolver -1 para indicar o
insucesso da funo...  Voc pode  arrumar um esquema diferente para
chegar isso (por  exemplo,  checando  a  varivel  emmError  aps  a
chamada a funo!).
                                                                                                                             
