Instruções: A Linguagem de Máquina – Aula 02

Post on 05-Feb-2016

41 views 6 download

description

Professor: André Luis Meneses Silva E-mail/msn: andreLuis.ms@gmail.com Página: www.dcomp.ufs.br/index.php/docentes:Andre. Instruções: A Linguagem de Máquina – Aula 02. Introdução. Instruções para tomada de decisões Desvio incondicional Suporte a procedimentos no hardware do computador - PowerPoint PPT Presentation

Transcript of Instruções: A Linguagem de Máquina – Aula 02

Instruções: A Linguagem de Máquina – Aula 02

Professor: André Luis Meneses SilvaE-mail/msn: andreLuis.ms@gmail.com

Página: www.dcomp.ufs.br/index.php/docentes:Andre

Introdução

Instruções para tomada de decisões Desvio incondicional

Suporte a procedimentos no hardware do computador

Endereçamento no mips para operandos e endereços de 32 bits.

Endereçamento em desvios condicionais e jumps.

Instruções para a tomada de decisões.

O que distingue um computador de uma calculadora simples? Capacidade de tomar decisões com base nos dados

de entrada e valores calculados. Em linguagens de alto nível, estruturas típicas

de decisão são as construções if, algumas vezes acompanhadas de goto e rótulos (labels).

O assembly do mips possue duas instruções que dão suporte para tomada de decisões (beq e bnq).

Instruções para a tomada de decisões.

beq Instrução utilizada quando desejamos comparar se

dois valores armazenados em registradores, são iguais.

Sintaxe: beq $r1, $r2, L1,

Onde $r1, $r2 são os registradores cujos valores armazenados vão ser comparados.

Se os valores são iguais, a sequência de execução pula para a instrução que possui o rótulo L1.

Instruções para a tomada de decisões.

bnq Instrução utilizada quando desejamos comparar se dois

valores armazenados em registradores, são diferentes. Sintaxe:

bnq $r1, $r2, L1, Onde $r1, $r2 são os registradores cujos valores armazenados

vão ser comparados. Se os valores são diferentes, a seqüência de execução pula para

a instrução que possui o rótulo L1.

beq e bnq são instruções conhecidas como desvios condicionais. Desvios condicionais são instruções que requerem a

comparação de dois valores e que leva em conta uma transferência de controle subseqüente para um novo endereço.

Desvio incondicional

O assembly do Mips também dá suporte a instrução de desvio incondicional. Basicamente, um desvio incondicional é uma

instrução que sempre diz que o processador deverá seguir o desvio.

A instrução para isso é a instrução j (jump). Sintaxe:

j rotulo # pula para a instrução precedida por # rotulo

Instruções para a tomada de decisões.

Vamos ver estas instruções na prática. Dada a seguinte construção Java, qual o assembly

obtido?if ( i == j)

f = g + h;else

f = g – h;

Instruções para a tomada de decisões.

Vamos ver estas instruções na prática. Dada a seguinte construção Java, qual o assembly

obtido?if ( i == j)

f = g + h;else

f = g – h;

Calma isso ainda não é o assembly

Instruções para a tomada de decisões.

Bne $s3, $s4, Else

Instruções para a tomada de decisões.

Bne $s3, $s4, Else

add $s0, $s1, $s2

Instruções para a tomada de decisões.

Bne $s3, $s4, Else

add $s0, $s1, $s2

J Exit;

Instruções para a tomada de decisões.

Bne $s3, $s4, Else

add $s0, $s1, $s2

J Exit;

ELSE:sub $s0, $s1, $s2

Instruções para a tomada de decisões.

Bne $s3, $s4, Else

add $s0, $s1, $s2

J Exit;

ELSE:sub $s0, $s1, $s2

Exit:

Instruções para a tomada de decisões.

Observem que o programador assembly não precisa se preocupar com o cálculo do endereço utilizado nos desvios.

E um laço, como seria? Nos restringiremos ao laço while. Os demais

laços são bastante semelhantes.

Instruções para a tomada de decisões.

Seja o seguinte código Javawhile (save[i] == k)

i += 1;

Qual seria o assembly correspondente, supondo que os valores de i e k estão nos registradores $s3 e $s5, e a base do array save em $s6?

Instruções para a tomada de decisões.

1. Realizar a leitura de save[i]Loop: sll $t1, $s3, 2 # $t1 = 4 * iadd $t1, $t1, $s6 # $t1 = endereço de

save[i]lw $t0, 0($t1) # $t0 = save[i] 2. Teste do loop, terminando se save[i] != kBne $t0, $s5, Exit #vá para exit se save[i] != k 3. Senão, adiciona 1 a i e volta para o início.add $s3, $s3, 1 # i = i + 1j LoopExit:

Instruções para a tomada de decisões.

Código fonte

while (save[i] == k)i += 1;

Resultado FinalLoop: sll $t1, $s3, 2add $t1, $t1, $s6 lw $t0, 0($t1)

Bne $t0, $s5, Exit

add $s3, $s3, 1j LoopExit:

Instruções para a tomada de decisões.

Estas sequências de instruções sem desvios (exceto, possivelmente, no final) e sem destinos de desvio ou rótulos de desvio (exceto, possivelmente, no início) são conhecidas como blocos básicos.

Blocos básicos são muito importante e constituem uma das etapas do projeto de compiladores, basicamente, através deles, podemos realizar algumas otimizações no programa.

Instruções para a tomada de decisões.

As instruções slt e slti Embora o teste de igualdade e desigualdade seja

bastante popular, precisamos também de um outro tipo de comparação.

A instrução slt é usada quando desejamos verificar se o valor armazenado em um registrador é menor que o valor armazenado em um outro registrador.

A instrução slti é usada quando desejamos verificar se o valor armazenado em um registrador é menor que o valor de uma constante literal.

Instruções para a tomada de decisões.

Sintaxe de uso slt $t1, $r1, $r2

Basicamente, se o valor em $r1 for menor que o valor em $r2, $t1 recebe o valor 1. Caso contrário, $t1 recebe o valor 0.

slti $t1, $r1, constante Basicamente, se o valor em $r1 for menor que o

valor da constante literal, $t1 recebe o valor 1. Caso contrário, $t1 recebe o valor 0.

E se quisermos fazer algo do tipo se i < j faça, tem como?

Senão tiver como fazer, porque o MIPS é assim?

Instruções para a tomada de decisões.

Realmente não temos como fazer isso, mas há uma razão bastante lógica.

Se o MIPS tivesse uma instrução que já desempenhasse ambos os papéis ele estaria ferindo sua restrição de projeto (no qual, o processador seria dotado de apenas instruções simples).

Logo é preferível quebrar esta instrução mais complexas em duas mais simples e, caso tenhamos necessidade de reproduzirmos um se i < 4 então, utilizamos as instruções apresentadas anteriormente.

Instruções para a tomada de decisões.

O registrador $zero No MIPS temos um registrador especial que sempre

armazena o valor 0. O registrador $zero em conjunto com slt, slti, beq,

bne criam todas as condições relativas: igual, diferente, menor que, maior que, menor ou igual e maior ou igual.

Instruções para a tomada de decisões.

Instruções Case/Switch O modo mais simples de implementá-las é através

de uma cadeia de if-then-else.

Outra forma de implementá-las é através de uma tabela de endereços de desvio. Para apoiar tais situações, o processador MIPS

possui a instrução de desvio incondicional jr (jump register) que pula para o endereço armazenado pelo registrador.

Sintaxe: jr $r1

Clareando as idéias

Memória de Instruções

0123...9

00000000000001000000100000001100

...00100100

Memória de Dados

0123...9

00000000000001000000100000001100

...00100100

Processador

Clareando as idéias

Memória de Instruções

0123...9

00000000000001000000100000001100

...00100100

Memória de Dados

0123...9

00000000000001000000100000001100

...00100100

Processador

Suporte a procedimentos no hardware do computador

Procedimento ou função é um recurso bastante empregado em linguagens de alto nível para modularizar o código.

Podemos ver um procedimento como um espião, pois um espião: Sai com um plano secreto, adquire recursos, realiza

a tarefa, cobre seus rastros e depois retorna ao ponto de origem com o resultado desejado.

De forma similar funcionam os procedimentos, vamos ver como isso funciona.

Suporte a procedimentos no hardware do computador

Na chamada de uma função, alguns registradores do MIPS são reservados para propósito especial, são eles: $a0 - $a3: quatro registradores de argumento, para

passar parâmetros $v0-$v1: dois registradores de valor, para valores

de retorno $ra: um registrador de endereço de retorno, para

retornar ao ponto de origem.

Suporte a procedimentos no hardware do computador

Além de alocar esses registradores, o assembly do MIPS inclui uma instrução apenas para tratamento de funções/procedimentos.

Esta instrução desvia para um endereço e simultaneamente salva o endereço da instrução seguinte no registrador $ra.

Esta instrução se chama jal (jump-and-link). Sua sintaxe é a seguinte: jal EndereçoProcedimento

Suporte a procedimentos no hardware do computador

Existe também um outro registrador de próposito específico denominado PC (program counter).

Este registrador armazena o endereço da instrução atual sendo executada.

Então qual endereço salvo por jal no registrador $ra?

Suporte a procedimentos no hardware do computador

Existe também um outro registrador de próposito específico denominado PC (program counter).

Este registrador armazena o endereço da instrução atual sendo executada.

Então qual endereço salvo por jal no registrador $ra? $PC + 4;

Suporte a procedimentos no hardware do computador

Então, quando ocorre uma chamada de função: 1. O programa que chama (caller), coloca os

valores de parâmetro em $a0 - $a3. 2. Em seguida, caller, utiliza jal X para desviar o

procedimento para o procedimento X (o procedimento chamado é denominado callee).

3. O callee, então, realiza os cálculos, coloca os resultados em $v0-$v1.

4. Em seguida o callee retorna o controle para o caller usando jr $ra.

Suporte a procedimentos no hardware do computador

E se precisarmos de mais argumentos além dos 4 registradores para argumentos e os dois para valores de retorno?

O que o callee deve fazer?

Suporte a procedimentos no hardware do computador

O callee executa um processo denominado spilling registers. A idéia básica é armazenar em memória valores

que serão necessários posteriormente para a execução do programa.

A estrutura de dados utilizada para fazer este armazenamento é uma pilha.

Para controle desta pilha, o MIPS possui um registrador especial denominado stack pointer ($sp). O stack pointer sempre aponta para o último

endreço alocado mais recentemente.

Suporte a procedimentos no hardware do computador

10000Stack Pointer Stack

Suporte a procedimentos no hardware do computador

Valor do registrador $r110000

Stack Pointer Stack

9996

crescimento

Suporte a procedimentos no hardware do computador

Valor do registrador $r110000

Stack Pointer Stack

9996Valor do registrador $r2

9992

crescimento

Suporte a procedimentos no hardware do computador

Qual seria o código assembly do seguinte procedimento C?

int exemplo_folha (int g, int h, int i, int j){int f;f = (g + h) – (i + j);return f;

}

Suporte a procedimentos no hardware do computador

Fazendo o mapeamento dos elementos da função para registradores, teremos:

int exemplo_folha (int g, int h, int i, int j){int f;f = (g + h) – (i + j);return f;

}

$a0, $a1, $a2, $a3

$s0

$t0 e $t1$v0

Suporte a procedimentos no hardware do computador

Percebam a existência de registradores conflitantes, ou seja, que já podem estar sendo utilizados ($s0, $t0 e $t1).

int exemplo_folha (int g, int h, int i, int j){int f;f = (g + h) – (i + j);return f;

}

$s0

$t0 e $t1

Suporte a procedimentos no hardware do computador

Alguém chama jal exemplo_folha#Liberando registradoresexemplo_folha:addi $sp, $sp, -12 # ajusta a pilha criando

#espaço para três itens

sw $t1, 8($sp) #salva registradores $t1, $t0 e $s0

sw $t0, 4($sp) # para ser usado depoissw $s0, 0($sp)

$t1

$t0

$s0$sp

Suporte a procedimentos no hardware do computador

add $t0, $a0, $a1 # $t0 = g+hadd $t1, $a2, $a3 # $t1 = i + jsub $s0, $t0, $t1 # $s0 = (g+h) – (i + j), ou

seja, f

#Retornando o valor de fadd $v0, $s0, $zero

int exemplo_folha (int g, int h, int i, int j){int f;f = (g + h) – (i + j);return f;

}

Suporte a procedimentos no hardware do computador

#Restaurando os três valores antigos dos registradores

lw $s0, 0($sp)lw $t0, 4($sp)lw $t1, 8($sp)addi $sp, $sp, 12

# E finalmente, o procedimento terminajr $ra # Desvia de volta à rotina que chamou

$t1

$t0

$s0$sp

$sp

Suporte a procedimentos no hardware do computador

No exemplo anterior, salvamos os valores dos registradores $t0 e $t1. Porém existem casos em que o valor de um registrador pode ser descartado sem problemas.

Por causa disso, o mips separa 18 dos registradores em dois grupos: $t0-$t9: 10 registradores temporários que não são

preservados pelo procedimento chamado (callee) em uma chamada de procedimento.

$s0-$s7: 8 registradores salvos que precisam ser preservados em uma chamada de procedimento (se forem usados, o procedimento chamado os salva e restaura).

Suporte a procedimentos no hardware do computador

O código mostrado anteriormente é perfeitamente aceitável para funções que não fazem chamadas a outras funções.

Funções que não fazem chamadas a outras funções são denominadas folhas. As que chamam outras são denominadas aninhadas.

E para funções aninhadas, como seria?

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Salvando registradoresfact:

addi $sp, $sp, -8 #ajusta pilha para 2 itenssw $ra, 4($sp) # salva o endereço de retorno

sw $a0, 0($sp) # salva o argumento n

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Condiçãoslti $t0, $a0, 1 # teste para n < 1Beq $t0, $zero, L1 # se n>=1 vai para L1

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Senão for maior que 1, devolve o valor 1.addi $v0, $zero, 1 # retorna 1addi $sp, $sp, 8 # retira 2 itens da pilhajr $ra #retorna para depois de jalPessoal, não entendi. Alguém me

responda. Porque não restauramos os valores da pilha nesse caso?

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

addi $v0, $zero, 1 # retorna 1addi $sp, $sp, 8 # retira 2 itens da pilhajr $ra #retorna para depois de jalObservem que no caso base, o valor do

registrador $ra e $a0 não é alterado, logo não é necessário recuperar os valores dele da memória

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Se for maior que 1L1: addi $a0, $a0 -1 #arg1 = n – 1;

jal fact #chama fact(n-1);

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Restaurando registradores.#A próxima instrução é onde fact retorna.lw $a0, 0($sp) #retorna de jal: restaura nlw $ra, 4($sp) #restaura endereço de

retornoaddi $sp, $sp, 8 #ajusta stack pointer

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

#Devolvendo o novo $v0

mul $v0, $a0, $v0 # retorna n * fact( n - 1)jr $ra # retorna para o procedimento que o chamou

int fact (int n){ if (n < 1) return (1); else return (n * fact(n – 1));}

Suporte a procedimentos no hardware do computador

Para resumo de história, quem salva o que na pilha?

Caller Salva os registradores de argumentos. Salva os registradores temporários ($t0-$t9) que

serão necessários após a chamada da função. Callee

Salva os registradores salvos ($s0-$s8) Salva o registrador que armazena o endereço de

retorno ($ra)

Suporte a procedimentos no hardware do computador

Além dos elementos já citados, a pilha também pode ser utilizada para armazenar outros elementos. Alguns exemplos são variáveis locais (tais como

arrays ou estruturas) que não cabem em registradores.

Este segmento da pilha relativo a um procedimento é conhecido como frame ou registro de ativação.

Em geral os processadores possuem um processador específico para apontar para o início do frame. Este registrador é conhecido como frame pointer ($fp).

Suporte a procedimentos no hardware do computador

Suporte a procedimentos no hardware do computador

O frame pointer, assim como o stack pointer, é utilizado nas instruções que alocam e recuperam dados do frame.

Mas se ambos registradores possuem a mesma funcionalidade, então para que termos o frame pointer?

Suporte a procedimentos no hardware do computador

O frame pointer, assim como o stack pointer, é podem ser utilizados nas instruções que alocam e recuperam dados do frame.

Mas se ambos registradores possuem a mesma funcionalidade, então para que termos o frame pointer? O frame pointer, ao contrário do stack pointer, não

tem seu valor alterado durante o procedimento. Logo se torna mais fácil recuperar dados utilizando o valor do stack pointer.

Suporte a procedimentos no hardware do computador

O assunto que vimos até o momento, é aplicado apenas para variáveis automáticas (ou seja) locais aos procedimentos.

No entanto ainda faltam tratar dois casos: Variáveis globais (ou estáticas). Estruturas de dados dinâmicas.

Estes elementos, quando em memória, não são alocados no stack.

Os dados estáticos podem ser acessados através do registrador $gp.

Os dados dinâmicos é armazenado em uma região de memória denominada heap.

Suporte a procedimentos no hardware do computador

Endereçamento no MIPS para operandos e endereços de 32 bits

Até o momento, consideramos que endereços de memória já estariam em registradores. Lembrem-se que cada endereço de memória é representado por 32 bits.

Lembrando que as instruções com constantes (imediatas) do mips só trabalham com 16 bits.

Como fazemos para armazenar endereços de memória em registradores?

Endereçamento no MIPS para operandos e endereços de 32 bits

Precisamos usar duas instruções; nova instrução “load upper immediate”:

Endereçamento no MIPS para operandos e endereços de 32 bits

Depois, precisamos acertar os bits de ordem inferior, por exemplo:

Endereçamento em desvios condicionais e jumps

Já a instrução de desvio condicional jump utiliza um terceiro formato de instrução (tipo j).

Nessas instruções temos 26 bits para especificar o local para onde desejamos desviar.

Endereçamento em desvios condicionais e jumps

No entanto, para desvios condicionais temos um problema:

Nosso campo de desvio só possui 16 bits. Fazendo os cálculos, 216 = 65536; E agora pessoal, será que no MIPS só

podemos fazer programas de no máximo 64 kbytes?

Endereçamento em desvios condicionais e jumps

Para evitar este problema, os processadores trabalham com uma técnica denominada de endereçamento relativo.

Basicamente a idéia é associar o endereço expresso em uma instrução condicional a um outro elemento (registrador). Qual seria este registrador?

Endereçamento em desvios condicionais e jumps

Para evitar este problema, os processadores trabalham com uma técnica denominada de endereçamento relativo.

Basicamente a idéia é associar o endereço expresso em uma instrução condicional a um outro elemento (registrador). Qual seria este registrador?

O registrador utilizado é o PC. Lembrem-se o PC a todo momento se atualiza, armazenando o endereço da instrução atual, sendo executada.

Endereçamento em desvios condicionais e jumps

Porque isso resolve?

Endereçamento em desvios condicionais e jumps

Porque isso resolve? Isso resolve porque, em geral, os endereços de

desvio não ficam muito longe dos locais onde é solicitado o desvio.

Mas e para chamada de funções? Tem algum sentido ela ficar próxima do local do desvio? Como isso é resolvido?

Endereçamento em desvios condicionais e jumps

Porque isso resolve? Isso resolve porque, em geral, os endereços de desvio

não ficam muito longe dos locais onde é solicitado o desvio.

Mas e para chamada de funções? Tem algum sentido ela ficar próxima do local do desvio? Como isso é resolvido? Lembrem-se que para funções utilizamos j ou jr que

possuem um espaçamento de bits ainda maior (26 bits). Adicionalmente, o MIPS otimiza isso tudo. Seu

endereçamento é feito por palavras (endereçamento alinhado), logo o espaço de endereçamento aumenta em mais 4 vezes.

Formas de endereçamento.

Endereçamento em Registrador Onde o operando é um registrador

add e sub, por exemplo. Endereçamento imediato

Onde o operando é uma constante dentro da própria instrução addi e subi, por exemplo.

Endereçamento de base Onde o operando está no local de memória cujo endereço é a soma de um

registrador e uma constante. lw, sw

Endereçamento relativo ao PC Onde o endereçamento é a soma do PC e uma constante na instrução

bne, beq, por exemplo. Endereçamento pseudodireto.

Onde o endereço de jum são os 26 bits da instrução concatenados com os bits mais altos do PC. j e jr.

Bibliografia

Patterson & Hennessy. Organização e Projeto de Computadores.

Seção 2.6 a 2.7 e 2.9