Programação em Linguagem Assembly (Saltos e Subrotinas)

Documentos relacionados
Assembly Saltos e Subrotinas

Prof. Adilson Gonzaga

Programação de Microprocessadores. Programação de Microprocessadores SEL-433 APLICAÇÕES DE MICROPROCESSADORES I

As 5 partes fundamentais. Linguagem de Programação Pinagem Características Elétricas Ambiente de Desenvolvimento Integrado - IDE

7. PROGRAMANDO O MICROCONTROLADOR. Microcontroladores - Prof: Demantova

1. Instruções de Desvio

5 Programação modular em Linguagem Assembly

CONJUNTO DE INSTRUÇÕES

Sistemas Microprocessados. sato<at>utfpr<dot>edu<dot>br

Familiarização com o ambiente de desenvolvimento da Keil Software. (uvision 51 e dscope 51)

SEL-614 MICROPROCESSADORES E APLICAÇÕES. Adilson Gonzaga

Contador crescente e decrescente...

Conjunto de Instruções do 8051

FORMATO DO PROGRAMA FONTE

Laboratório de Microprocessadores e Microcontroladores

Microcontroladores. Conjunto de Instruções do Prof. Guilherme Peron Prof. Heitor Lopes Prof. Ronnier Rohrich Prof. Rubão

Laboratório de Microprocessadores e Microcontroladores

Neander - características

NEANDERWIN. Algumas características do processador Neander são:

Laboratório de Microprocessadores e Microcontroladores

Símbolos e abreviaturas utilizadas na descrição das instruções

PARTE II - CONJUNTO DE INSTRUÇÕES ARQUITETURA DE COMPUTADORES ANTONIO RAMOS DE CARVALHO JÚNIOR

Interrupção. Prof. Adilson Gonzaga

Conjunto de Instruções (ISA) I

Aula 14 Funcionamento de Processadores (Visão específica)

Linguagem de Montagem do NeanderX

mov R1,10H ; Carrega o dado do endereço 10H em R1 mov R1,#10H ; Carrega 10H em R1

TÉCNICO DE INFORMÁTICA - SISTEMAS

Família 8051 (introdução) 2011/1

ção de Computadores I

Tópicos: 1 - Modos de endereçamento do Pilha e instruções de Pilha. 3 - Instruções que usam pilha: - instrução CALL - instrução RET

EXERCÍCIOS RESOLVIDOS

MICROPROCESSADORES E MICROCONTROLADORES PROVA 2 UMA SOLUÇÃO POSSÍVEL. Obs.: Todas as questões têm valor 2,0. Boa prova e Feliz Natal e Ano Novo!!!!

Revisão da Linguagem C Prof. Evandro L. L. Rodrigues

SEBENTA INTRODUÇÃO Á ALGORITMIA

7. A pilha e subrotinas

Microprocessadores I ELE Aula 7 Conjunto de Instruções do Microprocessador 8085 Desvios

SEL 0415 INTROD. À ORGANIZAÇÃO DE COMPUTADORES

ORGANIZAÇÃO DE COMPUTADORES

Laboratório de Microprocessadores e Microcontroladores

Variáveis primitivas e Controle de fluxo

Microprocessadores I ELE Conjunto de Instruções do Microprocessador 8085 Aula 9 - PILHA E SUBROTINAS -

Grupo I (5 valores) CD AB

Prof. Adilson Gonzaga

Aula 10 Microcontrolador Intel 8051 Parte 2

Estruturas de controlo do C if-else statement

Laboratório de Microprocessadores e Microcontroladores. Experimento 6: Conversor Analógico/Digital e Conversor Digital/Analógico

Conjunto de Instruções (ISA) II

Oprojeto apresenta três níveis de dificuldade: fácil, médio e difícil. No modo fácil tem-se uma

Estruturas da linguagem C. 1. Identificadores, tipos primitivos, variáveis e constantes, operadores e expressões.

Esta pseudomáquina foi criada em homenagem ao homem de Neandertal, o antecessor do homo sapiens.

Introdução ao PIC. Guilherme Luiz Moritz 1. 6 de novembro de DAELT - Universidade Tecnológica Federal do Paraná

CPU. CPU Unidade Central de Processamento. Função: leitura, escrita e processamento de dados

Introdução à Arquitetura de Computadores

Microcontrolador Assembly UTFPR / DAELN Microcontroladores 1 Prof. Gabriel Kovalhuk

Laboratório de Microprocessadores e Microcontroladores. Experimento 7:

MICROPROCESSADORES E MICROCONTROLADORES PROVA 2 - RESPOSTA ESPERADA

Assembly Primeiros Passos

Tipos Primitivos, estruturas de iteração e decisão.

EEC2104 Microprocessadores

Laboratório de Programação II

SSC304 Introdução à Programação Para Engenharias

Temporização Interrupções. Prof: Evandro L. L. Rodrigues. Rotinas de Atraso

CAPÍTULO 4 CONJUNTO DE INSTRUÇÕES

LINGUAGEM C: COMANDOS DE REPETIÇÃO

Engenharia Electrotécnica/ Engenharia Informática Microprocessadores e Aplicações

Algoritmos e Estruturas de Dados I (DCC/003) Estruturas Condicionais e de Repetição

NEANDERWIN - Resumo operacional

Arquitectura de Computadores

Laboratório de Microprocessadores e Microcontroladores

NOTAS DE AULA 06 MICROCONTROLADOR 8051

PROGRAMAÇÃO ESTRUTURADA E ORIENTADA A OBJETOS

Informática I. Aula 9. Aula 9-17/05/2006 1

Algoritmos e Estruturas de Dados I (DCC/003) Estruturas Básicas. Aula Tópico 2

Exercícios resolvidos (aula de 4 de Maio) Resolução:

Transcrição:

Programação em Linguagem Assembly (Saltos e Subrotinas) João Paulo Sousa jpsousa@fe.up.pt Setembro 2005 Conteúdo 1 Objectivos 2 2 Introdução 2 3 Ciclos e estruturas de controlo 2 3.1 Ciclos for()............................................ 2 3.2 Ciclos enquanto()......................................... 3 3.3 Ciclos repetir().......................................... 3 3.4 Estruturas if then else...................................... 4 3.5 Estruturas de escolha múltipla................................. 5 4 Chamada e retorno de subrotinas 6 5 Problemas 7 1

1 Objectivos Consolidação de conhecimentos sobre programação em linguagem assembly da família 51. Familiarização com as instruções de salto e chamada de subrotinas. Utilização da stack e do stack pointer. 2 Introdução Ao contrário do que se passa nas linguagens de alto nível, a linguagem assembly não dispõe mecanismos próprios que conduzam a programar de modo estruturado. Felizmente é fácil implementar algumas estruturas de controlo existentes em linguagens de alto nível recorrendo a instruções de salto. Estude com cuidado os exemplos apresentados e as considerações que os acompanham bem como um dos livros recomendados [2, secção 2.4] e depois resolva os problemas propostos. 3 Ciclos e estruturas de controlo 3.1 Ciclos for() A maneira mais fácil de controlar a execução de determinado grupo de instruções um número de vezes conhecido é utilizar a instrução DJNZ (decrement and jump if not zero) que admite como operando um registo (djnz Rn,rel8) ou uma variável definida em memória (djnz direct,rel8). Repare-se no seguinte exemplo: 2 ; Inicializaç~ao de variáveis em memória 4 ; for(i=0;i<20;i++) { 5 ; temp[i]=0 6 ; } 7 ; tmed=0; 8 ;==================================================================== 9 0014 10 SIZE equ 20 ; Tamanho do vector 11 ---- 12 dseg at 40h ; Segmento (absoluto) de dados 0040 13 temp: ds SIZE ; Vector temperaturas... 0054 14 tmed: ds 1 ; Temperatura média 15 ---- 16 cseg at 0000h ; Segmento (absoluto) de código 0000 7840 17 mov r0,#temp ; Endereço inicial do vector 0002 E4 18 clr a 0003 7F10 19 mov r7,#size ; Tamanho do vector 0005 F6 20 next: mov @r0,a ; Inicializa (limpa) posiç~ao apontada 0006 08 21 inc r0 ; Aponta posiç~ao seguinte 0007 DFFC 22 djnz r7,next ; Salta se R7 for diferente de zero 0009 F6 23 mov @r0,a ; Inicializa (limpa) tmed 24 25 end 1. O segmento de dados começa no endereço 40h (linha 12) e a variável temp ocupa 20 (14h) bytes (linhas 13 e 10), logo é lógico que o endereço da variável tmed (linha 14) seja 54h. 2. O registo R0 funciona como apontador para o vector temp e deve ser inicialmente carregado com o endereço da primeira posição do vector (linha 17). 3. O inicio do ciclo de limpeza do vector temp é assinalado com a etiqueta next (linha 20). Fora do ciclo (linha 19) o registo R7, que funciona como contador, é inicializado com o número de posições do vector. 2

4. A instrução djnz, de decremento, comparação e salto, é codificada em dois bytes: no primeiro está o código da instrução e no segundo a distância entre o endereço da próxima instrução e o endereço destino, neste caso, quatro bytes para trás. Esta distância, que pode tomar valores de 128 a +127, é expressa num byte em complemento para dois, o que justifica a representação FCh (= 4) que se pode constatar na listagem. 5. No fim do ciclo o apontador aponta uma posição além da última do vector temp, ou seja, aponta justamente para a variável tmed pelo que (linha 23) basta escrever lá o valor zero. 3.2 Ciclos enquanto() Um ciclo deste tipo caracteriza-se por ter o teste de controlo logo no início pelo que o conjunto de instruções que encerra pode nunca ser executado. O exemplo seguinte introduz a instrução de salto condicional jz (jump if accumulator is zero) e o salto incondicional jmp: 2 ; Ciclo enquanto 4 ; while(cont!=0) { 5 ; cont-- 6 ; } 7 ; cont=100; 8 ;==================================================================== 9 ---- 10 dseg at 40h ; Segmento (absoluto) de dados 0040 11 cont: ds 1 ; Contador 12 ---- 13 cseg at 0000h ; Segmento (absoluto) de código 14 0000 E540 15 next: mov a,cont ; Teste da 0002 6004 16 jz done ; condiç~ao de fecho do ciclo 0004 1540 17 dec cont 0006 80F8 18 jmp next ; Volta ao início do ciclo 0008 754064 19 done: mov cont,#100 ; Atribuiç~ao final 20 21 end 1. O teste de controlo do ciclo é feito no início de cada iteração (linhas 15 e 16) de modo que se inicialmente a variável cont for nula, o ciclo não se realiza nenhuma vez. 2. O salto na linha 18 é essencial para garantir a repetição do teste no início de cada iteração. A propósito deste salto convém esclarecer que jmp não é uma instrução no sentido estrito da palavra, mas sim uma instrução virtual, própria do assemblador da Keil, que este transforma automaticamente numa de três instruções reais: sjmp (short jump), ajmp (absolute jump) ou ljmp (long jump) consoante a distância ao destino especificada no salto em questão. Aqui, a codificação resultante (80h, linha 18) corresponde, como seria de esperar atendendo à distância, à da instrução sjmp. 3. Mais uma vez a codificação das instruções de salto utilizadas neste exemplo é feita em dois bytes: o primeiro corresponde ao código da instrução propriamente dita e o segundo à distância entre o endereço da próxima instrução e o endereço destino. No primeiro salto (linha 16) essa distância é de quatro bytes para a frente e no segundo é de oito bytes para trás (a que corresponde, em complemento para dois, a representação F8h). 3.3 Ciclos repetir() Um ciclo deste tipo caracteriza-se por ter o teste de controlo no fim de cada iteração pelo que o conjunto de instruções que encerra é sempre executado pelo menos uma vez. Repare-se no seguinte exemplo que 3

introduz a instrução jnz (jump if accumulator is not zero): 2 ; Ciclo repetir 4 ; do { 5 ; cont-- 6 ; } while(cont!=0); 7 ; cont=100; 8 ;==================================================================== 9 ---- 10 dseg at 40h ; Segmento (absoluto) de dados 0040 11 cont: ds 1 ; Contador 12 ---- 13 cseg at 0000h ; Segmento (absoluto) de código 14 0000 1540 15 next1: dec cont 0002 E540 16 mov a,cont ; Teste da 0004 70FA 17 jnz next1 ; condiç~ao de fecho do ciclo 0006 754064 18 mov cont,#100 ; Atribuiç~ao final 19 20 21 ; ou ent~ao, de forma ainda mais resumida 22 0009 D540FD 23 next2: djnz cont,next2 ; Decrementa, testa e repete 000C 754064 24 mov cont,#100 ; Atribuiç~ao final 25 26 end 1. O teste de controlo do ciclo é feito no fim de cada iteração (linhas 16 e 17) por isso, ainda que a variável cont seja inicialmente nula, realiza-se sempre pelo menos uma iteração do ciclo. Neste exemplo concreto esse caso particular daria até origem a que se efectuassem 256 iterações já que, após a primeira, a variável cont passaria de zero para 255 e o ciclo só pararia quando cont voltasse a zero novamente. 2. A instrução djnz (linha 23) permite, neste caso particular, uma codificação alternativa muito eficiente. 3.4 Estruturas if then else As instruções de salto permitem uma implementação confortável deste tipo de estruturas nos programas escritos em assembly. O exemplo seguinte introduz as instruções ljmp (long jump) e cjne (compare and jump if not equal). 2 ; Teste de valores de 16 bits e de valores n~ao nulos 4 ; if(val==0) { 5 ; state++; 6 ; cont=maxcont; 7 ; } 8 ; else { 9 ; if(state==12) 10 ; state--; 11 ; } 12 ;==================================================================== 13 3A98 14 MAXCONT equ 15000 15 ---- 16 dseg at 40h 0040 17 val: ds 2 ; Ocupa 2 bytes 0042 18 cont: ds 2 ; Ocupa 2 bytes 0044 19 state: ds 1 ; Ocupa apenas 1 byte 20 ---- 21 cseg at 0000h 0000 E540 22 mov a,val ; Pega no MSB e 4

0002 4541 23 orl a,val+1 ; conjuga com o LSB 0004 600A 24 jz zero ; Salta se LSB=MSB=0 25 0006 740C 26 mov a,#12 0008 B5440D 27 cjne a,state,done ; Compara state com 12, salta se diferente 000B 1544 28 dec state ; Faz state-- 000D 020018 29 ljmp done 30 0010 0544 31 zero: inc state ; Faz state++ 0012 75423A 32 mov cont,#high(maxcont) ; Guarda MSB de MAXCONT 0015 754398 33 mov cont+1,#low(maxcont) ; Guarda LSB de MAXCONT 0018 34 done: 35 36 end 1. Repare-se na declaração da variável val (linha 17): uma vez que ocupa dois bytes o teste efectuado (linhas 22, 23 e 24) deve incluir ambos. 2. Nas linhas 32 e 33 foram utilizados dois operadores suportados pelo assemblador da Keil (high e low) que calculam, respectivamente, a metade mais significativa e menos significativa de um valor de 16 bits. 3. A instrução de salto incondicional ljmp (linha 29) não era aqui estritamente necessária pois, atendendo ao endereço destino do salto, bastaria utilizar a instrução sjmp. Ela está aqui por causa da sua tradução em código máquina: dos três bytes gerados o primeiro (02h) é o código da instrução propriamente dita enquanto que os dois seguintes (0018h) representam o endereço destino e não a distância do salto. Poderia ter sido utilizada a instrução virtual genérica jmp que teria neste caso como tradução os códigos da instrução sjmp. 3.5 Estruturas de escolha múltipla A instrução de comparação cjne permite também implementar estruturas de escolha múltipla semelhantes às que existem em linguagens de alto nível. Repare-se no exemplo seguinte: 1 ;=============================================================== 2 ; Escolha múltipla 4 ; switch (op) { 5 ; case 1: pin=10;break; 6 ; case 2: pin=50;break; 7 ; case 3: pin=250;break; 8 ; default: pin=0; 9 ; } 10 ;=============================================================== 11 ---- 12 dseg at 40h 0040 13 op: ds 1 0041 14 pin: ds 1 15 ---- 16 cseg at 0000h 0000 E540 17 mov a,op 0002 B40104 18 cjne a,#1,not1 ; Compara com 1 0005 740A 19 mov a,#10 0007 800F 20 sjmp done 0009 B40204 21 Not1: cjne a,#2,not2 ; Compara com 2 000C 7432 22 mov a,#50 000E 8008 23 sjmp done 0010 B40304 24 Not2: cjne a,#3,not Compara com 3 0013 74FA 25 mov a,#250 0015 8001 26 sjmp done 0017 E4 27 Not3: clr a ; Default... 0018 F541 28 done: mov pin,a 29 30 end 5

1. A comparação (linhas 18, 21 e 24) não estraga o registo acumulador pelo que (linha 17) basta carregá-lo uma vez. 2. Novamente se nota nos códigos da instrução de comparação e salto (linhas 18, 21 e 24) a distância entre o endereço da próxima instrução e o endereço destino do salto, quatro bytes nos três casos deste exemplo. 3. A instrução mov final (linha 28) completa a execução. É sempre executada qualquer que seja a escolha feita. 4 Chamada e retorno de subrotinas As instruções de chamada de subrotinas 1 contribuem decisivamente para garantir uma boa estrutura dos programas, ao permitirem dividir uma tarefa complexa em tarefas mais simples, cada uma executada por uma rotina que em devido tempo será chamada. O exemplo seguinte apresenta as instruções de chamada lcall e acall, a instrução de retorno ret e a instrução nop (no operation). 2 ; Atraso configurável 4 ; delay(n) { 5 ; for(i=n;i<0;i--); 6 ; } 7 ; 8 ; delay(50); 9 ; delay(100); 10 ;==================================================================== 11 ---- 12 cseg at 0000h 0000 7F32 13 mov r7,#50 0002 120080 14 lcall delay ; delay(50) 0005 7F64 15 mov r7,#100 0007 1180 16 acall delay ; delay(100) 0009 80FE 17 stop: sjmp stop 18 ---- 19 cseg at 0080h 0080 00 20 delay: nop ; N~ao faz nada 0081 00 21 nop ; a n~ao ser gastar algum tempo 0082 DFFC 22 djnz r7,delay ; Repete R7 vezes 0084 22 23 ret 24 25 end 1. A codificação da instrução lcall (linha 14) é bastante mais simples e directa do que a da instrução acall (linha 16). Naquela aparece de forma evidente o endereço destino enquanto nesta parte do endereço é incorporada no código da instrução [1, páginas 17 e 36]. 2. Poderia ter sido utilizada a instrução virtual genérica call para substituir as instruções lcall e acall. Atendendo à proximidade da rotina, a instrução virtual seria traduzida, em ambos os casos, como se tratasse de uma instrução acall. 3. A instrução de salto (linha 17) é necessária para encravar o programa, caso contrário depois de executada a instrução da linha 16, a subrotina seria novamente executada mas no fim a stack ficaria corrompida por ter sido executado um ret sem previamente ter sido executado um acall ou lcall. 1 Os termos rotina e subrotina serão usados indistintamente para especificar um conjunto de instruções que executam uma tarefa específica no contexto da resolução de um problema mais abrangente. 6

5 Problemas Apresentam-se de seguida alguns problemas que requerem a utilização de instruções de salto e chamada de subrotinas. 1. Escreva um programa que calcule t = (a) são todos inferiores a 13, (b) são todos inferiores a 256. 19 i=0 y[i] supondo que os elementos do vector: Declare as variáveis num segmento de dados absoluto com início em 40h. 2. Traduza à mão, para código máquina, as duas soluções do problema anterior. 3. Escreva uma rotina que calcule a soma (efectuada sem considerar eventuais transportes) dos conteúdos de uma zona de memória com 32 bytes de comprimento e início apontado pelo registo R0. O resultado deve ficar no acumulador. Escreva um programa que chame essa rotina para somar os conteúdos da zona de memória com início no endereço 30h. 4. Escreva uma rotina que calcule o valor mínimo de uma zona de memória com início apontado pelo registo R0 e comprimento indicado no registo R7. No fim o mínimo deve ficar em R7. 5. Escreva a rotina testval que testa se o valor contido no acumulador é positivo, nulo ou negativo e incrementa, respectivamente, as variáveis np, nz e nn. 6. Considere o vector vv[ ], com 50 elementos de um byte cada, representados em complemento para dois. Com base na rotina desenvolvida no problema anterior escreva um programa que comece por fazer np = nz = nn = 0 e de seguida conte quantos elementos positivos, nulos e negativos existem no vector. Declare o vector e as variáveis num segmento de dados absoluto com início em 60h. 7. Escreva um programa que implemente na variável cont definida num segmento de dados absoluto com início em 30h um contador BCD (binary coded decimal) de dois dígitos. Considere os seguintes casos: (a) contagem crescente: 0, 1, 2,..., 99, 0, 1,..., (b) contagem decrescente: 99, 98,..., 2, 1, 0, 99, 98,.... Sugestão: consulte o manual de programação [1, página 27] para perceber como funciona a instrução da (decimal adjust) e utilize-a. 8. Suponha já existente a rotina upcase que converte para maiúscula a letra minúscula contida no acumulador devolvendo o resultado da conversão também no acumulador. (a) Escreva um programa que, recorrendo a essa rotina, converta para maiúsculas um texto com início apontado por R0 e cujo fim é indicado pelo código 0. (b) Escreva a rotina upcase. 9. Apresente duas rotinas diferentes (cjne, movc) para converter o valor contido no acumulador de acordo com a tabela 1. O resultado deve vir no acumulador. O valor 0 1 2 3 É convertido em 100 232 166 250 Tabela 1: Conversão de valores 7

10. Suponha já existente a rotina countbits que conta o número de bits a um da posição de memória apontada por R0, devolvendo o resultado no acumulador. (a) Escreva um programa que, recorrendo a essa rotina, conte o número de bits a um de uma zona de memória com início apontado pelo registo R0 e comprimento indicado no registo R7. O resultado deve ficar na variável nbits, declarada num segmento de dados absoluto. (b) Escreva a rotina countbits. Referências [1] Philips semiconductors; 80C51 family programmer s guide and instruction set; Setembro de 1997. [2] Yeralan, Senser and Ahluwalia, Ashutosh; Programming and Interfacing the 8051 Microcontroller; Addison Wesley, 1995; ISBN 0 201 63365 5. 8