Faculdade de Computação Arquitetura e Organização de Computadores 2 1 Laboratório de Programação MIPS – entrega 18/04/2016 Prof. Cláudio C. Rodrigues a Problemas: P1) Considere que você é um projetista da ARM e deve projetar um novo conjunto de instruções com apenas 16 registradores de 32 bits. Isto significa que precisamos apenas de campos de 4 bits para identificar operandos registradores em nossas instruções. a) Quantos bits extras obteremos para serem utilizados em outros campos nos seguintes formatos: R, J e I? b) Para instruções R-formato, você atribuiria os bits extras para opcode, shamt ou funct? Explique sua escolha em uma ou duas frases. c) Para instruções do formato-I, você, naturalmente, atribuiria os bits extras para o campo imediato, resultando no seguinte formato: [ opcode (6) | rs (4) | rt (4) | immediate (18) ] Qual a fração do espaço de endereçamento de memória, podemos alcançar com uma instrução de desvio (branch)? d) Assuma que o Program Counter (PC) contém atualmente o endereço 0x08000000. Qual é o menor endereço (em hexadecimal), podemos alcançar com uma instrução de desvio? P2) Considere as declarações de uma variável do string (str) realizadas conforme as sentenças abaixo. Explique de forma objetiva como o espaço de endereçamento de memória será configurado, para cada uma das declarações. a) static char str[] = "thing"; b) char str[] = "thing"; c) char *str = malloc(6); strcpy(str, "thing"); P3) Modos de Endereçamento do MIPS: Temos vários modos de endereçamento para o acesso à memória (imediato não listados): endereçamento base deslocamento. endereçamento relativo ao PC. endereçamento pseudo-direto. endereçamento por registrador. a) Uma determinada solução de programação em MIPS assembly necessita de uma instrução para executar um salto para um endereço 2^28 + 4 bytes distante da atual posição do PC. Como você faria para resolver? Considere que o endereço de destino será conhecido em tempo de compilação. b) Uma determinada solução de programação em MIPS assembly necessita de uma instrução para executar um desvio para um endereço 2^17 + 4 bytes distante da atual posição do PC, quando $t0 é igual a 0. Considere que não saltaremos para um endereço superior a 2^28 bytes. Como você faria para resolver? P4) Convenções a) Como deve o registrador $sp ser utilizado? Quando é que devemos adicionar ou subtrair $sp? b) Quais registradores necessitams ser salvos ou restaurados antes de executarmos a instrução jr para retornar de uma função? c) Quais registradores necessitam ser salvos antes de executar a instrução JAL? d) Como podemos passar parâmetros para funções? e) O que devemos fazer se houvera necessidade de passar mais do que quatro parâmetros para uma função? f) Como são retornados valores pelas funções? Arquitetura e Organização de Computadores 2 1 P5) Comente o código MIPS a seguir e descreva em uma sentença que ele computa. Assuma que $a0 é utilizado para a entrada e inicialmente contém n, um inteiro positivo. Assuma que $v0 é utilizado para a saída. begin: addi $t0, $zero, 0 addi $t1, $zero, 1 loop: slt $t2, $a0, $t1 bne $t2, $zero, finish add $t0, $t0, $t1 addi $t1, $t1, 2 j loop finish: add $v0, $t0, $zero P6) Considere a função mistério escrita em MIPS assembly: 1 misterio: 2 beq $a1, $0, L3 3 sll $a1, $a1, 2 4 addu $a1, $a0, $a1 5 move $t8, $a0 6 L1: 7 addiu $t8, $t8, 4 8 beq $t8, $a1, L3 9 move $t9, $t8 10 L2: 11 beq $t9, $a0, L1 12 lw $t0, -4($t9) 13 lw $t1, 0($t9) 14 slt $t2, $t1, $t0 15 beq $t2, $0, L1 16 sw $t1, -4($t9) 17 sw $t0, 0($t9) 18 addiu $t9, $t9, -4 19 # PRINTF AQUI 20 j L2 21 L3: 22 jr $ra a) Qual seria a assinatura da função mistério em linguagem C? b) Explique de forma objetiva o que a função mistério faz? c) Considere uma modificação no código acima para incluir a invocação da função de biblioteca PRINTF na linha marcada #PRINTF AQUI, mas não modifique qualquer outra linha da função. Liste os registradores que precisam ser salvos na pilha antes da chamada da PRINTF e restaurados na sequência. P7) O padrão IEEE 754 define a representação binária para valores em ponto flutuante (floating point values) usando três campos: - O sign determina o sinal do número (0 para positivo, 1 para negativo) - O exponent é uma representação de excesso (bias) de 127 - O significand aramazena a parte fracionária. Abaixo temos o formato da representação de ponto flutuante de precisão simples (32-bit): sign 1 exponent 8 significand 23 FP normalizados: Valor = (-1)Sign x 2(Exponent – Bias) x 1.significand2 FP denormalizados: Valor = (-1)Sign x 2(Exponent – Bias + 1) x 0.significand2 Arquitetura e Organização de Computadores 2 2 Converta os seguintes valores de binário para decimal ou decimal para binário: 0x00000000 34.65 0x80000F00 99.7825 0xFF94BEEF -∞ a) P8) O seguinte fragmento de código processa um array e produz dois importantes valores nos registradores $v0 e $v1. Assuma que o array consiste de 5000 palavras indexadas de 0 a 4999, e seu endereço base está armazenado em $a0 e seu tamanho (5000) em $a1. Descreva em uma sentença o que este código faz. Especificamente, o que será retornado em $v0 e $v1? outer: inner: skip: next: P9) add $a1, $a1, $a1 add $a1, $a1, $a1 add $v0, $zero, $zero add $t0, $zero, $zero add $t4, $a0, $t0 lw $t4, 0($t4) add $t5, $zero, $zero add $t1, $zero, $zero add $t3, $a0, $t1 lw $t3, 0($t3) bne $t3, $t4, skip addi $t5, $t5, 1 addi $t1, $t1, 4 bne $t1, $a1, inner slt $t2, $t5, $v0 bne $t2, $zero, next add $v0, $t5, $zero add $v1, $t4, $zero addi $t0, $t0, 4 bne $t0, $a1, outer O programa a seguir tenta copiar palavras de um endereço no registrador $a1, contando o número de palavras copiadas no registrador $v0. O programa para de copiar quando encontra uma palavra igual a 0. Você não tem que preservar o conteúdo dos registradores $v1, $a0 e $a1. Esta palavra de terminação deve ser copiada, mas não contada. loop: lw $v1, 0($a0) addi $v0, $v0, 1 sw $v1, 0($a1) addi $a0, $a0, 1 addi $a1, $a1, 1 bne $v1, $zero, loop # # # # # # read next word from source increment count words copied write to destination advance pointer to next source advance pointer to next dest loop if word copied != zero Existem múltiplos erros neste programa MIPS; conserte-os e torne este programa bug-free. O modo mais fácil de escrever programas MIPS é utilizar o simulador MARS disponível no sítio da disciplina. Você pode efetuar o download do simulador através dos links na página do curso. P10) Considere o seguinte fragmento de código C: for (i=0;i<=100;i=i+1) { a[i] = b[i] + c; } Assuma que a e b são arrays de inteiros (.word) e que o endereço base de a está em $a0 e que o endereço base de b está em $a1. O registrador $t0 está associado a variável i e o registrador $s0 a variável c. Escreva o código utilizando o conjunto de instruções MIPS. Quantas instruções são executadas durante a execução deste código? Quantas referências de dados na memória serão feitas durante a execução? Arquitetura e Organização de Computadores 2 3 P11) Converta a função abaixo, escrita em linguagem C, para a linguagem do MIPS assembly. Considere que $a0 e $a1 guardam os ponteiros para os inteiros, troque os valores para os quais eles apontam usando a pilha. void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } P12) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. O fragmento calcula a soma de números de 0 a N. Considere que $s0 mantem N (N>=0), $s1 mantem a soma. Transforme a solução em estrutura de função. int soma= 0 if (N == 0) return 0; while (N != 0) { suma += N N--; } return soma; P13) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. // Strcpy: // $s1 -> char s1[] = “Hello!”; // $s2 -> char *s2 = // malloc(sizeof(char)*7); int i=0; do { s2[i] = s1[i]; i++; } while(s1[i] != '\0'); s2[i] = '\0'; P14) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. /** Converts the string S to lowercase */ void string_to_lowercase(char *s) { for(char c = *s; (c=*s) != '\0'; s++) { if(c >= 'A' && c <= 'Z') { *s += 'a' - 'A'; } } } P15) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. /** Returns the number of bytes in S before, but not counting, the null terminator. */ size_t string_length(char *s) { char *s2 = s; while(*s2++); return s2 - s - 1; } Arquitetura e Organização de Computadores 2 4 P16) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. /** Return the number of odd numbers in a number array */ uint32_t number_odds(uint32_t *numbers, uint32_t size) { uint32_t odds = 0; for (uint32_t i = 0; i < size; i++) odds += *(numbers+i) & 1; // odds += numbers[i] & 1; return odds; } P17) Converta o fragmento de código abaixo, escrito em linguagem C, para a linguagem do MIPS assembly. // Nth_Fibonacci(n): // $s0 -> n, $s1 -> fib // $t0 -> i, $t1 -> j // Assume fib, i, j are these values int fib = 1, i = 1, j = 1; if (n==0) return 0; else if (n==1) return 1; n -= 2; while (n != 0) { fib = i + j; j = i; i = fib; n--; } return fib; P18) Escreva, na linguagem de montagem do MIPS, um programa que converta uma string decimal em ASCII para um número inteiro. Seu programa deve considerar que o registrador $a0 tem endereço do caractere null, usado para marcar o fim da string que contém alguma combinação dos dígitos de 0 a 9. Seu programa deve calcular o valor inteiro correspondente a essa string de bits, colocando seu valor no registrador $v0. Seu programa não deve preocupar-se com números negativos. Se for identificado no string um caractere que não represente um dígito, seu programa deve retornar o valor -1 no registrador $v0. Por exemplo, se o registrador $a0 aponta para uma sequência de três bytes: 50dez, 52dez, 0dez , seguida do caractere null = 24, então, quando o programa termina, o registrador $v0 deve ter o valor 24dez armazenado nele.(O subscrito “dez” significa base 10.) P19) Escreva um procedimento, itoa, na linguagem de montagem, do MIPS, para converter um argumento inteiro na sua representação decimal ASCII. O procedimento deve receber dois argumentos: o primeiro é um valor inteiro a ser convertido, que deve estar no registrador $a0, e o segundo é o endereço onde escrever a string obtido da conversão, endereço este armazenado no registrador $a1. Portanto, itoa deve converter seu primeiro argumento para uma string terminada com o caractere null armazenando esta string no endereço obtido do seu segundo argumento. O procedimento deve retornar também, em $v0, o valor numérico correspondente à contagem dos caracteres diferentes de null, pertencentes à string gerada. P20) Escreva em MIPS assembly o programa abaixo: num1: num2: main: .data .word 0x7FFFFFFF .word 16 .space 8 .text lw $t0,num1($0) lw $t1,num2($0) mult $t0,$t1 mfhi $t0 mflo $t1 sw $t0,num2+4($0) sw $t1,num2+8($0) Arquitetura e Organização de Computadores 2 5 Este programa declara duas variáveis num1 e num2, carrega-as para os registos $t0 e $t1 respectivamente e armazena o resultado da multiplicação nas palavras que vêm depois dessas variáveis (a diretiva .space reserva espaço para essas duas palavras). Que resultado se obtém após executar este programa? Porque fica o resultado armazenado em duas palavras de memória? Modifique o código para que num1 e num2 sejam respectivamente 10 e 3. Reescreva código para dividir num1 por num2 e coloque o quociente e resto nas posições que vêm a seguir a num1 e num2. P21) Escreva uma função em MIPS assembly, denominada senox, que calcula o seno de x. A sua função apenas deverá calcular os primeiros 10 termos, isto é, até ao termo x 19/19!. O seno de x pode ser calculado utilizando a expansão da série de Taylor: 𝒔𝒆𝒏𝒐 𝒙 = 𝒙 − 𝒙𝟑 𝒙𝟓 𝒙𝟕 + − +⋯ 𝟑! 𝟓! 𝟕! O elemento x da série de Taylor deve ser em radianos. Portanto, a função senox deve ler o valor do ângulo em graus e converter para radianos. Para realizar a conversão utilize a regra de três, considerando que PI radianos é igual a 180 e que a constante PI assume valor de 3.141592 P22) Escreva uma função em MIPS assembly, denominado cosex, que calcula o cosseno de x. A sua função apenas deverá calcular os primeiros 10 termos, isto é, até ao termo x20/20!. O cosseno de x pode ser calculado utilizando a expansão da série de Taylor: 𝒙𝟐 𝒙𝟒 𝒙𝟔 𝒄𝒐𝒔𝒔𝒆𝒏𝒐 𝒙 = 𝟏 − + − + ⋯ 𝟐! 𝟒! 𝟔! O elemento x da série de Taylor deve ser em radianos. Portanto, a função cosex deve ler o valor do ângulo em graus e converter para radianos. Para realizar a conversão utilize a regra de três, considerando que PI radianos é igual a 180 e que a constante PI assume valor de 3.141592 P23) Escreva uma função em MIPS assembly, denominado exp para calcular ex por desenvolvimento em Série de Taylor desprezando termos, em grandeza, inferiores a 10-7. 𝒆𝒙 = 𝟏 + 𝒙 𝒙𝟐 𝒙𝟑 + + +⋯ , 𝟏! 𝟐! 𝟑! −∞ < 𝒙 < ∞ A função exponencial deve somar os termos da série até aparecer um termo cujo valor absoluto seja menor 𝑥𝑘 que 0.0001 (precisão). Isto é, o termo | | tende a zero quando k tende a +∞. Repetir o cálculo dos termos 𝑘! 𝑥𝑘 até um k tal que | | < 0.0000001. (5,0 pontos) 𝑘! Dica: evite calcular o valor do fatorial, calcule um termo da série usando o termo anterior. P24) Escreva em MIPS assembly um programa que, dado um vetor v com 5 posições (por exemplo, int v[5] = { 3, 2, 4, 1, 5 }) faça um gráfico horizontal com os valores do vetor. Exemplo: para o vetor v acima, deve imprimir na tela: 3 *** 2 ** 4 **** 1* 5 ***** Arquitetura e Organização de Computadores 2 6 P25) Considere o seguinte jogo: n pessoas (numeradas de 1 a n) são dispostas em círculo. O algoritmo deve eleger uma posição inicial em aleatório e remover as pessoas do círculo de forma alternada (pessoasim-pessoa-não) e o círculo aperta-se. O algoritmo termina quando restar apenas uma pessoa (sobrevivente). Por exemplo, para n = 10 e posição inicial igual a 2, a ordem das eliminações é: 2, 4, 6, 8, 10, 3, 7, 1, 9 e 5 é o sobrevivente (ver figura). Escreva em MIPS assembly um programa que leia n e escreva a ordem das eliminações e o sobrevivente de acordo com este algoritmo. DICA: Represente o círculo de pessoas com uma variável indexada Arquitetura e Organização de Computadores 2 7