Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
Conjunto de Instruções
It is easy to see by formal-logical methods that there exist
certain [instruction sets] that are in abstract adequate to
control and cause the execution of any sequence of
operations ... The really decisive considerations from the
present point of view, in selection an [instruction set], are
more of a practical nature: simplicity of the equipment
demanded by the [instruction set], and the clarity of its
application to the actually important problems together
with the speed of its handling of those problems.
Burks, Goldstine and von Neumann, 1947
Conjunto de Instruções
As linguagens de máquina são bastante parecidas
entre si. Aprendendo bem uma é fácil aprender outra.
Isto ocorre porque:
♦ Todas são baseadas nos mesmos princípios (arquitetura de von
Neumann);
♦ Existe um conjunto de operações básicas que todas as máquinas devem
fornecer;
♦ Projetistas têm um mesmo objetivo: encontrar uma linguagem que torne
fácil a construção do hardware e de compiladores, maximizando aperformance e minimizando os custos → SIMPLICIDADE
♦ Desta maneira é necessário um processo de Tradução
Tradução
♦ As linguagens LBNs são definidas por uma série deMnemônicos, que são, basicamente, símbolos querepresentam código binários
♦ Por exemplo, no caso do MIPS a instrução de adição érepresentada por add a, b, c• esta instrução determina que o processador some o conteúdo de
dois registradores (b, c) e coloque o resultado em outro registrador(a)
♦ A instrução ADD segue um formato bem definido:• código correspondente ao mnemônico da instrução add• identif icação do registrador destino• identif icação do primeiro operando• identif icação do segundo operando
Assembler x Linguagem de Máquina
♦ Entretanto, para que um programa seja entendido pelamáquina, é necessário que suas instruções estejamcodificadas na forma binária, isto é, na forma de 0s e 1s.
♦ No MIPS, a instrução add corresponde ao código binário000000100000
♦ O conjunto de instruções de uma arquitetura (na forma deMnemônicos) corresponde à Linguagem de Montagem daarquitetura (Linguagem ASSEMBLY)
♦ O conjunto de instruções de uma arquitetura (na formabinária) corresponde à Linguagem de Máquina
Tradutores
♦ Tanto os programas implementados em LANs como emLBN precisam ser traduzidos para a linguagem demáquina do processador
♦ O processo de tradução de uma linguagem de alto nível(LAN) para linguagem de máquina é feito compiladoresou interpretadores
♦ O processo de tradução de uma linguagem de Montagempara linguagem de máquina é feito por tradutoresdenominados de Montadores (ou Assemblers).
Compiladores e Interpretadores
♦ Compiladores são tradutores que após várias fases(análise léxica, análise sintática, análise semântica,geração de código intermediário, otimização de código egeração de código de montagem) geram um programaexecutável.
♦ Na verdade, este programa executável deverá sercarregado em memória para ser executado. Quem fazesta tarefa é um programa do sistema operacional(programa carregador ou loader)
♦ Interpretadores não geram código executável
♦ Os interpretadores traduzem cada instrução do programa(em LAN ou Assembly) e a executam
Interpretadorfonte
(LAN ouAssembly)
execução
Conjunto de Instruções
O conjunto de instruções que veremos vem doMIPS, utilizado por diversas empresas (NEC,Nintendo, Silicon Graphics, Sony, …)
Utilizaremos um simulador de MIPS chamadoSPIM, que tem versões para Unix, Windows eDOS. O SPIM pode ser baixado a partir da URL:
http://www.mkp.com/cod2e.htm
ISA do MIPS (simplificada)
♦ Categorias de Instruções:• Load/Store• Computação• Jump e Desvio• Ponto Flutuante• Gerenciamento de Memória• Especial
♦ 3 Formatos de Instrução: 32 bits
R0 - R31
PC
HI
LO
OP
OP
OP
rs rt rd sa funct
rs rt imediato
Destino do jump
Registradores
add a, a, d # a = b + c + dadd a, a, e # a = b + c + d + e
instrução porlinha
Operações do Hardware
♦ Exigir que toda instrução tenha exatamente trêsoperandos condiz com a filosofia de manter ohardware simples: hardware para númerovariável de parâmetros é mais complexo quepara número fixo.
Princípio #1 para projetos: Simplicidadefavorece a regularidade
Exemplo
♦ Qual o código gerado por um compilador C parao seguinte trecho?
add a, b, c #a = b + csub d, a, e #d = a - e
a = b + c;d = a – e;
sub f, t0, t1 #f (g h) (I j)
Operandos e Registradores
♦ Ao contrário das linguagens de alto nível, operandosde instruções aritméticas não podem ser quaisquervariáveis
→ são escolhidos dentre um conjunto de registradores:
→ Número limitado de endereços especiais construídosdiretamente no hardware;
→ Blocos básicos para construção de computadores, pois sãoprimitivas usadas em projeto de hardware que também sãovistas pelo programador;
Registradores : benefícios
♦ Registradores no hardware, dentro do processador→ mais rápidos que memória
♦ Registradores são de mais fácil utilização porcompiladores:
♦ como um local para armazenamento temporário
♦ podem armazenar variáveis para reduzir o tráfego dememória e melhorar a densidade de código (uma vez queos registradores podem ser especificados com menosbits que um endereço de memória)
Operandos e Registradores
♦ Apesar de podermos nos referir aos registradoresatravés de números, em MIPS existe uma convençãode se utilizar nomes na forma $xy
♦ Usaremos:
♦ $s0, $s1, $s2, … para registradores quecorrespondam a variáveis em C
♦ $t0, $t1, $t2, … para registradores temporáriosnecessários para compilar o programa em instruçõesMIPS
Exemplo
Qual o código gerado por um compilador C para oseguinte trecho?
add $t0, $s1, $s2 # temporário t0 = g + hadd $t1, $s3, $s4 # temporário t1 = i + jsub $s0, $t0, $t1 # f = (g + h) – (I + j)
As variáveis f, g, h, i, j podem ser mapeadas nos registradores$s0, $s1, $s2, $s3 e $s4, respectivamente.
f = (g + h) – (i + j)
p , çfornecer um endereço de memória
Memória
♦ Memória é somente um grande vetor unidimensional,com o endereço atuando como índice no vetor,começando em 0.
3210
10010
1011
Processador
DadosEndereços
Memória
Transferindo dados da memória
♦ A instrução de transferência de dados da memória parao registrador é chamada de load.
♦ Formato:
♦ Endereço de memória acessado é dado pela soma daconstante (chamada de offset) com o conteúdo doregistrador base
Em MIPS, o nome da instrução é:lw (load word)
lw registrador destino, constante (registrador base)
Vetor A = [0,0,0,0,15], com 5 posições, começando no endereço dememória 102. Este endereço é chamado de endereço base dovetor. Assim, 102 é o endereço de A[0],103 o de A[1], ...,106 o deA[4].
Vetor na memória
Dados
Endereços
Endereço basede A
... 5 10 0 0 0 0 15 42 ...
... 100 101 102 103 104 105 106 107 ...
Exemplo
♦ Suponha que o vetor A tenha 100 posições, e que o compiladorassociou as variáveis g e h aos registradores $s1 e $s2. Temosainda que o endereço base do vetor A é dado em $s3. Qual ocódigo para
♦ Primeiro temos que pegar o operando que está na memória etransferi-lo para um registrador:
g = h + A[8] ?
lw $t0, 8($s3) # temporário t0 = A[8]add $s1, $s2, $t0 # g = h + A[8]
ProcessadorDadosEndereços
Memória
Cada posição do vetor (de inteiros) é uma palavra, e portantoocupa 4 bytes
Vetor A = [0,0,0,0,15], com 5 posições, começando no endereço dememória 408. Assim, 408 é o endereço de A[0],412 o de A[1], 416o de A[2], 420 o de A[3] e 424 o de A[4].
Vetor na memória (2)
Dados
Endereços
Endereço basede A
... 5 1 0 0 0 0 0 1 5 4 2 ... ... 400 404 408 412 416 420 424 428 ...
Exemplo♦ Suponha que o vetor A tenha 100 posições, e que o compilador
associou a variável h ao registrador $s2. Temos ainda que oendereço base do vetor A é dado em $s3. Qual o código para:
♦ A nona posição do vetor A, A[8], está no offset 8 x 4 = 32
♦ A décima-terceira posição do vetor A, A[12], está no offset 12 x4 = 48
A[12] = h +A[8] ?
lw $t0, 32($s3) # temporário t0 = A[8]add $t0, $s2, $t0 # temporário t0 = h + A[8]
lw $t0, 48($s3) # carrega A[12] em $t0!!!!
(chamada de offset) com o conteúdo do registrador base
Endereço absoluto de A[3]
♦ Para obter o endereço absoluto precisamos:
0 1 2 3 4 5 6 7 8 9 ...
Registrador baseexe. $s2
Variável i ( i = 3) ($s4)
deslocamento(offset)offset = 4*i
endereço = $s2 + 4*3
Exemplo: variável de índice
♦ Suponha que o vetor A tenha 100 posições, e que o compiladorassociou as variáveis g, h e i aos registradores $s1, $s2 e $s4.Temos ainda que o endereço base do vetor A é dado em $s3.Qual o código para:
♦ Precisamos primeiro calcular o endereço de A[i]. Antes desomar i ao endereço base de A, devemos multiplicar i por 4.Vamos fazer isto por enquanto da seguinte forma:
g = h + A[i]?
add $t1, $s4, $s4 # $t1 = 2* iadd $t1, $t1, $t1 # $t1 = 4* i
Resumo da Tradução
g = h + A[i]
add $t1, $s4, $s4 # $t1 = 2 * iadd $t1, $t1, $t1 # $t1 = 4 * iadd $t1, $t1, $s3 # $t1 = endereço de A[i]lw $t0, 0($t1) # temporário $t0 = A[i]add $s1, $s2, $t0 # g = h + A[i]
Exercício
Temos ainda que o endereço base do vetor A é dadoem $s2, e que as variáveis i e g são dadas em $s0 e$s1, respectivamente. Qual o código para
A[i+g] = g + A[i] –A[0] ?
add $t0, $t0, $s2 # $t0 = endereço de A[i + g]sw $t1, 0($t0) # A[i + g] = g + A[i] – A[0]
Utilizando os registradores
♦ Muitos programas têm mais variáveis do que o númerode registradores presente na máquina.
♦ Compilador tenta manter as variáveis mais usadas nosregistradores e coloca o resto na memória, utilizandoloads e stores para mover os dados entre a memória eos registradores:
♦ Compiladores têm que utilizar os registradores deforma eficiente.
♦ MIPS requer que todas as palavras comecem emendereços que são múltiplos de 4 bytes
♦ Chamamos isto de alinhamento: objetos têm que terendereços que sejam múltiplos de seus tamanhos.
0 1 2 3Alinhado
Não alinhado
Alinhamento de Dados na Memória
, , , p
Representando Instruções noComputador
♦ Números são armazenados no hardware na base 2, oubinária.
♦ Instruções podem ser representadas como números;na verdade, cada pedaço da instrução é um número, eo posicionamento lado a lado destes números é queformam a instrução.
♦ Existe uma convenção em MIPS para associar nomesde registradores a seus números:
$s0, $s1, …, $s7 → 16, 17, …, 23$t0, $t1, …, $t7 → 8, 9, …, 15
Representando Instruções noComputador ...
♦ Linguagem de máquina para a instrução
♦ Cada um destes segmentos é chamado de campo. O primeiro eo último campos, juntos, dizem que a instrução é uma adição. Osegundo diz qual é o primeiro registrador fonte (17 = $s1) e oterceiro o segundo registrador fonte (18 = $s2). O quarto campoé o registrador destino (8 = $t0). O quinto campo não é usadonesta instrução, e por isto tem valor zero.
0 17 18 8 0 32
add $t0, $s1,$s2
Todas as instruções em MIPS possuem 32 bits ( simplicidadefavorece regularidade”).
Formato Instrução MIPS
♦ Daremos nomes aos campos para simplificar a discussão:
♦ op: operação básica da instrução (opcode);♦ rs: primeiro registrador fonte;♦ rt: segundo registrador fonte;♦ rd: registrador destino, recebe o resultado da operação♦ shamt: quantidade de shift (veremos no capítulo 4)♦ funct: função; seleciona a variante específica da operação dada
no campo op, também chamada de código de função
op rs rt rd shamt funct
6 bits 5 bits 5 bits 5 bits 5 bits 6 bits
Formato Instrução MIPS...
♦ Um problema acontece quando uma instrução necessita decampos mais longos que os mostrados neste exemplo.
♦ Ex.: a instrução lw precisa especificar dois registradores e umaconstante. Se a constante for ser representada no campo de umdos registradores, o valor dela ficará limitado a 32 (2^5).Obviamente, este valor é pequeno demais para ser útil.
♦ Assim, temos um conflito entre o desejo de que todas asinstruções tenham o mesmo tamanho e o desejo de quetenhamos um único formato de instruções.
de dados: tipo-I ou formato-I
Formato Instrução MIPS...
♦ Formato tipo-I:
♦ O endereço de 16 bits significa que uma instrução lw podecarregar qualquer palavra dentro de uma região de ±2^15 ou32768 bytes (2^13 ou 8192 palavras) em relação ao endereçono registrador base rs.
op rs rt endereço
6 bits 5 bits 5 bits 16 bits
Formato Instrução MIPS...
♦ Ex: lw $t0, 32($s3) #temporário $t0 = A[8]
♦ Neste exemplo, rs recebe 19 ($s3), rt recebe 8 ($t0) e o campoendereço recebe o valor 32. Op neste caso é 35 (lw). Em umainstrução de load, o campo rt determina o registrador destino!!
♦ Apesar do hardware ficar mais complexo ao utilizarmosdiferentes formatos de instrução, podemos reduzir este aumentode complexidade ao mantermos certa similaridade entre osformatos (ex.: 3 primeiros campos nos formatos tipo-R e tipo-Isão os mesmos; comprimento do último campo tipo-I é igual àsoma dos 3 últimos tipo-R).
op rs rt endereço
Codificação das Instruções Vistas
Instrução Formato op rs rt rd shamt funct endereço
add R 0 reg reg reg 0 32 não
sub R 0 reg reg reg 0 34 não
lw I 35 reg reg não não não ender.
sw I 43 reg reg não não não ender.
$s0, $s1, …, $s7 → 16, 17, …, 23$t0, $t1, …, $t7 → 8, 9, …, 15
Exemplo de compilação manual
♦ Suponha que $t1 tenha o endereço base de A e que $s2corresponda a h, traduza a seguinte linha em C para código demáquina MIPS: A[300] = h + A[300];
♦ Primeiro, temos que o código em assembly correspondente é:
♦ Qual o código de máquina destas 3 instruções?
lw $t0,1200($t1) # $t0 = A[300]add $t0, $s2, $t0 # $t0 = h + A[300]sw $t0, 1200($t1) # A[300] = h + A[300]
000000 10010 01000 01000 00000 100000
101011 01001 01000 0000 0100 1011 0000
Idéia geral: conceito de programaarmazenado
♦ Computadores de hoje são construídos baseados em doisprincípios fundamentais:
• Instruções podem ser representadas como números
• Programas podem ser armazenados na memória paraserem lidos ou escritos da mesma forma que números
♦ Conceito de programa armazenado, fundamental para aComputação!!!
Instruções para tomada de decisões
♦ O que distingue um computador de uma calculadora simples éa habilidade de tomar decisões.
♦ Com base na entrada e nos resultados computados, diferentesinstruções são executadas.
♦ Em linguagens de alto nível, uma das formas de se tomardecisões é através das instruções if e goto.
♦ Em MIPS, temos duas instruções que atuam de maneira similara instruções que combinam if com goto:
• beq registr1, registr2, L1 # branch if equal• bne registr1, registr2, L1 # branch if not equal
rótulo (label)
goto L1
Instruções de decisão no MIPS ...
♦ em C, isto seria equivalente a:
♦ Estas instruções são chamadas de desvios condicionais.
bne registr1, registr2, L1
Semântica: “desvie se (valores nos registradores) não sãoiguais”
if (registr1!=registr2) goto L1
Exemplo
♦ Se as variáveis f, g, h, i, j correspondem aos registradores $s0a $s4, qual é o código compilado para o seguinte trecho em C?
Como instruções são armazenadas na memória, elas têm endereçostambém!!
i f (i == j) gotoL1; f = g + h;L1: f = f – i;
beq $s3, $s4, L1 # vá para L1 se $s3 == $s4 add $s0, $s1, $s2 # f = g + h (se i != j)
L1: sub $s0, $s0, $s3 # f = f – i (se i == j)
Desvio incondicional em MIPS
♦ MIPS tem um desvio incondicional:
♦ Chamada de instrução de salto (jump): salte para o rótuloespecificado, incondicionalmente
♦ Em C, isto seria equivalente a: goto label
♦ Podemos pensar que isto é equivalente a:
• Uma vez que a condição sempre é satisfeita
♦ Existe um formato de instrução para desvio (tipo-J ou formato-J),como veremos mais à frente.
j rotulo
beq $0,$0,rotulo
Exemplo: código para if
♦ Se as variáveis f, g, h, i, j correspondem aos registradores $s0 a$s4, qual é o código compilado para o seguinte trecho em C?
♦ Queremos implementar o seguinte fluxo:
Fim
i == j?
f=g+h f=g-h
(falso) i != j
(verdadeiro) i == j
if (i == j) f = g + h; else f = g – h;
$ , $ , $ g ( j)Fim:
Loops
♦ Decisões são importantes para escolher entre duasalternativas, e para iterar uma computação (loop). Usamos asmesmas instruções assembly para as duas situações.
♦ Tudo depende de onde colocamos o rótulo para o qualsaltaremos.
Exemplo de loop♦ Se as variáveis g, h, i, j correspondem aos registradores $s1 a $s4, e o
endereço base do vetor A (de 100 elementos) está em $s5, compile oseguinte trecho em C.
Loop: g = g + A[i];if ( (i = i + j) != h ) goto Loop;
Loop: add $t1, $s3, $s3 # $t1 = 2 * iadd $t1, $t1, $t1 # $t1 = 4 * i
add $t1, $t1, $s5 # $t1 = ender. de A[i]lw $t0, 0($t1) # $t0 = A[i]add $s1, $s1, $t0 # g = g + A[i]
add $s3, $s3, $s4 # i = i + jbne $s3, $s2, Loop # Loop se (i != h)
♦ Temos inicialmente que carregar save[i] para um registradortemporário:
♦ Agora fazemos o teste do loop, saindo se save[i] != k
♦ Devemos agora voltar para o while no inicio do loop
Loop: add $t1, $s3, $s3 # $t1 = 2 * iadd $t1, $t1, $t1 # $t1 = 4 * iadd $t1, $t1, $s6 # $t1 = endereço de save[i]
lw $t0, 0($t1) # $t0 = save[i]
bne $t0, $s5, Fim # vá para Fim se save[i] != kadd $s3, $s3, $s4 # i = i + j
j Loop # vá para LoopFim:
Compilando um laço do tipo while
Comparando dois registradores
♦ Os testes de igualdade ou desigualdade são provavelmente osmais populares, mas às vezes queremos testar se uma variávelé menor do que outra
♦ Por exemplo, um for pode querer testar se um índice é menordo que zero.
♦ Em MIPS, temos uma instrução que compara os valores dedois registradores, e atribui 1 a um terceiro registrador se oprimeiro registrador é menor que o segundo, e 0 casocontrário:
♦ → Se $s3 < $s4, $t0 recebe 1, caso contrário, recebe 0
slt (set on less than) slt $t0, $s3, $s4
Exemplo: desvio se menor que
♦ Qual o código para testar se a variável a, mapeada no registrador$s0, é menor que a variável b (registrador $s1), e desviar para orótulo Menor se a condição for satisfeita?
♦ Primeiro usamos a instrução slt e um registrador temporário:
♦ Registrador $t0 é 1 se a < b. Portanto, testamos se $t0 não é 0:
slt $t0, $s0, $s1 # $t0 = (a < b)?
bne $t0, zero, Menor # vá para Menor se $t0!=0# ou seja, se (a < b)
Tradução de if (a < b) then... else
if (i < j) f = g + h;
else f = g – h;
slt $t0, $s0, $s1 # $t0 = (a < b)?
beq $t0, zero, Else # vá para else se a >= badd $s0, $s1, $s2 # f = g + h (se i == j)
j Fim # vá para FimElse: sub $s0, $s1, $s2 # f = g – h (se i != j)Fim:
Um outro tipo de desvioincondicional
♦ Até agora vimos uma instrução de desvio incondicional, atravésda instrução
♦ Nesta instrução, temos que especificar um rótulo, ou seja umendereço fixo, para o qual o Program Counter será desviado.
♦ Em diversas situações, pode ser interessante que desviemospara um endereço variável, armazenado em um registrador.Para tanto, existe a instrução jr:
j Rotulo # desvio pararótulo
jr registrador #desvio paraendereço
#contido noregistrador
Comando switch
♦ A linguagem C define o comando switch, que permite que oprogramador selecione uma alternativa dentre várias,dependendo de um único valor.
♦ Como compilar o seguinte trecho de código?
switch (k) { case 0: f = i + j; break; case 1: f = g + h; break; case 2: f = g – h; break; case 3: f = i – j; break;
}
Comando switch♦ Desta forma, se temos n casos possíveis, teremos, em média,
que testar n/2 casos contra k para encontrar o caso desejado.
♦ Como podemos implementar o comando switch de maneiramais eficiente?
♦ Em alguns casos, podemos utilizar uma tabela de endereços, detal forma que ao acessar a tabela na posição correspondente ak, TabEnd[k], obtenhamos o endereço do rótulo desejado.
♦ Desta maneira, podemos tomar a decisão em tempo constante.
Comando switch
♦ Melhorando o comando switch:
♦
♦ Vamos supor que as variáveis f, g, h, i, j, k estão nosregistradores $s0 a $s5, e que $t2 contenha o valor 4.
switch (k) {case 0: f = i + j; break;case 1: f = g + h; break;case 2: f = g – h; break;case 3: f = i – j; break;
}
♦ Vamos utilizar k para indexação; por isto temos que multiplicark por 4.
Comando switch
♦ Suponha que o vetor de endereços TabEnd, cujo endereçoestá em $t4, possui quatro posições, com os endereçoscorrespondentes aos rótulos L0, L1, L2 e L3:
♦ Agora saltamos para o endereço presente em $t0:
add $t1, $s5, $s5 # t1 = 2 * kadd $t1, $t1, $t1 # t1 = 4 * k
add $t1, $t1, $t4 # t1 = endereço de TabEnd[k]lw $t0, 0($t1) # t0 = TabEnd[k]
jr $t0
Comando switch
♦ Por fim tratamos os casos do switch:
L0: add $s0, $s3, $s4 # f = i+jj Fim
L1: add $s0, $s1, $s2 # f = g + hj Fim
L2: sub $s0, $s1, $s2 # f = g – hj Fim
L3: sub $s0, $s3, $s4 # f = i – j (não precisamos saltar# para o Fim, já que a próxima# instrução tem o rótulo Fim)
Fim:
Instruções de suporte a procedimentos
♦ Procedimentos ou subrotinas são utilizadas pelosprogramadores para:• Facilitar a compreensão e manutenção de código;• Possibilitar o reaproveitamento de código.
♦ O código de um procedimento fica “isolado”, sendo a interfacecom o restante do código dada pelos argumentos de entrada epelos resultados de saída.
Instruções de suporte a procedimentos
♦ Na execução de um procedimento, um programa deve seguiros seguintes passos:• Colocar os argumentos (parâmetros) em um lugar em que o
procedimento possa acessá-los;• Transferir o controle para o procedimento;• Executar a tarefa desejada;• Colocar o resultado da execução em um lugar em que o
código que chamou o procedimento possa acessar;• Retornar o controle para o ponto de origem.
♦ $ra: registrador utilizado para retornar para o ponto de origem(ra = return address).
Valores de retorno do procedimento
Desvio para procedimento
Instruções de suporte a procedimentos
Execução do procedimento
Preparo argumentos para o procedimento $a0-$a3
$ra;desvio
$v0-$v1
Continuação do programa
Retorno para a continuação do programa jr $ra
C
MIPS
Exemplo de procedimento
... soma(a,b);... /* a:$s0; b:$s1 */}
int soma(int x, int y) { /* x:$a0; y:$a1 */return x+y;
}
endereço1000 add $a0,$s0,$zero # x = a1004 add $a1,$s1,$zero # y = b1008 addi $ra,$zero,1016 # $ra = 10161012 j soma # desvio para soma1016 ...2000 soma: add $v0,$a0,$a12004 jr $ra # volte p/ origem,
# no endereço 1016
jal (jump and link) ...
♦ Link, neste caso, quer dizer que é formada, no registrador $ra,uma referência para a instrução que vem logo após a instruçãojal, ou seja, a instrução jal é equivalente ao seguinte código:
♦ Por que existe a instrução jal??
Procedimentos são muito comuns: “faça o caso comum ser rápido”
$ra = PC + 4j Rótulo
C
MIPS
Exemplo de procedimento (revisado)
... soma(a,b);... /* a:$s0; b:$s1 */}
int sum(int x, int y) { /* x:$a0; y:$a1 */return x+y;
}
end1000 add $a0,$s0,$zero # x = a1004 add $a1,$s1,$zero # y = b1008 jal soma # prepara $ra e
# jump p/ proc soma1012 ...2000 soma: add $v0,$a0,$a12004 jr $ra # volte p/ origem,
# no endereço 1012
$ , $ , $ $jr $ra # retorne para origem
Usando mais registradores
♦ Suponha que um procedimento necessite de maisregistradores do que os 4 registradores de argumentos e os 2de retorno.
♦ O código que vai chamar este procedimento pode estarutilizando diversos registradores, de tal forma que oprocedimento não pode utilizar os registradores de qualquerforma, uma vez que valores importantes poderiam serperdidos.
♦ Assim, qualquer registrador que o procedimento utilize e quepossa ser do interesse do código “chamador” deve ter seuvalor restaurado para o valor anterior à execução doprocedimento.
Usando mais registradores
♦ Como fazer isto?
♦ Processo conhecido por register spilling:• Uso de uma pilha, estrutura de dados do tipo LIFO (last-in
first-out);• Temos um apontador para o topo da pilha;• Este apontador é ajustado em uma palavra para cada
registrador que é colocado na pilha (operação conhecidapor push), ou retirado da pilha (operação conhecida porpop).
• Em MIPS, um registrador é utilizado somente para indicar otopo da pilha: sp (stack pointer)
$ p p
0
Endereço
Código Programa
Estático Variáveis declaradas umavez para todo programa
HeapEspaço explicitamente criadomalloc: apontadores em C
PilhaEspaço para procedimentosarmazenarem informações$sp
stackpointer
Alocação de memória em C
Exemplo: exemplo_proc
♦ Suponha que tenhamos o seguinte código:
Vamos gerar o código correspondente em assembly MIPS.
int exemplo_proc (int g, int j, int i, int h){
int f;f = (g+h) – (i+j);return f;
}
sw $s0, 0(sp) # empilha $s0
Exemplo : exemplo_proc
Como ficou a pilha?
$sp
Valoresempilhados
antes dafunção
Pilha antes dafunção
$t1
$t0
$s0$sp
Valoresempilhados
antes dafunção
Pilha durante execuçãoda função
Exemplo : exemplo_proc
♦ As próximas instruções correspondem ao corpo doprocedimento:
♦ O resultado deve ser armazenado no registrador $v0:
add $v0, $s0, $zero # retorna f em $v0
add $t0, $a0, $a1 # $t0 = g + hadd $t1, $a2, $a3 # $t1 = i + jsub $s0, $t0, $t1 # f = $t0 = (g+h) – (i+j)
# este procedimento
Instruções de suporte a procedimentos
♦ No exemplo anterior, nós utilizamos registradores temporários eassumimos que os valores deles deveriam ser guardados erestaurados.
♦ Para evitar que registradores que não são utilizados sejamempilhados e desempilhados, MIPS oferece duas classes deregistradores:• $t0-$t9: 10 registradores temporários que não são
preservados pela função que é chamada.• $s0-$s7: 8 registradores que têm seus valores preservados
no processo de chamada de procedimento. Desta forma, seestes registradores forem utilizados pelo procedimento, elesdevem ter seus valores empilhados no início doprocedimento e desempilhados no final.
Instruções de suporte a procedimentos
♦ Esta simples convenção faz com que percamos menos tempoempilhando e desempilhando registradores
♦ No exemplo, teríamos que preservar somente o valor de $s0.
♦ O que fazer se temos um código que utiliza registradorestemporários e vai chamar uma função??
♦ Podem aparecer problemas quando fazemos funções quechamam outras funções (por exemplo, funções recursivas)??
♦ Como resolver?
Procedimentos aninhados:convenção sobre registradores
♦ Uma solução é empilhar todos os registradores que precisamser preservados.
♦ Para isto, temos que estabelecer uma convenção entre asubrotina que chama a função e a subrotina chamada, paraestabelecer quais registradores serão preservados, e por quem.
♦ Definições• Chamadora: função que faz a chamada, utilizando jal;• Chamada: função sendo chamada.
♦ Podemos pensar nestas convenções como sendo um contratoentre a Chamadora e a Chamada;
Por que utilizar convenções parachamadas de procedimentos?
♦ Se tanto a sub-rotina Chamadora quanto a Chamadaobedecerem a convenção, temos os seguintes benefícios:
♦ programadores podem escrever funções quefuncionam juntas;
♦ Funções que chamam outras funções – como asrecursivas – funcionam corretamente.
Atenção!! Chamadora ou chamada não representa uma propriedadeda função, mas sim o papel que a função exerce em uma chamadade procedimento específica. Assim, uma função pode exercer opapel de chamadora e de chamada, só que em diferentes chamadasde procedimento.
• Registradores temporários $t0 - $t9
♦ Direitos da Chamadora• Utilizar os registradores s, sem que eles sejam
alterados pela Chamada• Assumir que os valores de retorno e a pilha estão
corretos
♦ Registradores que devem ser preservados pelaChamada:• Registradores $s $s0 - $s7
Direitos da Chamadora e da Chamada
Exemplo: soma_recursiva
♦ Suponha que tenhamos o seguinte código, que calcula a soman + (n-1) + … + 2 + 1 de forma recursiva:
♦ Vamos gerar o código correspondente em assembly MIPS.
int soma_recursiva (int n){
if (n < 1)return 0;
elsereturn n + soma_recursiva(n-1)
}
que é armazenado corresponde a um endereço que está nasub-rotina que chama esta função
Exemplo: soma_recursiva
♦ Vamos agora compilar o corpo da função. Inicialmente,testamos se n < 1:
♦ Se n >=1, a função deve retornar o valor 0. Não podemos nosesquecer de restaurar a pilha.
♦ Por que não carregamos os valores de $a0 e $ra antes deajustar $sp??
slti $t0, $a0, 1 # testa se n < 1beq $t0, $zero, L1 # se n>=1, vá para L1
add $v0, $zero, $zero # valor de retorno é 0add $sp, $sp, 8 # remove 2 itens da pilhajr $ra # retorne para depois de jal
Exemplo: soma_recursiva
♦ Se n >=1, decrementamos n e chamamos novamente a funçãosoma_recursiva com o novo valor de n.
♦ Quando a soma para (n-1) é calculada, o programa volta aexecutar na próxima instrução. Restauramos o endereço deretorno e o argumento anteriores, e incrementamos oapontador de topo de pilha:
L1:
subi $a0, $a0, 1 # argumento passa a ser (n-1) jal soma_recursiva # calcula a soma para (n-1)
lw $a0, 0($sp) # restaura o valor de nlw $ra, 4($sp) # restaura o endereço de retornoaddi $sp, $sp, 8 # retira 2 itens da pilha.
Variáveis automáticas e estáticas
♦ Variáveis automáticas são aquelas que são locais a umprocedimento, e que portanto só são acessíveis enquanto oprocedimento está ativado.
♦ Quando uma função contém dados que são grandes demaispara serem colocados em registradores, eles são colocados napilha. Exemplos são estruturas de dados como registros(structs) ou vetores estáticos (que não usam malloc paraalocação).
♦ Já as variáveis estáticas são aquelas que estão ativas durantetoda a execução do programa. Em C, elas são as variáveisglobais e as variáveis marcadas como static.
Variáveis automáticas e estáticas
♦ A região da pilha onde são armazenados os registradoressalvos e as variáveis locais a um procedimento é chamada deregistro de ativação.
♦ Para facilitar o acesso a estas variáveis, o registrador $fp (framepointer) é utilizado. Ele marca o início do registro de ativação, enão é atualizado de forma automática, só sendo utilizado sehouver variáveis do procedimento na pilha. A vantagem de seusar $fp é que $sp pode ter o valor alterado durante a execuçãoda função.
♦ Para facilitar o acesso às variáveis estáticas, o registrador $gp(global pointer) é utilizado. Estas variáveis são alocadas naregião de memória “dados estáticos”, ver figura 3.22 do livro(seção 3.9)
Pilha antes dafunção
Pilha durante execuçãoda função
0 zero constante 0
1 at reservado para o montador
2 v0 resultados de funções
• v1
4 a0 argumentos
5 a1
6 a2
7 a3
8 t0 temporários: Chamadora
. . . é que deve salvar
15 t7
Registradores MIPS: resumo daconvenção de software
16 s0 Chamada é que deve
. . . salvar
23 s7
24 t8 temporários (cont.)
25 t9
26 k0 reservados para o kernel
27 k1 do sistema operacional
28 gp global pointer
29 sp stack pointer
30 fp frame pointer
31 ra endereço de retorno
Fig. A.1 0
Categoria Instru ção Exemplo SemânticaAdição add $s1, $s2, $s3 $s1 = $s2 + $s3AritméticaSubtração sub $s1, $s2, $s3 $s1 = $s2 - $s3Load word lw $s1, 100($s2) $s1 = Mem[$s2 + 100]Transferência
de dados Store word sw $s1, 100($s2) Mem[$s2 + 100] = $s1Branch onequal
beq $s1, $s2, L If ($s1 == $s2) goto L
Branch on notequal
bne $s1, $s2, L If ($s1 != $s2) goto L
DesvioCondicional
Set on lessthan
slt $s1, $s2, $s3 if ($s2 < $s3) $s1 = 1; else $s1 = 0;
Jump j 2500 goto 10000Jump register jr $t1 goto $t1
DesvioIncondicional
Jump & link jal 2500 $ra = PC + 4; goto 10000
Resumo: instruções vistas até agora
ç g ( p )
� No entanto, como grande parte dosprogramas utiliza texto, MIPS forneceinstruções específicas para mover bytes.
� Leitura de bytes:
� load byte (lb): lê um byte da memória,colocando-o nos 8 bits mais à direita d eum registrador
� Ex: lb $t0, 0($sp) # lê byte que está n otopo da pilh a
Trabalhando com caracteres e strings
♦ Escrita de bytes:
♦ store byte (sb): escreve na memória o byte que está nos 8bits mais à direita de um registrador
♦ Ex: sb $t0, 0($sp) # escreve byte no topo da pilha
Trabalhando com caracteres e strings
ocupa um byte?
♦ A string é armazenada em uma estrutura, em que umavariável diz o comprimento da cadeia e outra traz oscaracteres que compõe a cadeia;
Ex: “casa” = {4, _c_ _a_ _s_ _a_} = {4, 99 97 115 97}
♦ A última posição de uma cadeia é indicada por um caractereespecial.
Ex: “casa” = _c_ _a_ _s_ _a_ 0 = 99 97 115 97 0
♦ Esta é a representação utilizada pela linguagem C, sendo omarcador de final de string o valor 0.
Trabalhando com caracteres e strings
Exemplo: string_copy
♦ Suponha que tenhamos o seguinte código:
void strcpy(char x[], char y[]){
int i;i = 0;while ((x[i] = y[i]) != 0)
i = i + 1;}
Vamos gerar o código correspondente em assembly MIPS.
♦ Podemos fazer o laço então; o endereço de y[i] é formadoadicionando i com o endereço base de y:
L1:add $t1, $a1, $s0 # $t1 = endereço de y[i]
♦ Por que não multiplicamos i por 4??♦ y é um vetor de bytes, e não de palavras!!!
♦ Agora carregamos o caractere y[i]:
lb $t2, 0($t1) # $t2 = y[i]
Exemplo: string_copy
♦ Preparamos agora o endereço de x[i] em $t3, e armazenamosy[i]:
add $t3, $a0, $s0 # $t3 = endereço de x[i]sb $t2, 0($t3)# x[i] = y[i]
♦ Se o caractere y[i] for 0, saimos do loop:
beq $t2, $zero, L2 # se y[i] == 0, desvie para L2
♦ Senão, incremente i e itere novamante:
addi $s0, $s0, 1 # $s0 = $s0 + 1j L1 # desvie para L1
Exemplo: string_copy
que $s em funções que não chamam outra função.
Padrão Unicode♦ Está se tornando cada vez mais comum um outro tipo de
codificação para caracteres, o padrão Unicode. Java utilizaeste padrão.
♦ Este padrão, além de representar todos os caracteres latinos,pode representar símbolos de letras orientais, dentre outros.
♦ Um caractere passa a ocupar 16 bits. Quantos símbolos podemser representados?
♦ MIPS inclui instruções para trabalhar com 16 bits, mas nãoveremos elas neste curso. Quem estiver curioso, consulte oapêndice A do livro.