Anotações da 2a Edição OBS: Essas anotações são adaptações do material suplementar (apresentações PPT) ao Livro do Hennessy e Patterson. Supõe-se que os estudantes tenham noções de lógica digital e linguagem assembly para o entendimento das aulas. 1 Compilando códigos para MIPS 2 Código C → Código MIPS • • • Compilador faz a conversão: C code: A = B + C; E = F - A; MIPS code: add $s0, $s1, $s2 sub $s4, $s5, $s0 Operandos só em registradores: load/store para trabalhar com variáveis do programa. Instruções R, I, J (aulas anteriores...) 3 Compilando indexação de vetores • Seja A um vetor de inteiros (4 bytes) e que o compilador tenha associado as variáveis g, h e i com os registradores $s1, $s2 e $s4. Considere que o endereço inicial (ou de base) do vetor está em $s3. • O código a seguir é uma possível compilação do trecho de código em C para instruções assembly MIPS: g = h + A[i]; 1) Converter indexação de word para bytes: add $t1,$s4,$s4 # Temp reg $t1 = 2 * i add $t1,$t1,$t1 # Temp reg $t1 = 4 * i 2) Para pegar o endereço de A[i], deve-se adicionar $t1 à base de A em $s3: add $t1,$t1,$s3 # $t1 = endereço de A[i] (4 * i + $s3) 3) Usar o endereço calculado para carregar A[i] num reg temporário: lw $t0,0($t1) # Temp reg $t0 recebe A[i] 4) Finalmente, adicionar A[i] a h e colocar a soma em g: add $s1,$s2,$t0 # g = h + A[i] 4 Compilando if-then-else • Assumindo que as 5 variáveis f, g, h, i e j correspondem aos 5 registradores de $s0 a $s4, o código compilado MIPS será o mostrado abaixo para a construção if em C: if (i==j) f = g + h; else f = g - h; bne $s3,$s4,Else # go to Else if i != j add $s0,$s1,$s2 # f = g + h (desvia se i != j) j Exit Else: sub $s0,$s1,$s2 # f = g - h (desvia de i == j) Exit: 5 Compilando if-then-else (Versão 2) • Assumindo que as 5 variáveis f, g, h, i e j correspondem aos 5 registradores de $s0 a $s4, o código compilado MIPS será o mostrado abaixo para a construção if em C: if (i==j) f = g + h; else f = g - h; beq $s3,$s4,Else # go to Else if i ! j sub $s0,$s1,$s2 # f = g - h (desvia de i == j) j Exit Else: add $s0,$s1,$s2 # f = g + h (desvia se i != j) Exit: 6 Compilando um loop while • Assumindo que as 3 variáveis i, j, k correspondem aos 3 registradores de $s3 a $s5, e que a base do vetor V está em $s6. O código compilado MIPS para a construção em C será: while (V[i] == k) i = i + j; 1) Carregar V[i] num registrador temporário: Loop: add $t1,$s3,$s3 add $t1,$t1,$t1 add $t1,$t1,$s6 lw $t0,0($t1) # reg temporário $t1 = 2 * i # reg temporário $t1 = 4 * i # $t1 = endereço de V[i] # reg temporário $t0 = V[i] 2) A próxima instrução realiza o teste do loop, saindo se V[i] != k : bne $t0,$s5,Exit # go to Exit se V[i] != k 3) A próxima instrução é somar j e i: add $s3,$s3,$s4 4) Finalmente, chega-se ao fim do loop: j Loop Exit: #i=i+j # go to Loop no início do código 7 Compilando um switch a partir de uma Tabela de Endereços de Desvio • O trecho em C seleciona 1 entre 4 alternativas dependendo do valor assumido pela variável k, cujo domínio é 0, 1, 2 e 3. 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; } • Suponha que as variáveis de f a k correspondem as 6 variáveis de $s0 a $s5, e que o registrador $t2 contenha o valor inteiro 4 e o registrador $t4 o valor inicial da sequência de labels L0, L1, L2 e L3 armazenados na memória. Qual o código correspondente em assembly MIPS? • 8 Código do switch em MIPS slt $t3, $s5, $zero bne $t3, $zero, Exit slt $t3, $s5, $t2 beq $t3, $zero, Exit add $t1, $s5, $s5 add $t1, $t1, $t1 add $t1, $t1, $t4 lw $t0, 0 ($t1) jr $t0 L0: add $s0, $s3, j Exit L1: add $s0, $s1, j Exit L2: sub $s0, $s1, j Exit L3: sub $s0, $s3, Exit: Testa se 0 <= k < 4 $s5 armazena k Salva em $t0 o endereço de Li Li depende de $s5 $s4 $s2 $s2 $s4 9 Código MIPS compilado O que tem aqui dentro? 10 Código compilado MIPS • O que faz o código abaixo? .text .globl main main: li $t0,4 li $t1,6 beq $t0,$t1,sai subu $t1,$t1,1 j fim sai: addu $t0,$t0,2 fim: j $ra # # # # # # # Inicia uma área de código Label como visibilidade global Declaração do label main i=4; j=6; if(i==j) j=j-1; Subtrai sem considerar overflow # i=i+2; (Soma sem considerar overflow) # Retorna para o programa que chamou 11 Exemplo 1 .text .globl main main: li $t0,4 li $t1,6 beq $t0,$t1,salto subu $t1,$t1,1 j fim salto: addu $t0,$t0,2 fim: j $ra # # # # # # # Inicia uma área de código Label como visibilidade global Declaração do label main i=4; j=6; if(i==j) j=j-1; (Subtrai sem considerar overflow) # i=i+2; (Soma sem considerar overflow) # Retorna para o programa que chamou 12 Exemplo 2 .text .globl main main: move $t0, $zero # i=0; move $t1, $zero # int sum = 0; loop: mul $t2, $t0, $t0 # i * i addu $t1, $t1, $t2 # sum = sum + i * i; addu $t0, $t0, 1 # i=i+1 ble $t0, 100, loop # desvia para loop se i<=100 ################ printf("\nThe sum from 0 .. 100 is %d", sum); ############### la $a0, str # Atribui o endereço de str para o registrador $a0 li $v0, 4 # $v0=4 imprime a string endereçada por $a0 no syscall syscall # Chamada ao SO move $a0, $t1 # Atribui o valor de $t1 (inteiro) para o registrador $a0 li $v0, 1 # $v0=1 imprime o valor armazenado em $a0 no syscall syscall # Chamada ao SO j $ra .rdata # Inicia uma área de dados str: .asciiz "\nThe sum from 0 .. 100 is " # Declaração de caracteres ASCII (string) 13 Chamadas de SO - syscall • • • Alguns serviços do sistema, principalmente para entrada e saída, podem ser utilizados em programas em assembly MIPS. Os conteúdos dos registradores MIPS não são afetados pela chamada de sistema (system call), exceto para registradores de resultados. Como usar serviços do sistema com SYSCALL? 1. Carregar o número do serviço no registrador $v0. 2. Carregar os valores dos argumentos, se houver, em $a0, $a1, $a2, ou $f12 especificados. 3. Lançar a instrução SYSCALL. 4. Recuperar os valores de retorno, se houver, a partir dos registradores de resultado especificados. • Ex: Mostrar o valor armazenado em $t0 no console (saída padrão) li $v0, 1 # serviço add $a0, $t0, $zero # carrega argumento syscall # Chamada 1: print um integer o valor desejado no registrador de argumento $a0, using pseudo-op de sistema Ver: http://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html 14 Exemplo de I/O em arquivo # Sample MIPS program that writes to a new file. # by Kenneth Vollmar and Pete Sanderson .data fout: .asciiz "testout.txt" # filename for output buffer: .asciiz "The quick brown fox jumps over the lazy dog." .text ############################################################### # Open (for writing) a file that does not exist li $v0, 13 # system call for open file la $a0, fout # output file name li $a1, 1 # Open for writing (flags are 0: read, 1: write) li $a2, 0 # mode is ignored syscall # open a file (file descriptor returned in $v0) move $s6, $v0 # save the file descriptor ############################################################### # Write to file just opened li $v0, 15 # system call for write to file move $a0, $s6 # file descriptor la $a1, buffer # address of buffer from which to write li $a2, 44 # hardcoded buffer length syscall # write to file ############################################################### # Close the file li $v0, 16 # system call for close file move $a0, $s6 # file descriptor to close syscall # close file ############################################################### Fonte: http://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html 15