Microprocessadores Ementa: Arquitetura de microprocessadores. Instruções de transferencia de dados, operações lógicas e aritméticas, desvios e subrotinas. Interrupções . Linguagem Assembly. Introdução ao projeto de microcomputadores. Aspectos de sistemas de desenvolvimento para microprocessadores. COMENTÁRIOS 1 - Introdução 1.1 - Assembler, Assembly e linguagem de máquina 1.2 - Arquitetura de um microcomputador padrão 1.2.1 - Placa principal 1.2.1.1 - Unidade Central de Processamento (UPC) 1.2.1.2 - Memória Principal 1.2.2 - Barramento (endereço, dados e controle) 1.2.2.1 - Via de Endereço 1.2.2.2 - Via de Controle 1.2.2.3 - Via de Dados 1.2.3 - Placa de Vídeo 1.2.4 - Placa de Entrada / Saída 1.2.5 - Placa Controladora de Disco 1.2.6 Exemplo da Arquitetura de um computador 1.2.7 Fluxograma do seguenciamento de instruções 1.3 - Sistema de Entrada e Saída básico("Bios") 1.4 - Sistema Operacional ("DOS") 1.4.1 - Sistema Central 1.4.2 - Programas Auxiliares 1.4.3 - Gerenciador de Comandos 2 - Os Microprocessadores 2.1 - Definição de "Bit, Byte, Word, Dword" 2.2 - Arquitetura Interna de um Computador padrão 2.2.1 - Registros de Dados 2.2.2 - Registros de Segmentos 2.2.3 - Registros de Apontadores 2.2.4 - Associação entre registradores, apontadores e segmentos 2.2.5 - Registro de Estado 2.3 - Modo de Endereçamento 2.4.1 - Endereçamento Imediato 2.4.2 - Endereçamento Direto 2.4.3 - Endereçamento por Registros 2.4.4 2.4.5 2.4.6 - Endereçamento Indireto - Endereçamento Base - Endereçamento Índice 2.4.7 2.4.8 - Endereçamento de E/S - Resumo dos tipos de endereçamento 3 - Programação 3.1 - Utilitários Debug 3.1.1 - Como entrar no Debug 3.1.2 - Comando do Debug 3.2 - Exemplos de programa, escritos em linguagem assembly, utilizando o utilitário debug 3.2.1 - Instrução MOV 3.2.2 - Instrução ADD 3.2.3 - Instrução SUB 3.2.4 - Programa exemplo: Somar dois valores 3.2.5 - Instrução CMP 3.2.6 - Instrução de Salto Condicional 3.3 - Instruções para manipular dados. 3.3.1 - Instrução MOVSB e MOVSW 3.3.2 - Instrução REP 3.3.3 - Instrução LODSW e STOSB - STOSW 3.3.4 - Instrução CMPSB - CMPSW 3.4 - Instruções para manipular bits 3.4.1 - Instrução RCL 3.4.2 - Instrução RCR 3.4.3 - Instrução ROL 3.4.4 - Instrução ROR 3.4.5 - Instrução SAL e SHL 3.4.6 - Instrução SHR 3.4.7 - Instrução SAR 3.4.8 - Aplicando as instruções que manipulam bits 3.4.8.1 - RCL e SAL 3.4.8.2 - RCR e SHR 3.5 - Instruções aritméticas 3.5.1 - Instrução DD e ADC 3.5.2 - Instrução SUB e SBB 3.5.3 - Instrução MUL 3.5.4 - Instrução DIV 3.5.5 - Instrução DEC 3.5.6 - Instrução INC 3.6 - Instruções lógicas 3.6.1 - Instrução AND 3.6.2 - Instrução OR 3.6.3 - Instrução XOR 3.7 - Instruções de desvio e transferência de controle 3.7.1 - Instrução JUMP Relativo 3.7.2 - Instrução JUMP 3.7.3 - Instrução CALL 2 3.8 - Instruções de controle de "loops" 3.8.1 - Instrução LOOP 3.8.2 - Instrução LOOPZ e LOOPNZ 3.9 – Acesso a memória de pilha 3.9.1 – Instruções PUSH e POP 3.10 - Instruções de entrada e saída 3.11 - Interrupções 3 COMENTÁRIOS O microprocessador é um circuito eletrônico programável que realiza desde os trabalhos mais simples até os mais complexos, exercendo controle de equipamentos industriais como furadeiras, tornos, semáforos de trânsito, na medicina, na indústria de material bélico, etc. Apesar de ser um sistema complexo, sua aplicação é bastante simples e ilimitada. A linguagem Assembly de um microprocessador serve primordialmente para os seguintes propósitos: - evitar o uso direto das instruções e endereços de máquina dos microprocessadores em sua forma binária ou hexadecimal, tarefa que é bastante árdua para o ser humano; - entender e testar os programas e rotinas de interfaceamento para uso de dispositivos terminais e uso de memória e registradores; - preparar novas rotinas para projetos eletrônicos de controle de processos e aplicações usando microprocessadores. Entretanto, o uso da linguagem de baixo nível como a linguagem Assembly torna-se tarefa cada vez mais trabalhosa, tratando-se de microprocessadores poderosos, em decorrência da amplitude e complexidade dos seus componentes de hardware envolvidos. É desaconselhável preparar e testar programas extensos em linguagem Assembly ao se tratar de microprocessadores de 16, 32 ou mais bits, tendo em vista as dificuldades e diversidade das opções de uso das instruções. A linguagem Assembly para microprocessadores com 16 bits (8086/8088/80286), 32 bits (80386, 80486) ou mais bits é, entretanto, um meio indispensável para analisar, entender e preparar software para projetos de interface de equipamentos e aplicações com esses microprocessadores. Pois, apesar da maioria dos equipamentos de computação serem provenientes do exterior, quando há a necessidade de inteligar um específico dispositivo a um computador é necessario implementar a interface entre eles, pois este dado não é fornecido pelo fabricante. Não se trata de preparar programas extensos, mas de preparar programas curtos ou entender e adaptar os programas existentes que acompanham os manuais de aplicações utilizando microprocessadores. Os microprocessadores são amplamente utilizados e seus software’s são padronizados e compatíveis entre si. 4 CAPÍTULO I 1 - Introdução 1.1 - Assembler, Assembly e Linguagem de Máquina Linguagem de máquina é o conjunto de instruções primitivas (instruções de máquina), formada de códigos binários (dígitos 0 e 1)). Este é o único tipo de informação que o computador digital binário pode manipular. Os dígitos 0 e 1 são armazenados internamente no computador em forma de energia elétrica, por exemplo: Digito 0 - não há energia - FALSO Digito 1 - há energia - VERDADEIRO A principal desvantagem da linguagem de máquina é a sua utilização, pois, ela é difícil e cansativa. Para facilitar o uso mais conveniente do usuário foi criada a linguagem assembly, que expressa uma instrução de máquina por um mneumônico, por exemplo: Instrução de máquina Correspondente 0110 0111 Instrução Assembly MOV AX, BX Assembler é um montador que transforma cada instrução assembly em uma instrução de máquina. A correspondência entre elas é uma para uma, isto é, uma instrução assembly corresponde a uma instrução de máquina. 1.2 - Arquitetura de um Microcomputador Padrão 1.2.1 - Placa Principal No minímo deve ser constituída pela Unidade de Processamento Central (UPC) e pela Memória Principal (MP) 1.2.1.1 - Unidade Central de Processamento (UPC) A UPC, que num microcomputador (C) é um microprocessador (P), tem por função controlar todos os outros componentes do C, fazendo com que os dados fluam de modo a obedecer as instruções (ordens) captadas do programa pela UPC. Ela manipula os dados, endereçando posições de memória e realizando cálculos. 5 A UPC é constituída de (Figura 1 . 1): Unidade de Controle (UC): Gerencia o fluxo de dados; é a unidade ïnteligente da UPC; Unidade Lógica e Aritmética (ULA) : Utilizada para cálculos lógicos e aritméticos; Registros : Utilizados para a manipulação de dados armazenados na memória. 1.2.1.2 - Memória Principal (MP) Utilizada para armazenamento de dados binários. É bem mais rápida do que as memórias secundarias (Discos), pois não utilizam dispositivos mecânicos. Existem dois tipos : ROM e RAM. ROM (Read Only Memory) - É uma memória apenas de leitura, e, ao contrário da RAM ela não é apagada quando o C é desligado. Ela armazena os seguintes programas: - INICIALIZAÇÃO DO C – Este programa é executado assim que o C é ligado, ele envia mensagens para o vídeo, testa a memória RAM e aciona o driver ou Winchester para armazenar o Sistema Operacional (SO) na memória RAM. - BIOS (Basic Input Output System) - responsável pelo gerenciamento das funções básicas do computador, que tem como principais tarefas: ler teclado, cuidar do vídeo, porta paralela, porta serial e etc. A BIOS fornece rotinas para o gerenciamento das funções de E/S de um C. RAM (Random Acess Memory) - Utilizada para auxiliar o processamento de dados. Ela é apagada quando o C é desligado. É uma memória de leitura e escrita 1.2.2 - Barramento O barramento é constituído dos condutores que interligam a Unidade Central de Processamento (UCP) aos demais componentes do computador. Ele possui 3 vias: 1.2.2.1 - Via de Endereço Indica para qual endereço a UPC deve transmitir ou receber os dados da memória principal ou de um dispositivo de Entrada / Saída. Ela é unidirecional. 6 1.2.2.2 -Via de Controle Constituída por sinais ( I/OR, I/OW, MR, MW, INT, INTA , etc.) que controlam principalmente o sentido do fluxo de dados. Onde: I/OR – Leitura de Entrada/Saída; I/OW – Escrita de Entrada/Saída; MR – Leitura da Memória Principal; MW – Escrita na Memória Principal; INT – Pedido de interrupção de algum periférico; INTA – Reconhecimento do pedido de interrupção pela CPU, isto é, a CPU vai atender o pedido de interrupção . Esta via é bidirecional. 1.2.2.3 - Via de Dados Utilizada para a comunicação de dados entre a UPC e os demais componentes do C. Ela é bidirecional. 1.2.3 - Placa de Vídeo Responsável pelo controle do vídeo. Nos atuais PC's ela é ligada diretamente ao barramento do C, como visto na Fig. 1.2 Possui uma RAM, onde todos os dados que forem armazenados nela serão mostrados no monitor de vídeo. Esta memória RAM é denominada RAM de vídeo. Dependendo da Seleção das opções da placa, pode-se escolher entre modo texto, modo gráfico, resolução de gráficos, cores, etc. 7 1.2.4 - Placa de E/S As placas de E/S são utilizadas para a comunicação de dados entre os dispositivos periféricos e a placa central. Existem dois tipos de portas nas placas de E/S: as paralelas e as seriais. A serial converte dados paralelos para seriais ( Fig. 1.3). - Comparação entre as interfaces seriais e paralelas: serial: transfere um byte ou palavra um bit de cada vez; paralela: transfere um byte ou palavra de uma só vez; serial: a conexão requer poucos fios; paralela: a conexão requer no mínimo um fio para cada bit na serial a transferência dos dados é mais lenta do que a transmissão paralela. Para a transmissão de dados serialmente é possível dois modos diferentes: o modo síncrono e o modo assíncrono. 8 No modo assíncrono para cada caractér transmitido é adicionado um bit que indica o início do caractér (start bit), um ou dois bits que indicam o fim do caractér (stop bit) e, opcionalmente, um bit para a verificação da transmissão (parity bit). Este bit de paridade é utilizado para verificar se houve algum erro na trasmissão. No modo síncrono inicialmente é feita a transmissão de caractéres especiais para a sincronização do emissor com o receptor, este caractéres são denominados de caractéres de sincronização. Após isto, são enviados os dados um em seguida do outro sem sinais especiais para a separação de um caractér do outro. 1.2.5 - Placa Controladora de Discos Esta placa controla os discos, drivers e Winchester. É responsável pelos movimentos da cabeça de leitura/gravação, codificação/ decodificação (modulação, demodulação) dos dados magnéticos gravados nos discos (Fig. 1.4). 1.2.6 - Exemplo de um Microcomputador A Fig. 1.5 esboça a arquitetura de um microcomputador padrão. 9 1.2.7 - Fluxograma de sequenciamento de instruções 10 Fig. 1.6 - Sequenciamento de Instruções 11 1.3 - Basic Input Output System (BIOS) Conjunto de rotinas básicas que tratam da E/S de dados. Normalmente estas rotinas são implementadas pelo fabricante. Para sua implementação o fabricante deve seguir determinadas regras, para tornar compatível seus equipamentos com os de outros fabricantes. Assim uma BIOS que tenha sido desenvolvida por um determinado fabricante, poderá ser utilizada no computador de outro fabricante. 1.4 - Disk Operational System (DOS) É um programa que intermedia o operador, o programa sendo executado e a BIOS. É dividido em três partes: 1.4.1 - Sistema Central (S.C) Contém as principais rotinas do sistema operacional (SO) Função principal: gerenciar e organizar as informações, em geral, "contidas" em discos, vídeo, impressora, etc. O SC é armazenado na RAM da memória principal na inicialização, através do programa monitor, residente na ROM. 1.4.2 - Programas Auxiliares Complementa o S.C. Separado do S.C., pois caso estivessem juntos não haveria espaço suficiente na RAM. Quando necessário o programa auxiliar é carregado na RAM, executado e após isto, a RAM é novamente liberada. 1.5 - Gerenciador de Comandos (G.C.) É o programa que liga o usuário ao sistema operacional. Usuário envia comando (digita no teclado) G.C. recebe o comando G.C. interpreta o comando G.C. passa as ordens para o sistema central (S.C.) 12 CAPITULO II 2 - O MICROPROCESSADOR C O P é o componente do C que controla todos os outros componentes. Ele realiza o fluxo de dados entre os outros componentes obedecendo as ordens transmitidas pelo programa em execução, residente na Memória Principal. 2.1 - Bit, Byte, Word e Códigos bit - Unidade elementar de informação de um C byte - Conjunto de 8 bits Ordem crescente B7 B6 B5 B4 B3 B2 bit mais significativo B1 B0 bit menos significativo onde: B0 = 20 = 1; B1 = 21 = 2; B2 = 22 = 4; . . . B7 = 27 = 128. word - especifica 16 bits ou 2 bytes dword - especifica 32 bits ou 4 bytes ou 2 words Binário 0000 0001 0010 0011 0100 0101 0110 0111 1000 Octal 00 01 02 03 04 05 06 07 10 Códigos Decimal 00 01 02 03 04 05 06 07 08 Hexadecimal 0 1 2 3 4 5 6 7 8 13 1001 1010 1011 1100 1101 1110 1111 11 12 13 14 15 16 17 09 10 11 12 13 14 15 9 A B C D E F 2.2 –Arquitetura Interna do Microprocesador 8086 Em linguagem de máquina toda a programação é baseada em registradores. Eles são utilizados na manipulação dos dados que estão armazenados na memória principal ou nos dispositivos de E/S. Estes registros são internos a UPC. Em um P existem diversos tipos de registradores, fisicamente são iguais, mas possuem funções diferentes. Os registros internos são fisicamente similares a memória (MP), mas tem acesso mais rápido, pois a CPU não necessita ir buscar a informação na Memória Principal (MP), a informação já está contida na CPU. O P 8086 é dividido em 4 grupos de registros (Fig. 2.1) de acordo com suas funções: a ) Dados : é essencialmente o conjunto de registros aritméticos utilizados para processar informações; b ) Apontadores: são utilizados para endereçar a memória (MP); incluem registro de base e índice , utilizados para endereçar dados, o contador de programa ou apontador de instruções, utilizado para endereçar a próxima instrução e o apontador de pilha, utilizado para endereçar a memória de pilha ; c ) Segmentos : é um conjunto de registros de base de propósitos especiais, utilizados para endereçar a memória (MP); eles indicam o início de um dos três segmentos de memória (segmento de instruções ou segmento de dados ou segmento de pilha); d ) Estado : indica o estado do processo, isto é, como as variáveis de estado mudam com a execução do programa. A figura 2.1 mostra a configuração interna do microprocessador 8086. 14 Fig. 2.1 - Configuração interna do P 8086 2.2.1 - Registros de Dados O microprocessador 8086 possui quatro registros de dados (AX, BX, CX e DX), cada um deles com 16 bits (palavra). Todos eles são de uso geral, porém, existem algumas diferenças entre eles. Entre as caracteristicas comuns, pode-se citar: são utilizados para armazenar operandos e resultados da ULA; a palavra (word) pode ser particionada em dois bytes: o byte mais significativo (H) e o byte menos significativo (L); todas as instruções em assembly que referenciam a palavra, por exemplo, AX, também podem referenciar tanto o byte mais significativo, AH, bem como o byte menos significativo, AL; portanto, pode ser acessada a palavra (word) ou o byte mais significativo ou o byte menos significativo. Ordem crescente AX 15 8 AH Bit mais significativo 7 0 AL Bit menos significativo 15 As diferenças entre estes registros são : AX - é o único registro utilizado para transferir ou receber dados de portas de E/S: instrução IN AX, endereço da porta de E/S; BX - utilizado como registro de base; CX - utilizado como contador para determinadas instruções: instruções REP ou LOOP; DX - é o único registro que endereça portas de E/S: instrução IN AX, DX ____ nesta instrução o conteúdo de DX possui o endereço da porta de E/S 2.2.2 - Registros de Segmentos: Utilizados como endereço de base de uma posição de memória; Indicam, na memória principal o início de um dos três tipos de segmentos ou áreas; Cada um deles possui 16 bits; São denominados de segmento porque dividem a memória em segmentos de 64 kbytes ( 216 ). CS (Code Segment) – segmento (área ou memória) de código : utilizado pelo P para determinar o endereço da próxima instrução; indica o endereço inicial da memória de instruções; DS (Data Segment) - segmento de dados : utilizado para acessar dados da memória; indica o endereço inicial da memória de dados; ES (Extra Segment) - segmento extra de dados : utilizado para acessar dados que estão em outro segmento que não seja DS; normalmente este registro é utilizado quando o número de dados na área de dados excede 64 Kbytes; indica o endereço inicial da memória extra de dados; SS (Stack Segment) - segmento de pilha : utilizado para salvar registros e para guardar endereços de retorno de chamada de subrotinas e interrupções; indica o endereço inicial da memória pilha. 2.2.3 - Registros Apontadores Utilizados para endereçar a memória a partir da base definida pelos segmentos; Indicam (apontam) dentro de seu segmento qual o endereço da informação a ser acessada; Cada um deles possui 16 bits; SP (Stack Pointer) - Apontador de pilha (Stack Point) - endereço de retorno de chamada de subrotina (CALL) ou de subrotina de atendimento de interrupção ou de registros “salvos” na memória de pilha; 16 BP (Base Pointer) - Apontador de base; IP (Instruction Pointer) - Apontador de instruções (programa) - indica na memória de instruções qual a próxima instrução; SI (Source Index) - índice fonte - indica o endereço do dado a ser lido da memória dados; DI (Destination Index) - índice destino - indica o endereço do dado a ser escrito na memória dados. 2.2.4 - Associação entre Registradores apontadores / segmentos Quando o microprocessador 8086 vai acessar uma dos três segmentos, ele calcula o endereço de onde está contida ou deve ser armazenada a informação na memória principal, da seguinte maneira (o resultado está em hexadecimal): SP + 10 * SS SI + 10 * DS DI + 10 * ES IP + 10 * CS = endereço da posição da pilha; = endereço do dado a ser lido da MP; = endereço do dado a ser escrito na MP; = endereço da próxima instrução. Exemplo: Calcular endereço físico da próxima instrução a ser lida da MP. Sendo CS = 123AH IP = 341BH 341BH - endereço apontador 123AOB - endereço segmento (início) 157BBH - endereço físico da instrução Endereço Físico 00000 Memória . . . 123A0 Endereço Apontador 341B . . . 157BB Endereço Próxima Instrução . . . CS Início da memória de Instrução Range de Segmento = 64 Kbytes Pois IP=16 bits 2239F Fig. 2.2 17 2.2.5 - Registro de Estado (PSW - Program Status Word) Principais características 9 bits de estado = 9 bits de flags Flags divididos em : condicionais e controle Formatação (Fig. 2.3) 15 14 13 12 11 10 9 8 7 6 OF DF IF TF SF ZF 5 4 3 AF 2 PF 1 0 CF 8080 FLAGS Fig. 2.3 PSW do 8086 Flags condicionais CF - Carry - setado quando ocorre um vai um ("carry-out") no bit mais significativo do byte ou da palavra; PF - Paridade - Setado quando a paridade é par; resetado quando a paridade é impar; AF - Auxiliar Carry - Setado quando ocorre um "Carry-Out" no bit 3 do byte ou no bit 7 da palavra (Word); ZF - Zero - Setado quando o resultado da operação é zero; SF - Sinal - Setado quando o resultado da operação é negativo; Flag de Controle DF - Utilizado para movimentação de "strings" (Conjunto de dados) DF = 0 Movimento na forma crescente de endereços DADO 1 DADO2 . Strings . . DADO N DF = 1 Movimento na forma decrescente de endereços 18 IF - Interrupt Enable: quando setado a UPC alerta pedido de interrupção externa, caso contrario não; TF - TRAP: quando setado após a instrução, é gerada automáticamente uma interrupção interna. Utilizado normalmente na chamada de uma sub- rotina. Armazena endereço da próxima instrução para que o microprocessador retorne ao programa principal que estava executando. ENDEREÇO FFFFH FFFDH FFFBH 1 ordem de 2 entrada 3 dos dados FFFBH FFFDH FFFFH 1 ordem de 2 saída 3 dos dados Último a entrar é o primeiro a sair (memória 4F0) Fig. 2.4 Endereçamento da pilha (Stack) Endereço n-2 n-1 N n +1 Ender. de retorno 0 Programa na MP . CALL 0 10H 20H Endereço 2010h p-2 p-1 p+1 Ender. de retorno 1 Subrotina 0 na MP Inicio SC0 Endereço CALL 1 31H 41H 41314 Subrotina 1 na MP Inicio SB1 Retorno 1 Retorno 0 Fig. 2.4 Chamadas de sub-rotinas 19 2.3 - Modo de Endereçamento Modo de Endereçamento é o caminho no qual o operando é especificado. O operando pode estar contido em: registros internos da CPU; própria instrução; memória principal; porta E/S; Os endereços dos operandos da memória ou portas de E/S podem ser calculados de modos diferentes. Estes modos definem o modo de endereçamento, e são: 2.3.1 - Imediato Os operandos, de 8 ou 16 bits são dados ou valores que fazem parte da instrução. Portanto o dado é especificado na instrução. Código de Operação Operando Operando Fig. 2.5 - Formato de Endereçamento Imediato Exemplo: MOV AX, ABFDh (3 bytes) 1º Byte DC 2º Byte FD Instrução Low Byte (Registro AX Exemplo: MOV AL, ABh REG AL ABh 3º Byte AB High Byte Valor) (2 bytes) ------ significado: o byte menos significativo do AX recebe o valor ABh Dados: IP = 0000h e CS = 0100h Calculo do endereço físico da instrução endereço físico da próxima instrução a ser executada = IP + 10*CS 0000h + IP = endereço do apontador de instrução 20 01000h - 10 * CS = endereço do início do segmento de código na MP ________ 01000h endereço físico da próxima instrução Endereço Conteúdo da memória Instrução 01000h B0 - código de operação MOV AL, ABH 01001h AB – Operando 01002h XX Próxima instrução Conteúdo dos Registros Internos da UPC Antes da instrução 00000 . . . 00100 . . . AH AL XX XX Após a instrução 00002 . . . 00100 . . . AH AL XX AB IP CS AX IP CS AX 2.3.2 - Direto O endereço do dado está contido na instrução. Esta parte da instrução é denominada deslocamento. 1º Byte Código de operação 2º Byte deslocamento menos significativo 3º Byte deslocamento mais significativo Exemplo: MOV CX, [ 1 2 3 4 h] (4 bytes) CX conteúdo de memória com endereço de deslocamento 1 2 3 4 h Supondo : IP = 0000h , CS= 0100h e DS = 0200h Endereço físico instrução : 0000 + 1000 = 1000h Endereço físico dado : 1234 + 10*200 = 3234H 21 Endereço 1000 1001 1002 1003 1004 . . . 3234 3235 Conteúdo da Memória 8B OE 34 12 XX . . . AA BB Instrução Código operação MOV CX, [1234H] Endereço Próxima instrução . . . operando fonte . . . Conteúdo dos Registros internos da UPC 00000 . . . 00100 00200 . . . CH XX IP . CS DS . CL XX CX 00004 . . . 00100 00200 . . . CH BB IP CS DS CL AA CX Observe que o conteúdo do endereço menor é armazenado no “registro menos significativo” e o conteúdo do endereço maior é armazenado no “registro mais significativo”. 2.3.3 Registradores O dado está no registro interno que é especificado pela instrução Exemplo: MOV AX, BX (2 bytes) AX Conteúdo do registro BX ------ o dado está no registro BX, e, ele será carregado no registro AX. Supondo : IP = 0000h, CS = 0100h e BX = 1234h 22 endereço físico da instrução = 1000h Endereço 01000 01001 01002 Conteúdo da memória 8B - código de operação C3 XX Instrução MOV AX, BX Próxima instrução Conteúdo dos Registros Internos da UPC Antes da instrução 00000 . . . 00100 . . . XXXXX 01234 Após a instrução IP CS AX BX 00002 . . . 00100 . . . 01234 01234 IP CS AX BX 2.3.4 - Indireto O endereço do dado é especificado pelo conteúdo da memória ou do registrador contido na instrução. No endereçamento indireto por registrador, o endereço do dado está nos registros de base BX ou BP ou nos de índice DI ou SI, que estão especificados na instrução. Exemplo : MOV AX , [SI] (2 bytes) AX conteúdo da memória cujo endereço é dado pelo registro SI. Supondo : IP = 0000h, CS = 0100h, SI = 1234h e DS = 0200h Endereço físico da instrução = IP + 10 * CS = 1000h Endereço físico do dado = SI + 10 * DS = 1234 + 2000 = 3234h 23 Endereço 01000 01001 01002 . . . 03234 03235 8B 04 XX Conteúdo da memória - código de operação Instrução MOV AX, [SI] Próxima instrução . . . Operando fonte AA BB Conteúdo dos Registros Internos da UPC Antes da instrução 0000 . . . 0100 0200 . . . XXXX . . . 1234 Após a instrução IP CS DS AX SI 0002 . . . 0100 0200 . . AH . AL BB AA . . . 1234 IP CS DS AX SI 2.3.5 - Base O endereço do dado é obtido pela soma de um deslocamento, contido na instrução, com o conteúdo do registro de base BX ou BP. 24 Exemplo : MOV [BX] . Beta, AL ou MOV [BX + Beta], AL (4 bytes) Supondo : IP = 0000h, CS = 0100h , BX = 1000h, DS = 0200h e Beta = 1234h Endereço físico da instrução = 1000h Endereço físico do dado = (Beta + BX) + 10 * DS = (1234 + 1000) + 2000 = 4234h Endereço Conteúdo da memória Instrução 01000 88 - código de operação 01001 07 MOV [BX]. Beta, AL 01002 34 - Operando 01003 12 01004 XX Próxima instrução . . . . . . . . . 04234 CD Dado no endereço destino após execução Conteúdo dos Registros Internos da UPC Antes da instrução 0000 . . . 0100 0200 . . . BC IP 0004 . . . 0100 0200 . . . CS DS CD 1000 . . Após a instrução AX BX BC IP CS DS CD 1000 . . AX BX 2.3.6 - Índice 25 O endereço do dado é obtido pela soma de um deslocamento, contido na instrução, com o conteúdo do registro de índice SI ou DI, similar ao endereçamento por base. Exemplo : MOV AL, ARRAY. [SI] ou MOV AL, [ARRAY + SI} (4 Bytes) Supondo : IP = 0000h, CS = 0100h , SI = 2000h, DS = 0300h e ARRAY = 1234h Endereço físico da instrução = 1000h Endereço físico do dado = (Array + SI) + 10*DS = ( 1234 + 2000 ) + 3000 = 6234h Endereço 01000 01001 01002 01003 01004 . . . 06234 Conteúdo da memória - código de operação 8A 44 34 12 XX Instrução MOV AL, Array [ SI ] - Operando Próxima instrução . . . . . . F4 Conteúdo dos Registros Internos da UPC Antes da instrução 0000 . . . 0100 0300 . . . XX Após a instrução IP 0004 . . . 0100 0300 . . . CS DS XX . . . 2000 AX SI XX IP CS DS F4 . . . 2000 AX SI 2.3.7 - Endereçamento de E/S 26 O endereçamento de Entrada/Saída (I/O) é utilizado juntamente com as instruções IN e OUT para acessar portas de periféricos, podendo ser fixo ou variável. Neste tipo de endereçamento o registrador A ( AX, AH ou AL) deverá sempre ser utilizado como registro fonte ou destino. Canal Fixo Até 255 periféricos I N AL, porta AL Conteúdo da porta OUT porta, AX Porta Conteúdo de AX Canal Variável O registro DX é o único que pode ser utilizado para endereçar um canal variável Até 64k periféricos IN AX, DX AX Conteúdo da porta endereçada por DX OUT DX, AH Conteúdo da porta endereçada por DX Conteúdo AH 2.3.8 - Resumo dos modos de Endereçamento Imediato - dado está na instrução; Direto - endereço do dado está na instrução; Registrador - dado está no registro especificado na instrução; Indireto - endereço do dado está nos registro de base BX ou BP especificado na instrução; Base - endereço do dado é a soma de um deslocamento (dado na instrução), com o conteúdo do registro de base BX ou BP; Índice - similar ao de base, porém utiliza os registros de índice SI ou DI.. 27 Fig. Computação do endereço da memória Registros envolvidos nos modos de endereçamento Instruções Dados Direto Registro Indireto Base Indice Baseado Indexado X Pilha 28 CAPITULO III 3 - Programação 3.1 - Utilitário Debug 29 O Debug é um utilitário fornecido junto com o MS-DOS, que tem a finalidade de depurar programas.Através do Debug é possível fazer pequenos programas, ou testar outros programas feitos através de um compilador assembler. O Debug permite que se execute um programa passo a passo, isto é, uma instrução de cada vez. A cada instrução executada é possível examinar o estado dos registradores e da memória antes de prosseguir. Não serão mostrados todos os comandos ou sintaxes do debug, isto pode ser visto em algum livro que trate especificamente deste assunto. Apenas será mostrado a forma prática e objetiva de seus principais comandos, o que permitirá que sejam feitos e testados os primeiros programas dados como exemplos. 3.1.1 - Como Entrar no Debug Localizar o Debug no disquete do DOS. Para entrar no programa digitar :>Debug <Enter>. Ao entrar no Debug, apenas surgirá um tracinho (-) no canto esquerdo do vídeo, antecedendo o cursor. 3.1.2 - Comandos do Debug Comando R (registers) O comando R exibe no vídeo o conteúdo de todos os registradores e a próxima instrução a ser executada pelo programa sendo ‘ debugado’. Este comando também permite que se coloque qualquer valor em qualquer registrador. Para ver o valor de todos os registradores digitar: R <Enter> Para colocar um valor em um registrador, digitar: R[registrador] <Enter> Exemplo RAX <Enter> ( p/ carregar AS) Após digitar <Enter> será mostrado no vídeo o valor atual do registrador desejado e pode-se digitar um novo valor, ou apenas pressionar <Enter> para não alterar o valor atual. Comando A (assembler) O comando A entra num minicompilador assembler do Debug. Através dele é possível fazer pequenos programas, como o mostrado a seguir: Digitar A100 <Enter> Neste caso, o numero 100 é o endereço onde o programa será armazenado. 30 Surgirá um endereço formado por 8 dígitos. Os primeiros 4 dígitos representam o registrador CS e portanto são o segmento do programa. Os últimos 4 dígitos deverão ter o endereço 0100, que foi especificado no comando. Digitar o seguinte programa, sempre digitando < Enter> no final de cada linha. MOV MOV ADD MOV INT AS, 200 BX, 300 AS, BX [200], AS 3 Ao terminar de digitar o programa, teclar <Enter> deixando uma linha em branco para sair automaticamente do miniassembler. Comando U (unassembler) O comando U ‘disassembla’ um programa, convertendo os dígitos de volta em instruções. O formato deste comando é: U[endereço] <Enter>: Digitando apenas U <Enter> ele recomeçará a partir do ultimo endereço exibido. Digite U100 <Enter> Para ver o programa implementado. Comando T (trace) Este comando permite a execução passo a passo de um programa. A cada instrução executada, ele mostra o estado dos registradores e da memória envolvida na operação. Este comando é utilizado para executar e testar o programa dado acima. O formato do comando T, é: T = [segmento; endereço] <enter> Comando D (dump) Este comando permite que a memória seja examinada. Pode-se ver qualquer região da memória do computador , mas neste caso, será visto o endereço 200 do segmento de dados apontado por DS para ver o resultado da operação feita pelo processador. A sintaxe deste comando é: 31 D[segmento: endereço] <enter> Se o segmento for omitido, o segmento atual do registrador Ds será usado. Se o endereço for emitido, o último endereço mostrado será o ponto de partida, isto quer dizer que digitando apenas D <enter> o próximo bloco da memória será mostrado. Digite D200 <enter> (é omitido o segmento) Aparece o conteúdo do endereço 200 do segmento DS. Seguindo o exemplo acima, neste endereço observa-se o valor 500, sendo 00 no endereço 200 e 05 no endereço 201. Comando Q (quit) Este comando é usado para sair do Debug voltando para o DOS. Digite: Q <enter> 3.2 - Exemplo de programa escrito em linguagem assembly, utilizando o utilitario Debug 32 3.2.1 - Instrução MOV Usada para atribuir valores a um registrador ou a um endereço da memória. É uma das instruções fundamentais para manipulação dos dados. Na prática, qualquer programa, por menor que seja, sempre usará ao menos uma instrução MOV. Pode ser usada para carregar valores nos registradores ou para guardar valores na memória. Exemplos: MOV MOV MOV MOV MOV AX, 01 AX , BX [100], AX AX, [100] [100], 01 ;Carrega o registrador AX com o valor 1 ;Carrega o registrador AX com valor do registrador BX ;Põe o valor de AX no endereço 100 ;Coloca em AX o conteúdo do endereço 100 ;Coloca o valor 1 no endereço 100 Note que as chaves [ ] são utilizadas para especificar o conteúdo de um endereço. O simples fato de esquecer de usar um destes símbolos durante a programação, pode comprometer todo o resultado do programa, pois o valor obtido pode ser totalmente diferente do desejado. Veja exemplo: MOV MOV AX, 100 AX, [100] ;o registrador AX valerá 100 ;o registrador AX terá o valor contido no endereço 100 3.2.2 - Instrução ADD Soma dois valores e coloca o resultado da operação em um registrador ou um endereço da memória. A operação sempre é realizada somando-se o elemento que está depois da vírgula ao elemento que está antes, atribuindo ao primeiro elemento o resultado da soma. Exemplos: ADD AX, BX ADD ADD AX, 01 AX, [100] ADD [100], AX ADD [100], 01 ;Soma o valor de AX com o valor de BX e põe o resultado em AX. ; Soma ao valor de AX + 1 e deixa o resultado em AX. ;Soma ao valor de AX o conteúdo do endereço 100 e deixa o resultado em AX. ;Soma ao conteúdo do endereço 100, o valor de AX e deixa o resultado no endereço 100. ;Soma ao conteúdo do endereço 100, o valor 1 e deixa o resultado no endereço 100. 33 3.2.3 - Instrução SUB Subtrai dois valores e coloca o resultado da operação em um registrador ou em um endereço da memória. A operação sempre realizada subtraindo o segundo elemento do primeiro, e o resultado deixado no primeiro elemento. Exemplos: SUB SUB SUB SUB AX, BX AX, 01 AX, [100] [100], AX SUB [100], 01 ;Subtrai de AX o valor de BX ;Subtrai 1 de AX ;Subtrai de AX o conteúdo de endereço 100 ;Subtrai do conteúdo do endereço 100, o de AX. ;Subtrai 1 do conteúdo do endereço 100 valor 3.2.4 - Programa exemplo: Somar dois valores Neste exemplo, temos dois números gravados na memória. Queremos saber qual é a soma destes números e colocar o resultado em um lugar seguro da memória. Para obter o resultado é preciso ler em AX o primeiro número, somá-lo ao segundo e guardar o resultado na memória. Veja como isto é feito. MOV ADD MOV AX, [valor1] AX, [valor2] [resultado], AX ;obtém o valor do primeiro número ;soma com o segundo número ;salva o resultado na memória Como você pode perceber, neste exemplo nós realizamos a soma de sois números sem utilizar nenhum valor específico. No lugar dos valores, utilizamos os nomes : Valor1, valor2, resultado. Isto é chamado de LABEL (Rótulo). Um LABEL é utilizado para dar nome a um endereço da memória. Desta forma fica mais fácil fazer o programa, pois deixamos para o compilador a tarefa de transformar o label em um endereço correspondente. Podemos também atribuir um valor predefinido a um label, não precisando ser necessariamente um endereço de memória. 3.2.5 - INSTRUÇÃO CMP Compara dois valores e atualiza o FLAG de acordo com o resultado. Esta instrução é fundamental durante o programa. Ela é usada como base para a tomada de decisões pelo programa. Para um exemplo prático, imagine que o programa precisa saber se a tecla <ENTER> foi pressionada. Para chegar à conclusão sobre esta questão, o programa faz um MOV para AX com o valor da última tecla pressionada, então executa um CMP com AX (compara AX) e o valor da tecla 34 <ENTER>. Se os valores forem iguais, o FLAG Zero será colocado em 1 e o programa poderá verificar isso, decidindo o que fazer. Exemplos: CMP CMP CMP CMP CMP AX, BX AX, 01 AX, [100] [100], AX [100], 01 ; compara AX com BX ; compara AX com 1 ; compara o valor de AX com o conteúdo do endereço 100 ; compara o conteúdo do endereço 100 com o valor de AX ; compara o conteúdo do endereço 100 com o valor 1 A instrução CMP, causa alterações em vários BITS do FLAG. Quando uma instrução CMP é executada, internamente o microprocessador executa uma subtração, ou seja, ele subtrai o segundo elemento do primeiro. Exemplificando, a instrução CMP AX, 01 será processada internamente como "subtraia 1 de AX". Note que isto só ocorre internamente, e que na prática o valor de AX não será modificado. Mas você deve saber disso para poder planejar o destino do seu programa, quando for necessário basear- se no resultado de uma comparação para tomar uma decisão. Após uma instrução CMP, o FLAG assumirá a seguinte modificação: BIT DA FLAG ZERO CARRY PARITY ASSUMIRÁ O VALOR será 1, se os dois valores comparados forem iguais. Caso contrário será 0 será 1 se o segundo elemento for maior que o primeiro. Será 0 se o segundo Elemento for menor ou igual ao primeiro. será 1 se o número de bits 1 do valor que resultar da operação. Sempre que uma instrução CMP ou qualquer outra instrução aritmética é executada, o FLAG é alterado para indicar o resultado da operação. Através de um conjunto de instruções que operam baseadas no estado do FLAG, será possível ao programa tomar decisões baseadas no resultado da operação. |Veja no próximo item, que instruções são estas. 3.2.6 - INSTRUÇÕES DE SALTO CONDICIONAL Este conjunto de instruções permite direcionar o programa, baseando- se no estado do FLAG. Este conjunto é bem completo e permite que se obtenha um controle total sobre o rumo a ser tomado. 35 Seu nome original é "JUMP" (salto em inglês, e de fato, elas podem causar um salto para frente ou para trás, determinando qual será a próxima instrução a ser executada pelo microprocessador. Como o resultado do uso destas instruções será baseado no estado atual do FLAG, é importante que você conheça mais um pouco sobre este registrador. O FLAG, como já foi explicado antes, é um registrador de 16 bits que tem a finalidade de mostrar o estado atual do microprocessador, bem como acusar qual foi o resultado da última operação executada por ele. Para fazer isso, cada bit deste registrador recebeu um nome e uma letra que identifica. 7 dos 16 bits foram reservados para uso futuro do fabricante do microprocessador, portanto apenas 9 bits nos interessam. Cada bit pode conter o valor 0 ou 1, dependendo do resultado da última operação. É o próprio microprocessador que atualiza o valor destes bits, durante a execução de uma instrução. Já explicamos, um pouco atrás, os três bits do FLAG usados para exercer algum tipo de controle sobre o microprocessador, que são: TRAP (T), DIRECTION (D) e INTERRUPT - ENABLE (I). 3.3 - Manipulação de Dados Existem um conjunto de instruções específicas para a manipulação de dados. Elas são um complemento da instrução MOV pois são ideais para manipular uma seguência de dados. Elas permitem a manipulação de dados em forma de BYTEs ou WORDs. Uma particularidade delas é que são utilizadas com registradores predefinidos, isto é, você não pode especificar os registradores que serão usados. A operação sempre será feita com DS:SI para a origem dos dados e ES:DI para o destino dos dados. Assim, você deverá colocar os endereços nestes registradores antes de usar uma destas instruções. 3.3.1 -Instrução MOVSB e MOVSW Estas instruções copiam um byte (MOVSB) ou uma Word (MOVSW) DS:SI para ES:DI. Tomando como exemplo a instrução MOVSB, podemos dizer que da copia o byte contido no endereço apontado por DS:SI para o endereço apontado por ES:DI. Mas baseando-se no Flag de direção os registradores SI e DI serão incrementados ou decrementados automaticamente. Veja o exemplo: 36 Faremos um programa que transfere o valor contido no endereço: 0100:0000 para o endereço 0200:0000. CLD ; zera o Flag de direção (seleciona o avanço) MOV AX,0100 ;valor para o segmento DS MOV DS, AX ; MOV AX,0200 ;valor para o segmento ES MOV ES,AX ; MOV SI,0000 ;endereço 0000 (onde está a informação) MOV DI,0000 ;endereço 0000 (para onde vai a informação) MOVSB ;copia o valor de DS:DI para ES:DI e incrementa ;os valores de SI e DI. 3.3.2 - Instrução REP Esta instrução faz com que a instrução de manipulação de dados seja REPETIDA o numero de vezes estabelecido através do registrador CX. Por exemplo para copiar 10 bytes de um local para outro, coloque 10 em CX e use o comando REP MOVSB. Aplicando esta regra no programa anterior ele ficaria assim: CLD MOV MOV MOV MOV MOV MOV MOV REP AX,0100 DS,AX AX,0200 ES,AX SI,0000 DI,0000 CX, 10 MOVSB ;zera o Flag de direção (seleciona o avanço) ;valor para o segmento DS ; ;valor para o segmento ES ; ;endereço 0000 (onde está a informação) ;endereço 0000 (para onde vai a informação) ;número de bytes a mover ;copia o valor de DS:DI para ES:DI e incrementa ;os valores de SI e DI, decrementa CX e repete ;até que CX = 0. Também poderíamos Ter feito este programa usando CX = 5 e a instrução MOVSW no lugar da MOVSB, pois uma Word tem 2 bytes e o resultado da rotina seria a transferencia de 10 bytes (5*2). 3.3.3 - Instruções LODSB - LODSW e STOSB - STOSW LODSB carrega AL com o byte apontado por DS:SI, enquanto LODSW carrega AX com a Word apontada por DS:DI. STOSB salva o valor de AL no endereço apontado por DS:DI, e STOSW salva o valor de AX no endereço apontado por DS:DI. Após qualquer uma destas instruções o registrador SI ou DI, conforme o caso, é incrementado ou decrementado conforme o estado da Flag de DIREÇÂO. Estas 37 instruções são especialmente úteis quando é preciso realizar algum tipo de processamento com uma seguência de informações. Por exemplo, se tivéssemos uma tabela com 10 valores e fosse necessário somar 2 a cada um deles faríamos assim: MOV MOV endereço CLD MOV PRXM: LODSB ADD STOSB LOOP SI, TABELA_VALORES DI, SI CX, 10 AL,2 PRXM ;posiciona SI na tabela de valores ;DI também com o mesmo ;direção para frente ; a tabela tem 10 valores ;obtém um valor ; soma 2 valor ;devolve o valor à tabela ;repete até CX = 0 Neste exemplo, usando a instrução LOOP que será explicada mais adiante. 3.3.4 - Instrução CMPSB - CMPSW Estas instruções são utilizadas para comparar dados como faz a instrução CMP, porém são usadas para comparar seguencias de dados. Elas comparam o byte ou Word apontado por DS:SI com o byte ou Word apontado por ES:DI e incrementam ou decrementam SI e DI, conforme o estado da Flag de DIREÇAÔ. Para comparar uma seguencia é necessário utiliza-las em conjunto com a instrução REP. Um exemplo de emprego destas instruções seria na seguinte operação: é achar o nome de uma pessoa que está numa relação de nomes. O programa seria assim: CLD MOV PRXM: MOV MOV MOV REP JZ ADD CMP JNZ Nome_ERR:..... . . . Nome_OK BX, Lista_nomes DI,BX SI, Nome CX, 25 CMPSB Nome_OK BX, 25 [BX], 000h PRXM ;direção para frente ;posiciona DI na lista de nomes ;posiciona SI no nome procurado ;tamanho dos nomes ;compara um nome ;nome localizado ;posiciona no próximo nome ;final da tabela? ;não compara o próximo ; nome não está na lista ;nome está na lista 38 3.4 - Manipulação de Bits Um conjunto de instruções que permitem a manipulação de cada bit de um byte. Estas instruções são úteis em todas as circunstancias e são muito usadas na manipulação de imagens gráficas, programas de comunicação, e cálculos. Este grupo de instruções usa regras que se aplicam a todas as instruções pertencentes a ele. Como a função delas todas é a mesma: rotaciona bits, você pode especificar quantos bits quer rotacionar colocando o valor em CL, ou rotacionar uma vez usando o valor 1 direto. O número máximo que você pode usar em CL é 32, pois o 80286 e 80386 limitam a este valor máximo para impedir que num ambiente multitarefa, o microprocessador fique ocupado por muito tempo em um só programa. Exemplos: RCL MOV RCL AX, 1 CL, 10 BX,CL ; rotaciona AX uma vez ; ;rotaciona BX dez vezes 3.4.1 - Instrução RCL Rotaciona para esquerda usando o CARRY. DADO CARRY O CARRY é colocado no bit 0 do byte ou Word empurrando todos os bit, um bit mais para esquerda, ultimo bit do byte (o 7) ou da Word ( o 15) é colocado no CARRY. 3.4.2 - Instrução RCR Rotaciona para direita usando o CARRY. DADO CARRY 39 O CARRY é colocado no bit mais á esquerda (bit 7 do byte ou 15 da Word) empurrando todos os bits, um bit mais para direita, o bit 0 do byte ou Word é colocado no CARRY. 3.4.3 - Instrução ROL Rotaciona para esquerda. CARRY DADO Os bits do byte ou Word são deslocados um bit para a esquerda e o bit mais à esquerda é colocado no bit 0. O Carry também recebe o bit mais à esquerda, porém seu estado anterior é desprezado. 3.4.4 - Instrução ROR Rotaciona para direita DADO CARRY Os bits do byte ou Word são deslocados um bit mais para a direita e o bit 0 é colocado no ultimo bit do byte ou Word. O CARRY também recebe o bit 0. 3.4.5 - Instruções SAL e SHL Deslocamento aritmético á esquerda. Estas duas instruções tem a mesma função, ou seja, é a mesma instrução com dois nomes. CARRY DADO Um bit de valor 0 é inserido no primeiro bit do byte ou Word, deslocando os outros bits para a esquerda. O último bit ( 7 ou 15) é colocado no CARRY. 40 A instrução SAL pode ser utilizada para multiplicar um número por múltiplos de 2. Exemplo: MOV SAL SAL AL, VALOR AL, 1 AL, 1 ;obtém o valor ;multiplica por 2 ;multiplica por 4 Quando a primeira instrução SAL é executada, AL é multiplicado por 2, e na Segunda instrução AL também é multiplicado por 2, resultando em AL= AL * 2 * 2, ou seja, AL * 4. Veja porque: Valor inicial: 2 Em binário : 00000010 Após um sal: 00000100 = 4 3.4.6 - Instrução SHR Deslocamento aritmético á direita. DADO CARRY CARRY Um bit 0 é inserido à direita do byte ou Word. Os outros bits são deslocados para a direita e o bit 0 é colocado no CARRY. A instrução SHR pode ser usada para dividir um número por múltiplos de 2. Exemplo: MOV AL, VALOR ;obtém o valor SAL AL, 1 ;divide por 2 SAL AL, 1 ;divide por 4 Quando a primeira instrução SHR é executada, AL é dividido por 2, na Segunda instrução AL também é dividido por 2, resultando em AL = AL / 2 / 2, ou seja , AL / 4. Veja porque: Valor inicial : 10 Em binário : 00001010 Após um SAL: 00000101 = 5 Observe que a divisão terá sempre como resultado um valor exato, ou seja, não haverá quebrados ou restos. Para obter o resto poderíamos usar a instrução RCL, explicada anteriormente, copiando o CARRY para usar a instrução RCL, explicada anteriormente, copiando o CARRY para outro registrador depois de cada SAL, desta forma: 41 MOV MOV SAL RCL SAL RCL AL, VALOR BL,000h AL, 1 BL, 1 AL, 1 BL, 1 ;obtém o valor ;zera BL para guardar o resto ;divide por 2 ;copia CARRY em BL ;divide por 4 ;copia CARRY em BL No final desta rotina, AL terá o resultado da divisão e BL o resto. 3.4.7 - Instrução SAR Deslocamento á direita com repetição. 7 6 5 4 3 2 1 0 CARRY Desloca todos os bits do byte ou Word para a direita e não alterando o bit mais À esquerda, ou seja, o bit 7 do byte é copiado para o 6 mas é mantido intacto. 3.4.8 - Aplicando as Instruções que Manipulam Bits Mostraremos alguns exemplos de uso das instruções que acabamos de apresentar: 3.4.8.1 - RCL e SAL Podem ser usadas em conjunto para multiplicar um valor com mais de 16 bits. Considere que AX:BX contém um valor de 32 bits que deve ser multiplicado por 2, a rotina seria assim. SAL RCL BX, 1 AX, 1 ;multiplica a parte baixa ;multiplica a parte alta O primeiro SAL multiplica a parte baixa do valor ( a primeira Word) e deixa o bit 15 no CARRY. A instrução RCL copia o CARRY para BX (a Segunda Word) e multiplica-o deslocando os bits para a esquerda. Desta forma conseguimos transferir 1 bit de um registrador para outro. 42 3.4.8.2 - RCR e SHR Da mesma forma que o item anterior, estas instruções usadas em conjunto podem dividir valores maiores que 16 bits. Considerando um valor de 32 bits guardado em AX:BX, uma rotina para dividi-los por 2 seria assim: SHR RCR AX, 1 AX, 1 ;divide a parte alta ;divide a parte baixa No exemplo acima, o bit 0 de AX é transferido para o bit 15 de BX, passando antes pelo CARRY. 3.5 - Instruções Aritméticas Um outro conjunto de instruções é específico para cálculos. Embora outras instruções que não pertencem a este grupo também possam ser usadas para cálculos, como as instruções de manipulação de bits, neste conjunto incluiremos apenas as exclusivas para cálculos. 3.5.1Instruções ADD e ADC Usadas para somar (Adição). ADD soma dois valores sem considerar o Flag Carry enquanto ADC considera o CARRY na soma. Exemplo: Para apenas somar dois valores podemos fazer: MOV ADD AX,Valor_1 AX,VALOR_2 ;AX = AX + VALOR_2 Porém se a soma destes dois valores resultar num valor maior que 16bits ou 65535, haverá um estouro gerando um bit a mais. Este bit a mais será colocado no Flag Carry, já que AX comporta apenas 16bits. Sendo assim o resultado desta soma estará em Carry Flag + AX. Se quisermos obter resultados maiores que 16 bits, precisamos utilizar dois registradores para receber o resultado da soma e usar a instrução ADC para considerar o estado do Carry. Exemplo: Somaremos dois valores de 16 bits e usaremos BX:AX para guardar o resultado de 32bits. MOV MOV ADD ADC AX,VALOR_1 BX,000h AX,VALOR_2 BX,0 ;valor inicial de AX ;BX é zerado ;soma os dois valores ;soma BX com 0 para transferir ;a ele o valor de CARRY ;BX = BX + 0 + CARRY 43 Neste exemplo, AX é carregado com o primeiro valor, BX é zerado para posteriormente receber a parte do valor de 32 bits. Após somar AX com o segundo valor, o CARRY será um se tiver ocorrido um estouro. Usando a instrução ADC BX, 0 o valor do CARRY 0 ou 1 será somado a BX que foi previamente zerado. O resultado da soma será um número de 32 bits formado por BX:AX. 3.5.3 - Instrução MUL Usada para multiplicação de valores. Pode ser usada de duas formas, para multiplicar um valor de 8 bits por AL ou um valor de 16 bits por AX. Se a multiplicação for por AL, o resultado estará em AX, se a multiplicação for por AX, o resultado estará em DX:AX. Por exemplo: Para multiplicarmos um valor de 8 bits por outro de 8 bits, fazemos: MOV MUL MOV AL, valor_1 valor_2 [resultado], AX ;valor de 8 bits ; multiplica por outro valor de 8 bits ;salva resultado de 16 bits Para multiplicarmos um valor de 8 bits ou 16 bits por outro de 16 bits, fazemos: MOV MOV MUL MOV MOV AX, valor_1 CX, valor_2 CX [resultado], AX [resultado + 2], DX ;valor de 8 ou 16 bits ;valor de 16 bits ; multiplica ;salva resultado de 32 bits ; O resultado da operação é automático 16 ou 32 bits conforme o operando usado. Se for usado um operando de 8 bits, o resultado será de 16 bits e estará todo em AX. Exemplos: MUL MUL MUL CL DL 20 ;AX = AL * CL ;AX = AL * DL ;AX = AL * 20 Se for usado um operando de 16, o resultado será de 32 bits e estará em DX:AX, exemplos: MUL MUL MUL CX DX 8000h ;DX:AX = AX * CX ;DX:AX = AX * DX ;DX:AX = AX * 8000h 44 3.5.4 - Instrução DIV Usada para divisão. Seu emprego é semelhante à instrução MUL. Ela pode dividir o valor de AX por outro de 8 bits, ou dividir o valor de DX:AX por outro de 16 bits. Se a divisão for por 8 bits o resultado da divisão estará em AL enquanto AH guardará o resto da divisão. Se for por 16 bits, AX terá o resultado e DX o resto. Exemplos: DIV DIV DIV DIV CL 10 CX 500 ;AL = AX / CL (AH = resto) ;AL = AX / 10 (AH = resto) ;AX = DX:AX / CX (DX = resto) ;AX = DX:AX / 500 (DX = resto) 3.5.5 - Instrução DEC Decrementa um resgistrador ou um valor. Decrementar significa subtrair 1. Com toda operação aritmética o resultado da operação afeta diretamente os FLAGS de indicação. Útil em muitas ocasiões, ela é utilizada principalmente em controle de loops. Exemplos: MOV [CONTADOR], 10 PRXM: MOV AX, [BX] ADD AX, CX STOSW ADD BX, 2 DEC [CONTADOR] JNZ PRXM ;contador = 10 ;processa informação ; ; ; ;decrementa contador ;continua até que contador = 0 DEC pode ser usado com registradores ou endereços, exemplo: DEC DEC DEC AX BL [VALOR] ;AX = AX - 1 ;BL = BL - 1 ;VALOR = VALOR - 1 3.5.6 - Instrução INC É o inverso da instrução DEC, ou seja, ela incrementa um registrador ou um valor. Incrementa significa somar 1. INC, da mesma forma que DEC pode ser usado com registrador ou endereços, exemplo: INC INC INC DX AL [VEZES] ;DX = DX + 1 ;AL = AL + 1 ;VEZES = VEZES + 1 45 3.6 - Instrução Lógicas Assim como em todas as linguagens, no Assembly também temos valores lógicos ( e, ou , Tc...) porém o seu conceito é um pouco diferente das outras linguagens. 3.6.1 - Instrução AND Produz um 'e' lógico. AND faz uma comparação bit a bit entre dois valores e gera um terceiro valor contendo apenas os bits onde os dois valores iniciais continham 1. Exemplo: 1 2 0 0 AND AND AND AND 1=1 0=0 1=1 0=0 AND pode ser usado para isolar bits: MOV AND . . . AL, [INFORMAÇÃO] AL, 03H ;obtém informação ;isola os bits 0 e 1 ;continua o processamento Pede ser usado para testar um bit: MOV AND JNZ CL,[INDICADOR] CL, 004H PROCESSA ;obtém indicador de estado ;testa o bit 3 ;salta se o bit for 1 3.6.2 - Instrução OR Ou lógico. Ou compara um bit a outro e caso um deles seja 1, produz como resultado 1. Exemplos: 1 1 0 0 OR OR OR OR 1=1 0=1 1=1 0=0 De forma que o resultado só será 0 se os dois bits envolvidos forem zero. 46 OR pode ser usado para juntar dois valores em um só: MOV AL, [DIA] ;obtém o dia OR AL,[MÊS] ;junta ao mês . ;processamento . OR pode ser usado par mudar o valor de um bit para 1: MOV OR . . AL, [INDICADOR] AL, 02H ;obtém indicador ;seta o bit 1 de AL ;processa... 3.6.3 - Instrução XOR XOR soma um bit a outro e gerando o resultado 0 se os dois bits forem 1 ou 0 Exemplos: 1 XOR 1 = 0 1 XOR 0 = 1 0 XOR 1 = 1 0 XOR 0 = 1 XOR, assim como OR e AND, são, entre outras, muito utilizadas na manipulação de imagens gráficas. 3.7 - Instrução de Desvio e Transferencia de Controle Neste grupo, estão as instruções que permitem ao programa chamar sub-rotinas ou causar desvios condicionais dentro de um mesmo bloco. Apenas 3 tipos de instruções pertencem a ele: JUMP relativo, JUMP e CALL. 3.7.1 - Instrução JUMP relativo JUMP relativo significa SALTO. Neste caso, um salto condicional e relativo. Condicional porque ele só é executado se a condição estabelecida for verdadeira, e RELATIVO porque o salto é um número de bytes para frente ou para trás em RELAÇAO ao endereço em que está. Estas instruções são fundamentais em qualquer programa, pois através delas é que se ireciona o processamento, adequando-o às circunstancias. Elas são equivalentes ``a instrução IF das linguagens de alto nível. 47 Um grande conjunto de instruções integram este grupo, permitindo que se teste qualquer condição. As condições são sempre estabelecidas pelo estado do registrador FLAG. Algumas instruções deste grupo são: JZ JNZ JC JNC salta se Z = 1 salta se Z = 0 salta se C = 1 salta se C = 0 Como são sempre condicionadas ao estado do FLAG, estas instruções são sempre utilizadas após outra instrução que altere o FLAG, como: CMP, ADD, SUB, AND, OR e Tc..., exemplo: MOV AL, [NUMERO] ;obtém um número AND AL, 01 ;testa o bit 1 JZ PAR ;salta se o número é par ... ;processa o numero ímpar PAR:. . . O programa acima, testa se um número ´s par ou ímpar checando o bit 0 do número. Números ímpares sempre tem o bit 0 = 1. Se o número for par, a instrução AND AL, 01 fará o FLAG Z = 1 e a instrução JZ será válida. A relação completa dos JUMPs relativos está no APENDICE B 3.7.2 - Instrução JUMP Executa um desvio incondicional. A instrução JUMP não é relativa. Ao usá-la é necessário especificar o endereço real para onde o programa deve desviar, É claro que o programador não precisa saber o endereço, basta utilizar um LABEL e deixar o resto por conta do compilador. Esta instrução é muitas vezes utilizada em conjunto com os JUMPs relativos, já que estes são condicionais mas não podem desviar para endereços distantes (seu limite é 128 bytes à frente ou 127 para trás), enquanto JUMP não é condicional mas pode ir para qualquer endereço. Exemplo: INÍCIO: MOV ... MOV CMP JNZ JMP CONT: . . . ... JMP FIM: ... AX, [VALOR] AL, [SELEÇÂO] AL, FIM CONT FIM INÍCIO ;inicio do programa ;processamento do programa ;obtém seleção do usuário ;selecionou fim ;não, continua processamento ;sim, termina o programa ;processa ;volta ao início ;finaliza o programa 48 No exemplo acima, JUMP foi utilizado para voltar ao início do programa, ficando em loop. Durante o programa é testada a condição de FIM, que se for verdadeira permitirá que outro JMP desvie a uma sub-rotina que termina o programa. 3.7.3 - Instrução CALL Esta instrução, como JUMP, permite que se desvie para qualquer endereço da memória. Porém enquanto JUMP é utilizado para mudar o rumo do programa, CALL é especifico para executar uma sub-rotina. Ao executar uma instrução CALL o microprocessador guarda no STACK o endereço da instrução subsequente ao CALL no programa. A execução passa então para o endereço especificado no CALL. Ao encontrar uma instrução RET, o microprocessador recupera o endereço do STACK e volta a executar a instrução que estava após o CALL. Exemplo: Programa MOV CALL MOV CALL ... ... AX, NOME IMPRIME AX,FONE IMPRIME ;obtém endereço do nome ;sub-rotina - imprime nome ;obtém endereço do fone ;sub-rotina - imprime o fone ;processa Sub-rotina IMPRIME: MOV BX, [POSIÇÃO] ... ... ;rotina para imprimir ;processa RET ;retorna O programa acima dá o exemplo de uma sub-rotina que imprime os dados apontados por AX. O programa principal posiciona AX na informação desejada e chama a sub-rotina que imprime a informação. Ao encontrar um RET o controle volta ao programa principal. A instrução RET significa o retorno ao programa principal, após a execução da sub-rotina. 49 3.8 - Controle de Loop Embora já tenham sido vistas instruções que são utilizadas para controlar loops, como as instruções de saltos condicionais, existem algumas instruções especificas para isto. 3.8.1 - Instrução de LOOP Esta instrução decrementa o valor do registrador CX e executa um salto relativo se CX não for 0. Um programa que precise obter 3 números pelo teclado pode usá-la desta forma: MOV PRXMNUM: CALL CALL LOOP CX, 3 PEGA_NUMERO GUARDA_NUM PRXMNUM ;3 números ;obtém 1 numero ;guarda o número ;faz um loop ate CX = 0 A instrução LOOP usa a mesma forma de endereçamento dos JUMPS relativos. E pode ser substituído por eles, desta forma: ... DEC CX JR NZ<PRXMNUM ;programa ;decrementa CX ;executa ate CX = 0 3.8.2 - Instrução LOOPZ e LOOPNZ Operam da mesma forma que loop, porém devem ser usadas após uma instrução que afete o FLAG Z, pois além de decrementar CX, elas testam este FLAG. Exemplo: MOV CX, 10 ;serão 10 tentativas OUTRO: CALL OBTEM_NUMERO ;obtém um numero em AL CMP AL, 100 ;número = 100 ? LOOPNZ OUTRO ;não, loop ate CX = 0 ... ;processa O programa acima, obtém 10 números através da sub-rotina OBTEM_NUMERO, caso um número = 100 seja obtido, o loop é encerrado antes de completar os 10. Caso contrário ele só terminará quando tiverem sido obtidos 10 números. 3.9 – Acesso ao Stack Pointer 3.9.1 – Instruções PUSH e POP 50 A instrução PUSH salva o valor de um registrador no STACK. POP recupera este valor. Estas intruções são normalmente utilizadas para salvar o conteúdo prévio de um ou vários registradores, durante a execução de uma sub-rotina. Exemplo: Um programa de banco de dados chama uma sub-rotina que tem a função de coletar informações pelo teclado. Porém, a sub-rotina não pode alterar o valor dos registradores AX, BX, CX e DX, pois eles contém informações utilizadas pelo corpo principal do programa. As instruções PUSH e POP podem ser utilizadas desta maneira: Corpo principal … CALL SUB_ROTINA … ;processamento prévio ;chama a sub-rotina ;continua o processamento Sub- rotina SUB_ ROTINA: PUSH PUSH PUSH PUSH ... ... ... POP POP POP POP AX BX CX DX DX CX BX AX ;salva AX no STACK ;salva BX no STACK ;salva CX no STACK ;salva DX no STACK ;recupera DX ;recupera CX ;recupera BX ;recupera AX 51 3.10 - Entrada e Saída As instruções deste grupo, são utilizadas para a comunicação do microprocessador com outros componentes do hardware do computador. Duas instruções compõe o grupo: IN e OUT. A primeira é responsável pela leitura de informações e a segunda pelo envio de informações. O controle do alto falante interno do computador, por exemplo, é feito através das instruções IN e OUT. Algumas placas de funções específicas, como placa de som, placa de comunicação, placa de scanner e Tc..., também usam as instruções IN e OUT para se comunicarem com o microprocessador. O formato destas instruções é: IN IN OUT OUT AL,PORTA AL, DX porta, AL DX, AL ;lê a porta em AL ;lê em AL pela porta DX ;envia AL pela porta ;envia AL pela porta DX A porta é um endereço de até 16 bits. Cada periférico tem seus próprios endereços de entrada e saída que são documentados nos seus respectivos manuais técnicos. 3.11 - Interrupções As interrupções podem ser encaradas como uma forma de chamar determinadas rotinas que podem estar em posição variáveis da memória. Normalmente a memória do computador do endereço 0 até o 03FFh é reservada para guardar vetores de interrupção. Cada vetor de interrupção é formado por 4 bytes que guardam o endereço de uma rotina. Este endereço é formado pelo segmento (2 bytes) e endereço (2 bytes). Quando é pedida uma interrupção por algum dispositivo externo, é especificado um número de 0 a 255. Este número é utilizado pelo microprocessador para indexar um dos 256 vetores que existem na memória. O microprocessador obtém um endereço no vetor correspondente e passa o controle para a rotina. Ápós isto, o programa é desviado para a rotina de atendimento da específica interrupção. Tanto a BIOS quanto o DOS usam as interrupções como forma de acesso a suas rotinas. Esta foi a melhor forma encontrada para que não existissem problemas de desencontros com outros programas. No caso da BIOS, sabe-se que cada marca de computador tem a sua própria BIOS com as suas próprias rotinas de tamanho variados. E no caso do DOS, a cada vez que é carregado na memória pode estar em um endereço diferente. Então como avisar aos programas quais são os endereços das diversas rotinas do DOS e da BIOS, se a cada momento eles estão em posição diferentes da memória? Fácil, basta usar as interrupções que nunca mudam de lugar. Por este motivo os endereços das rotinas da BIOS e do DOS estão nos vetores de interrupção, e para acessá-los é utilizada a instrução INT. As interrupções também podem ser geradas por um dispositivo de hardware. Neste caso, o funcionamento é idêntico, porém o processo é desencadeado pelo hardware que fornece ao computador o número do vetor de interrupção desejado. 52 O indicador IE do registro da palavra de estado do processo (PSW) pode ser ligado ou desligado para habilitar ou desabilitar as interrupções, através das instruções STI e CLI. Quando uma interrupção é gerada por hardware, o microprocessador interrompe o que está fazendo para executar a interrupção, passando o controle do programa à rotina correspondente, se esta tiver maior prioridade. Antes de passar o controle para a rotina da interrupção, o microprocessador guarda no STACK POINTER o endereço atual sendo executado (registradores IP), e segmento de código (registradores CS) e o indicador de estados (FLAG). A última instrução de uma rotina de interrupção deve ser IRET e não RET. Isto porque IRET recupera os dados do STACK e devolve o controle ao programa original. Exemplos: INT 021h INT 010h ;chama interrupção 21h (DOS) ;chama interrupção 10H (BIOS) 53 Bibliografia: SHIMIZU, T; BERLARDI, A. A - "Linguagem Assembly" - Editora Atlas, 1993 PIERE, E; SCHOLZE, R; - "Assembler - Aprenda como programar seu PC" - Editora Érica, 1993. INTEL CORP. ; ASM-86Macro Assembler Operating Instructions for 8086 – based systems; ed.Inter Books, 1982. TRIEBEL, WALTER A. ; AVTAR SINGH; The 8088 and 8086 microprocessors: programming, interfacing, software, hardware and applications: including 80286, 80386, 80486 and pentium pr; ed.Prentice Hall, 1997, second edition. BARRY, B. BREY; Programming the 80286, 80386, 80486 and pentium – based personal computer; ed. MacMllan Pub Co.,1996. 54