Baixe o app para aproveitar ainda mais
Prévia do material em texto
Introdução à Arquitetura de Computadores Conteúdo 1 Capa 1 2 Introdução 2 2.1 O Que é Arquitetura de Computadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2.2 Computadores e as Várias Camadas de Abstração . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 Modelo de Von Neumann 4 4 O que é o MIPS? 5 4.1 O Processador MIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 4.2 A Filosofia do Projeto do MIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 Instruções do MIPS 6 5.1 Instruções Aritméticas Simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 5.2 Instruções de Operadores Lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 5.3 Instruções de Uso de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 5.4 Instruções de Controle de Fluxo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 5.5 Instruções de Comparações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 5.6 Resumo dos Modos de Endereçamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 6 Representação das Instruções 9 6.1 As Instruções Tipo R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.2 As Instruções Tipo I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.3 As Instruções Tipo J . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 7 As Pseudo-Instruções 10 7.1 A Pseudo-Instrução move . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 7.2 A Pseudo-Instrução Load Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 8 Suporte à Funções 11 8.1 As Etapas Necessárias para Invocar Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 8.2 Instruções de Uso de Funções: jal e jr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 8.3 Funções com Muitas Variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 8.4 Funções Recursivas e Sub-Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 i ii CONTEÚDO 9 Representação Numérica 13 9.1 Números Naturais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 9.2 Números Inteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 9.3 Números Reais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 9.4 Overflow e Underflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 10 As Operações da Unidade Lógica Aritmética 15 10.1 A Adição e Subtração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 10.2 A Multiplicação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 10.3 Fontes, contribuidores e licenças de texto e imagem . . . . . . . . . . . . . . . . . . . . . . . . . 18 10.3.1 Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 10.3.2 Imagens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 10.3.3 Licença . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Capítulo 1 Capa Introdução à Arquitetura de Computadores 1 Capítulo 2 Introdução 2.1 O Que é Arquitetura de Com- putadores A Arquitetura de Computadores é o projeto concei- tual e fundamental da estrutura operacional de um sis- tema computacional. Ela é o estudo dos requisitos ne- cessários para que um computador funcione e de como organizar os diversos componentes para obter melhores desempenhos. Como computador entendemos qualquer tipo de dispo- sitivo capaz de receber uma entrada e que retorna uma saída após realizar uma série de operações com base nos valores recebidos e armazenados. Existem vários tipos de computadores. Uma das formas de classificá-los é por meio das seguintes categorias: • Desktop: Computadores de baixo-custo e com de- sempenho razoável para um usuário “comum”. • Servidor: Máquinas projetadas para ter um desem- penho considerado bom para uma aplicação muito grande e complexa ou então para um número muito grande de operações mais simples. Alguns servido- res são simples computadores de Desktop melhora- dos. Entretanto, existem também aqueles que pos- suem arquiteturas muito mais sofisticadas que con- tam com dezenas ou até mesmo centenas de proces- sadores. • Sistemas Embarcados: Possuem um uso dedi- cado à uma única tarefa e normalmente vem em- butidos em outros aparelhos como celulares, micro- ondas, elevadores ou veículos. Possuem uma En- trada/Saída muito simples. Os princípios estudados em Arquitetura de Computa- dores são fundamentais para se projetar máquinas real- mente eficientes. 2.2 Computadores e as Várias Ca- madas de Abstração Computadores são aparelhos extremamente complexos. Para compreender o seu funcionamento, precisamos en- tender várias camadas de abstração diferente. A camada mais baixa de todas é aquela formada por tran- sistores, tensão e corrente elétrica. Quem costuma li- dar com esta camada são físicos e engenheiros elétricos. Nesta camada estuda-se o funcionamento de transistores e circuitos sempre levando em conta as propriedades fí- sicas da corrente elétrica. Abaixo vemos um desenho re- presentando um transistor. Uma camada acima, estão as portas lógicas - todas elas compostas por transistores. Neste nível estuda-se como criar estruturas mais complexas combinando-se as diver- sas portas como AND, OR e NOT para criar estruturas como multiplexadores, flip-flops e somadores. Neste es- tágio pode-se usar linguagens como o Verilog ou VHDL para programar circuitos. Abaixo vemos desenhos que representam várias portas lógicas: 2 2.2. COMPUTADORES E AS VÁRIAS CAMADAS DE ABSTRAÇÃO 3 Subindo mais um nível de abstração, começamos a lidar com estruturas mais complexas como registradores e uni- dades lógicas aritméticas - todas compostas por muitos flip-flops, somadores e multiplexadores. Vemos como todas essas estruturas realmente geram as instruções de cada máquina e como cada instrução funciona. É neste nível que costuma trabalhar um Arquiteto. Este será o nível que será abordado ao longo deste Wiki-livro. Abaixo mostramos a imagem de uma Unidade Lógica Aritmética - estrutura usada por computadores para re- alizar cálculos: Um nível além, estuda-se como combinar as instruções da camada anterior para realizar comandos mais sofisticados como as operações da lingüagem C e como coordenar o funcionamento de um sistema operacional por meio de interrupções e outros recursos. A imagem abaixo é um diagrama que representa o Kernel de um Sistema Opera- cional sendo usado como um meio de comunicação entre o Software e o Hardware: CPU Memory Devices Kernel Applications Acima desta camada, está o estudo do funcionamento de funções de bibliotecas, APIs e a programação de aplica- tivos e programas de computador simples.E finalmente, na camada de abstração mais superior está o funciona- mento de um programa de computador do ponto de vista do usuário. Como utilizar um aplicativo já criado. Capítulo 3 Modelo de Von Neumann Modelo de Von Neumann O modelo de arquitetura de computadores conhecido comoModelo de Von Neumann é uma forma de organi- zação genérica dos componentes de um sistema computa- cional digital. Esse modelo de arquitetura de computador digital proposto por Von Neumann está baseado em três premissas ou características básicas: a) os dados e as instruções ficam armazenadas no mesmo espaço de memória; b) cada espaço de memória possui um endereço, oqual será utilizado para identificar a posição de um determi- nado conteúdo; c) as instruções são executadas de forma sequencial. O modelo de arquitetura proposto por Von Neumann foi amplamente aceito, e o projeto conceitual do seu modelo é utilizado nos projetos de praticamente todos os com- putadores modernos atuais. De forma geral, o modelo de Von Neumann consolidou a divisão entre dois importan- tes conceitos que são hardware e software. Pois o projeto conceitual de computador digital proposto por esse mo- delo utiliza o conceito de programa armazenado na me- mória, juntamente com os dados que serão manipulados, ou seja, utiliza uma seqüência ordenada de instruções que conhecemos como software, independente do hardware. A arquitetura de Von Neumann é composta por: Memó- ria; CPU, que contém os registradores, Unidade aritmé- tica e lógica, e Unidade de Controle (CU); E ainda os dispositivos de entrada e saída para comunicação com o meio externo. A figura abaixo ilustra como estão interco- nectados os componentes do modelo de Von Neumann: Os componentes do modelo de Von Neumann comunicam-se através de uma estrutura interna co- nhecida como barramento, que operam a velocidades altíssimas interligando os principais componentes do modelo. 4 Capítulo 4 O que é o MIPS? 4.1 O Processador MIPS O MIPS é o nome de uma arquitetura de processadores baseados no uso de registradores. As suas instruções tem à disposição um conjunto de 32 registradores para rea- lizar as operações. Entretanto, alguns destes registrado- res não podem ser usados por programadores, pois são usados pela própria máquina para armazenar informações úteis. Processadores MIPS são do tipo RISC (Reduced Instruc- tion Set Computer - ou seja, Computadores com Con- junto de Instruções Reduzidas). Isso significa que existe um conjunto bastante pequeno de instruções que o pro- cessador sabe fazer. Combinando este pequeno número, podemos criar todas as demais operações. Pela sua elegância e simplicidade, processadores MIPS são bastante usados em cursos de arquiteturas de muitas universidades. Ele é considerado um processador bas- tante didático. ProjetosMIPS são atualmente bastante usados emmuitos sistemas embarcados como dispositivos Windows CE, roteadores Cisco e video-games como o Nintendo 64, Playstation, Playstation 2 e Playstation Portable. 4.2 A Filosofia do Projeto doMIPS Quando oMIPS estava sendo desenvolvido, quatro regras foram definidas para guiar o projeto. Elas são a filosofia do MIPS: • A simplicidade favorece a regularidade. • Omenor é (quase sempre) mais rápido. Levando em conta que uma corrente elétrica se propaga cerca de um palmo por nanosegundo, circuitos simples são menores e portanto, mais rápidos. • Um bom projeto demanda compromissos. • O caso comum DEVE ser mais rápido. É muito melhor tornar uma instrução que é usada 90% do tempo 10% mais rápida do que fazer com que uma instrução usada em 10% das vezes torne-se 90% mais rápida. Esta regra é baseada na “Lei de Am- dahl”. Foram estas as regras usadas para decidir vários aspectos do funcionamento do MIPS - incluindo quais seriam suas instruções e como elas funcionariam. 5 Capítulo 5 Instruções do MIPS Vamos começar agora a estudar as instruções que exis- tem em um computador MIPS. Para praticar e testar as instruções caso você não tenha umamáquinaMIPS é usar um simulador como o SPIM. O download do simulador SPIM para Linux, Mac OS, Unix e Windows pode ser feito no link: . O objetivo deste capítulo não é fornecer um guia de refe- rência exaustivo sobre todas as instruções dos MIPS. Ire- mos apenas apresentar um sub-conjunto mínimo de todas as instruções do MIPS que são o mínimo necessário para termos um computador funcionando. 5.1 Instruções Aritméticas Simples add $r1, $r2, $r3 # Esta instrução soma o conteúdo dos registradores # $r2 e $r3 colocando o conteúdo no regis- trador $r1 addi $r4, $r1, 9 # Agora estamos somando o conteúdo do registrador # $r1 com o valor imediato 9 e armazenando o # resultado em $r4. O número imedi- ato deve ter # 16 bits. addu $r5, $r6, $r4 # Quase igual ao add. Mas agora assumimos que # todos os valores são não-negativos. addiu $r7, $r8, 10 # Somamos o conteúdo de $r8 com o valor imediato # 10 e armazenamos o re- sultado em $r7. Assume-se # que todos os valores são não-negativos. sub $r1, $r2, $r3 # Subtrai-se o conteúdo de $r3 do conteúdo de $r2 # e coloca-se em $r1. Tam- bém existe subi, subu e # subiu que tem comportamento semelhante a addi, # addu e addiu, mas para a subtração. 5.2 Instruções de Operadores Ló- gicos and $r1, $r2, $r3 # Realiza uma operação AND bit-a-bit entre $r3 e $r2. # O resultado é armazenado em $r1. andi $r1, $r2, 42 # Realiza uma operação AND bit-a-bit entre $r2 e o valor # imediato 42. O resultado é armazenado em $r1. O número # imediato deve caber em 16 bits. or $r1, $r2, $r3 # Realiza uma operação OR bit-a-bit entre $r3 e $r2. # O resultado é armazenado em $r1. ori $r1, $r2, 42 # Realiza uma operação OR bit-a-bit entre $r2 e o valor # imediato 42. O resultado é armazenado em $r1. O número # imediato deve caber em 16 bits. Podemos notar que as instruções seguem uma lógica clara. Até agora todas seguem uma mesma lógica. Além destas, não existem instruções mais complexas como po- tências ou raízes quadradas.Somente as operações mate- máticas mais simples são representadas. Podemos ver aquelas 4 regras que formam a filosofia do projeto do MIPS em ação. 5.3 Instruções de Uso de memória As instruções do uso da memória seguem uma lógica di- ferente das instruções de operações aritméticas. Pra co- meçar, existem três tipos de instruções capazes de copiar dados da memória para os registradores. lw $r1, 4($r2) # Load Word: Esta instrução carrega uma palavra (estrutura de 4 bytes) # localizada no endereço representado pela soma do valor # armazenado no regis- trador $r2 mais 4. O resultado é armazenado em $r1. lh $r1, 6($r3) # Load Half: Esta instrução carrega uma es- trutura de 2 bits localizada # no endereço representado pela soma do valor armazeado no # registrador $r3 mais o número 6. O resultado é armazenado em $r1. lb $r1, 16($r2)# Load Byte: Esta instrução carrega um byte (8 bits) localizado no # endereço representado pela soma do valor armazenado em $r2 mais o # número 16. O resul- tado é armazenado em $r1. Perceba que desta forma é rápido de carregar o conteúdo de um valor em um vetor. Basta saber o endereço do va- lor inicial do vetor e o índice de sua posição. Por exem- plo, suponha que eu possua um vetor de caracteres char vetor[5]. Supondo que o registrador $r1 contenha o en- dereço de vetor[0], para armazenar o valor de vetor[3] no registrador $r2 e assumindo que cada caractere possui um byte, basta usar a seguinte instrução: lb $r2 24($r1) Colocamos o 24 lá porque cada caractere ocupa 8 bits e queremos pegar o quarto caractere da seqüência. Logo, precisamos nos deslocar 24 bits para acharmos o carac- tere certo. Afinal, a distância entre o primeiro elemento do vetor armazenado em $r1 e o quarto item do vetor é 6 5.4. INSTRUÇÕES DE CONTROLE DE FLUXO 7 de 24: [0][ ][ ][ ][ ][ ][ ][ ].[1][ ][ ][ ][ ][ ][ ][ ].[2][ ][ ][ ][ ][ ][ ][ ].[3][ ][ ][ ][ ][ ][ ][ ] Para armazenarmos conteúdo de um registrador na me- mória também existem 3 comandos: sw $r1, 4($r2) # Store Word: Esta instrução carrega uma palavra (estrutura de 4 bytes) # localizada no registrador $r1 e armazena no endereço representado # pela soma do valor armazenado no registrador $r2 mais 4. sh $r1, 4($r2) # Store Half: Esta instrução carrega uma estrutura de 2 bits # localizada no registrador $r1 e armazena no endereço representado # pela soma do valor armazenado no registrador $r2 mais 4. sb $r1, 4($r2) # Store Byte: Esta instrução carrega um byte (8 bits) # localizado no registrador $r1 e armazena no endereço representado # pela soma do valorarmazenado no registrador $r2 mais 4. Vamos ver um exemplo de conversão de um código es- crito em C para a lingüagem Assembly do MIPS assu- mindo que um int da lingüagem C tenha 4 bits: /* CÓDIGO C */ typedef struct A{ int x; int y; int z; int w; }aType; aType V[16]; (...) aPtr = &(V[3]); m = aPtr -> y; n = aPtr -> w; aPtr -> x = m + n; Vamos assumir que o vetor V esteja no endereço 0x0800.0000. A estrutura aType é formada por 4 valo- res numéricos consecutivos, cada um com 4 bits. Logo, cada aType ocupa 16 bits (4*4). Ou, em hexadecimal, 0x010 bits. Veja uma representação de um aType como é armazenado na memória: [x][x][x][x][y][y][y][y][z][z][z][z][w][w][w][w] Temos um vetor com 16 estruturas como esta chamado V. Logo, o vetor ocupa um espaço de 256 bits. Com es- tas informações, concluímos que o código em Assembly necessário para fazer a operação mostrada no código em C mostrado acima é: la $r1, 0x0800.0030 # A instrução Load Address carrega em $r1 o endereço de V[3]. Falaremos sobre o la depois. lw $r2, 4($r1) # Carregamos para $r2 o quarto bit à partir de V[3]. Ou seja, o valor de y. lw $r3, 12($r1) # Agora carregamos para $r3 o valor do inteiro w. add $r4, $r2, $r3 # Somamos os valores de y e w colocando o valor em $r4. sw $r4, 0($r1) # Colocamos o valor da soma no lugar do x. 5.4 Instruções de Controle de Fluxo Agora veremos instruções capazes de controlar o fluxo de execução de instruções de um computador. A primeira delas é a instrução beq, ou Branch if Equal: beq $r1, $r2, DESTINO Oque esta instrução faz é verificar se o valor de $r1 é igual à $r2. Caso isso seja verdadeiro, ela muda o valor do re- gistrador PC (Program Counter) que guarda o endereço da próxima instrução a ser executada. Se o valor passado como destino for 0, nada acontece. Nenhuma instrução é pulada, o programa executa a próxima instrução nor- malmente, independente de $r1 == $r2 ser verdadeiro ou falso. Se o valor passado for “1”, pula-se uma instrução se $r1 for igual a $r2. Se o valor passado for “2”, pulam- se duas instruções e assim por diante. Também pode-se passar valores negativos. Um valor de "−1” faz com que o programa entre em um loop infinito, nunca mais pas- sando para a próxima instrução. Uma "−2” faz com que voltemos uma instrução anterior, e assim por diante. Entretanto, o valor de DESTINO só pode ser no máximo um valor com 16 bits. Com um valor destes, só pode- mos pular no máximo cerca de 32 000 instruções para frente ou para trás. Isso não é um problema na maio- ria das vezes é muito raro existir um programa que exija que você pule uma quantidade tão grande de instruções. Assumindo que 4 linhas de código e Assembly corres- pondem a 1 linha em código C, para que pulemos uma quantidade tão grande de instruções, teríamos que fazer um if com um bloco com mais de 8.000 linhas de có- digo. Isso é algo extremamente difícil de ocorrer em um programa real. Mas caso você realmente precise pular mais de 32 000 instruções, isso é perfeitamente possível, desde que você altere antes o valor do registrador PC. Com isso, perde-se um pouco de desempenho, mas torna desvios de código extremamente grandes possível. E o importante é que o caso comum (programas em C com blocos menores de 8.000 linhas) roda mais rápido (regra 4 da Filosofia de Projeto do MIPS). Além do beq, temos também o bne, ou Branch if Not Equal: bne $r1, $r2, DESTINO Ele funciona da mesma forma que o beq. A diferença é que ele pula um determinado número de instruções so- mente se o valor dos dois registradores for diferente. E finalmente, temos a instrução j, ou Jump: j ENDEREÇO Ele faz com que o programa passe a executar a instrução que é encontrada no endereço dado. O endereço passado para a instrução j é sempre um número de 26 bits. Entre- tanto, os endereços da máquina sempre são números de 32 bits. Então como será possível saber qual o endereço em que está a instrução desejada? É muito simples. Instruções sempre estarão em ende- reços múltiplos de 4. Então sabemos que os dois últi- mos bits do endereço são sempre 0. Não precisamos armazená-los. Já os dois primeiros bits, retiramos do PC, pois é sempre muito mais provável que nós usemos o controle de fluxo para saltar para uma posição não muito distante. Caso precisemos saltar para um posição muito 8 CAPÍTULO 5. INSTRUÇÕES DO MIPS distante, basta alterarmos o valor do PC primeiro. Da mesma forma que foi visto no beq, o caso comum exe- cuta mais rápido desta forma. Isso é muito bom, mesmo que tenhamos mais trabalho e perda de desempenho nas pouquíssimas vezes nas quais precisamos dar saltos muito longos. 5.5 Instruções de Comparações Por fim, precisamos ver ainda instruções de comparação. Um exemplo é o slt, ou Set Less Than: slt $r1, $r2, $r3 Ela armazena 1 em $r1 se $r2 < $r3 e 0 caso contrário. 5.6 Resumo dos Modos de Endere- çamento Nas instruções do MIPS podemos representar os endere- ços de dados das seguintes formas: • A Registrador: Representamos o dado passando o nome do registrador no qual ele está contido. Ex: add $r1, $r2, $r2. • Base-Deslocamento: Representamos o dado pas- sando o endereço de um vetor no qual ele está e a quantidade de bits a serem deslocados. Ex: lw $r5, 4($r65). • Imediato: Passamos o dado escrevendo o seu valor imediato. Ex: addi $r1, $r2, 456. • Relativo ao PC: Passamos o dado descrevendo o seu valor relativo ao endereço da instrução atual. Ex: beq $r1, $r2, DESTINO. • Absoluto: passamos o valor informando o seu en- dereço (pseudo-)absoluto. Ex: j DESTINO. Existem apenas estas 5 formas de endereçamento no MIPS. Através delas, efetuamos todas as operações ne- cessárias. Capítulo 6 Representação das Instruções Sabemos que tudo dentro do computador é representado por meio de bits - que podem ter o valor de 0s e 1s. Até mesmo as instruções de um processador MIPS. Vamos estudar agora como uma instrução é representada a ní- vel de bits. O MIPS reconhece 3 famílias diferentes de instruções. São elas: 6.1 As Instruções Tipo R Como exemplo de instruções do tipo R vistas, temos: add, addu, sub, subu, or e and. Elas são codificadas da seguinte forma: [o][o][o][o][o][o] - [u][u][u][u][u] - [t][t][t][t][t] - [d][d][d][d][d] - [s][s][s][s][s] - [f][f][f][f][f][f] Onde a letra “o”, representa o opcode, ou Código de Ope- ração. Ele avisa mais-ou-menos o que a instrução vai fa- zer. Por exemplo, uma instrução de soma add é muito semelhante à instrução xor que faz um XOR lógico bit-a- bit. A única diferença é que na soma, devemos armazenar um bit a mais para representar o “vai um” quando soma- mos 1+1. Logo, as duas instruções tem o mesmo opcode. As letras “u” e “t” representam os operandos das instru- ções. Ou melhor, os registradores nos quais estão os ope- randos. A letra “d” é o registrador de destino onde deve ser arma- zenado o resultado. A letra “s” ou Shampt representa o deslocamento de bits, ou seja um shift que pode se usado após a operação. Finalmente, a letra “f” é o código de função. É por meio dela que diferenciamos instruções semelhantes que tem o mesmo opcode, como add e or. 6.2 As Instruções Tipo I Como exemplo deste tipo de instrução, podemos citar to- das aquelas que contam com um valor imediato, como addi, subi, ori, beq e bnq. Eles são codificados da seguinte forma: [o][o][o][o][o][o] - [u][u][u][u][u] - [t][t][t][t][t] - [i][i][i][i][i][i][i][i][i][i][i][i][i][i][i][i] A letra “o” representa o código da instrução. A letra “u” represeenta o número do registrador onde a o resultado da operação é colocado. Já a letra “t” representa o número do registrador em que está um dos operandos. Já o “i” representa o número imediato. Agora vemos o porquê do valor passado como imediato nunca poder exceder os 16 bits. 6.3 As Instruções Tipo J A única instrução vista no capítulo anterior do tipo J é a j. Ela é codificada da seguinte forma: [o][o][o][o][o][o] - [d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d][d]O “o” representa o código da operação j e d representa o destino. 9 Capítulo 7 As Pseudo-Instruções A linguagem Assembly de uma máquina costuma ser um reflexo direto de como são implementadas as instruções de um determinado processador. Entretanto, nem to- das as instruções que temos à disposição quando pro- gramamos em Assembly são instruções verdadeiras para o processador. Algumas delas são na verdade pseudo- instruções. Pseudo-instruções costumam ser substituídas pelo mon- tador ao gerar instruções para o computador na forma de Lingüagem de Máquina. Pseudo-Instruções são na verdade combinações de mais de uma instrução. Veja- mos agora alguns exemplos: 7.1 A Pseudo-Instrução move move $r1, $r2 # Copia o conteúdo do registrador $r2 para $r1 Ela é na verdade implementada da seguinte forma: addu $r1, $r0, $r2 # Soma $r2 com zero e coloca o resul- tado em $r1 O registrador $r0 usado acima não é um registrador co- mum. Ele sempre possui o valor “0” e é um dos poucos registradores cujo valor nunca pode ser alterado pelo pro- gramador. 7.2 A Pseudo-Instrução Load Ad- dress la $r1, ENDEREÇO # Coloca o valor numérico de 32 bits “ENDEREÇO” em $r1 Esta instrução é muito útil para fazer registradores rece- berem o valor de ponteiros para outros locais de memó- ria. De fato, usamos esta pseudo-instrução no Capítulo anterior quando convertemos um código em C para o As- sembly do MIPS. Ela é na verdade implementada desta forma: lui $r1, constHI # Carrega-se os 16 bits mais significativos em $r1 ori $r1, $r0, constLO # Executa-se um OR bit-a- bit entre o registrador # com os 16 bits mais significativos e os 16 bits # menos significativos O que a instrução lui, ou Load Upper Immediate faz é uma operação shift de 16 bits para a esquerda e coloca no registrador indicado. Este passo é necessário porque valores imediatos passados para instruções só podem ter 16 bits por causa da limitação de espaço das instruções do Tipo I. Também existe a instrução li, ou Load Immediate que faz exatamente a mesma coisa que o la. Note que o montador que remove as pseudo-instruções e as substitui por instruções que realmente existem no hardware sempre podem verificar se o valor que quere- mos carregar no registrador cabe em 16 bits. Neste caso, a instrução gerada fica bem mais simples e rápida: addu $r1, $r0, $r2 # Soma $r2 com 0 e coloca em $r1 10 Capítulo 8 Suporte à Funções Funções são ferramentas muito importantes, pois tornam código escrito muito mais usável e torna a tarefa de pro- gramar mais produtiva. Elas permitem que um progra- mador se concentre em apeenas uma tarefa de cada vez. Portanto, é essencial que um processador possua suporte á elas. Veremos como isso ocorre no MIPS. 8.1 As Etapas Necessárias para In- vocar Funções Quando queremos chamar uma função, as seguintes eta- pas devem ser cumpridas: • O programa principal deve colocar os parâmetros da função em um local que ela possa acessar. • O programa principal deve ceder o controle para a função. • A função deve coletar todos oos parâmetros deixa- dos pelo programa principal. • A função deve executar a tarefa desejada. • A função deve armazenar seus resultados em um lu- gar em que o programa principal possa acessar. • A função deve retornar o fluxo do código para o ponto imediatamente após ser chamada. Para que estes requisitos sejam cumpridos, as seguintes convenções fora criadas: • Os registradores $r4, $r5, $r6 e $r7 seriam usados para armazenar parâmetros de funções. Por causa desta funcionalidade, tais registradores podem ser chamados pelos seus “apelidos": $a0, $a1, $a2 e $a3. • Os registradores $r2 e $r3 seriam usados para as funções armazenarem seus valores de retorno para o programa principal. Por isso, eles costumam ser chamados de $v0 e $v1. Tais regras são apenas convenções. Nada impede que um programador as desrespeite e use outros registrado- res para estabelecer comunicação entre funções e progra- mas principais. Entretanto, para que um programa funci- one bem em conjunto com todos os demais, é importante quee tais convenções sejam seguidas. Além dos registradores convencionados acima, o regis- trador $r31 também tem um papel importante. Ele sem- pre armazena o endereço de retorno para o qual a última função chamada deve retornar. Por ter uma função tão importante, este registrador é mais conhecido pelo ape- lido $ra. 8.2 Instruções de Uso de Funções: jal e jr A instrução que usamos para invocar uma função chama- se jal, ou Jump and Link. Ela é usada da seguinte forma: jal ENDEREÇO_DA_FUNÇÃO Entretanto, só devemos chamar esta função depois de já termos salvo os argumentos nos registradores apropria- dos. Depois da função executar todas as operações e salvar os resultados apropriados em $v0 e $v1, podemos usar a instrução jr, ou Jump Register. Normalmente usamos a instrução passando para ela o valor do registrador $ra, que contém o endereço certo para voltarmos: jr $ra Como exemplo de como isso pode ser feito, vamos con- verter para Assembly o seguinte código em C: int example(int a, int b, int c, int d){ int f; f = (a + b) - (c + d) return f; } O código no Assembly do MIPS ficaria assim: example: # Label add $t0, $a0, $a1 # Soma a + b add $t1, $a2, $a3 # Soma c + d sub $v0, $t0, $t1 # Subtrai os dois valores e coloca o resultado no registrador de retorno jr $ra # Retorna o controle para a função principal Entretanto, observe que para realizarmos os cálculos ne- cessários, precisamos usar registradores. Ao fazer isso, 11 12 CAPÍTULO 8. SUPORTE À FUNÇÕES existe o grande risco de apagarmos dados importantes do programa principal. Para evitar isso, existe uma conven- ção que diz que os registradores $r8 até $r15, $r24 e $r25 são registradores temporários. Por isso, eles costumam ser chamados de $t0 até $t9. Após chamar uma função, o programa principal não deve esperar que os valores des- tes registradores sejam os mesmos. Somente dados que estejam nos registradores $r16 até $r23 são sempre pre- servados entre funções. Por esta razão, tais registradores permanentes (salvos) são chamados de $s0 até $s7. 8.3 Funções com Muitas Variáveis Existem funções que podem precisar receber mais do que 4 parâmetros. Entretanto, só temos registradores sufici- entes para armazenar 4 parâmetros. Nós também pode- mos querer retornar mais do que os 2 valores permitidos pelos registradores. Ou então, nossa função pode preci- sar armazenar mais do que 10 valores temporários. O que fazer para resolver isso? Como o espaço dentro de registradores é bastante limi- tado, só nos resta apelar para a pilha da memória. Por convenção, o registrador $r29, ou $sp (Stack Pointer) ar- mazena o endereço na pilha de onde novos valores podem ser colocados. Acessando seu endereço e alterando-o po- demos guardar valores na memória. O acesso à pilha da memória é muito mais lento que o acesso à registradores, mas este é o único modo de podermos armazenar uma quantidade muito maior de informação. Por motivos históricos, a pilha “cresce” sempre dos va- lores de endereços altos para valores menores. Ou seja, para alocar espaço para mais valores, precisamos sempre decrementar o seu valor. Incrementando-o, estamos na verdade removendo os últimos dados da pilha. Vamos reescrever agora o código Assembly visto acima, desta vez preeservando os valores dos registradores $t0 e $t1 para vermos como ficaria o resultado: example: # Label addi $sp, $sp, −8 # Alocamos espaço para dois valores de 4 bits. sw $t1, 4($sp) # Preservamos o valor de $t1 à partir do 4o bit após o Stack Pointer sw $t0, 0($sp) # Preservamos o valor de $t0 sobre o Stack Pointer add $t0, $a0, $a1 # Soma a + b add $t1, $a2, $a3 # Soma c + d sub $v0, $t0, $t1 # Subtrai os dois valores e coloca o resultado no registrador de retorno lw $t0, 0($sp) # Retiramos o valor antigo salvo de $t0 lw $t1, 4($sp) # Retiramosda pilha o valor antigo de $t1 addi $sp, $sp, 8 # Voltamos o Stack Pointer para a posição original apagando de vez as variáveis locais jr $ra # Retorna o controle para a função principal 8.4 Funções Recursivas e Sub- Funções Da mesma forma que o programa principal invocou uma função, uma função também pode invocar outras fun- ções. Se la for recursiva, ela pode até mesmo invocar clo- nes de si mesma para realizar uma tarefa. Como imple- mentar isso sendo que temos apenas um registrador $ra? Se chamarmos outra função, o $ra original é sobrescrito e podemos perder a capacidade de voltar ao programa prin- cipal. Além disso, valores temporários que representam variáveis locais podem ser perdidos. A única forma de evitar isso é enviar para a pilha tudo aquilo que precisa ser salvo - damesma forma que fizemos com alguns valores no exemplo acima. Para mostrar isso na prática vamos implementar em Assembly a seguinte função em C: /* Calcula Fatorial */ int fat(int n){ if(n < 1) return 1; else return (n * fat(n - 1)); } O resultado final é algo como: fat: # Início da função addi $sp, $sp, −8 # Aloca espaço na pilha para 2 valores sw $ra, 4($sp) # Guarda valor de retorno na pilha sw $a0, 0($sp) # Guarda primeiro argu- mento na pilha slti $t0, $a0, 1 # $t0 = ( $a0 < 1) beq $t0, $zero, L1 # Se $a0 >= 1, vá para L1 addi $v0, $zero, 1 # Senão, coloque 1 como valor de retorno addi $sp, $sp, 8 # Apague as duas variáveis locais salvas na pilha jr $ra # Encerra a função L1: addi $a0, $a0, −1 # Se $a >= 1, decremente $a0 jal fat # Chame um clone recursivo de fat que retorna fat($a0-1) lw $a0, 0($sp) # Recupere os valores iniciais do parâmetro da função lw $ra, 4($sp) # Recupere o endereço de retorno antigo addi $sp, $sp, 8 # Apague as duas variáveis locais salvas na pilha mul $v0, $a0, $v0 # Coloque $a0 * fat($a0 - 1) como valor de retorno jr $ra # Encerra a função Por fim, uma última coisa útil que é interessante comentar é que o Stack Pointer ($sp) pode ser alterado várias vezes ao longo de uma função. Paramantermemorizado o valor do endereço da pilha no início da função, costuma-se usar o registrador $r30 como um Frame Pointer ($fp). Nos exemplos acima, isso não foi preciso, pois só mudamos o valor do Stack Pointer no começo e fim de cada função. Mas em alguns programas utilizar este registrador pode ser útil. Capítulo 9 Representação Numérica Números podem ser representados em qualquer tipo de base. Humanos costumam representar números na base decimal. Esta possui este nome por possuir 10 dígitos diferentes: 0, 1, 2, 3, 4, 5, 6, 7, 8 e 9. Como computadores só são capazes de reconhecer dois tipos diferentes de estados, é natural para eles representar números na base binária. Ou seja, eles só compreendem os valores “0” e “1”. Vamos ver agora coo podemos re- presentar diversos tipos de números usando apenas dois tipos diferentes de sinais. 9.1 Números Naturais Representar Números Naturais é simples bastante sim- ples - mesmo quando só podemos usar dois tipos dife- rentes de sinais. O 0 decimal é representado como 0. O 1 decimal também é representado como 1. Já o 2 deci- mal é representado com “10”. Enfim, quando contamos os números naturais na base binária, fazemos da seguinte forma: BASE | BINÁRIA | 0 1 10 11 100 101 110 111 1000 1001 1010 | BASE | DECIMAL | 0 1 2 3 4 5 6 7 8 9 10 Quando representamos números desta forma, não temos números negativos. Logo, nenhum número possui sinal algum. Por isso, chamamos tais números de unsigned (sem sinal). Atualmente, a maioria das máquinas possui representa- ção numérica 32 bits. Isso significa que seus números são compostos por 32 dígitos. Com uma representação destas, o menor número binário sem sinal que podemos representar é 00000000000000000000000000000000 e o maior é 1111111111111111111111111111111. Con- vertemos tais valores para decimal, chegamos à conclu- são que a maioria dos computadores só lida com números sem sinal cujo valor esteja entre 0 e 4.294.967.295 - que são os equivalentes decimais destes números. Para descobrir qual é o equivalente decimal de um nú- mero binário de 32 bits, usa-se a fórmula abaixo: N0 ∗ 232 + N1 ∗ 231 + N2 ∗ 230 + N3 ∗ 229 + (...) + N29 ∗ 23 +N30 ∗ 22 +N31 ∗ 21 +N32 ∗ 20 ondeN0 é o dígito mais significativo eN32 é o bit menos significativo. 9.2 Números Inteiros Nem sempre os números com os quais queremos lidar são naturais. Pode haver necessidade de realizarmos ope- rações com números negativos. Para tal, devemos en- contrar uma forma de representarmos números negati- vos. Uma das primeiras formas tentadas de fazer isso foi reservando o primeiro bit de um número para represen- tar o sinal. Assim, um 0000000 (...) 001 representa +1 e um 10000 (...) 001 representaria um −1. Entretanto, tal forma de representação já foi abandonada há muito tempo. Um dos principai motivos para o abandono desta representação está no fato de sempre termos que verificar o primeiro bit para descobrir como efetuar uma soma ou subtração entre dois números. Além disso, tal represen- tação tornaria possível um "+0” e um "−0”. A forma de se representar números inteiros em compu- tadores modernos é chamada de Representação em Com- plemento de 2. Ela é feita da seguinte forma: Os 31 bits mais à esquerda representam sempre núme- ros positivos. Calculamos o que eles representam com a mesma fórmula vista acima. Entretanto, o primeiro bit representa sempre “0” se o seu valor for “0” ou "−232 se o seu valor for “1”. Assim, a fórmula para se calcular o que representa um número binário inteiro em decimal é: −N0 ∗ 232 +N1 ∗ 231 +N2 ∗ 230 +N3 ∗ 229 + (...) + N29 ∗ 23 +N30 ∗ 22 +N31 ∗ 21 +N32 ∗ 20 ondeN0 é o dígito mais significativo eN32 é o bit menos significativo. A representação em complemento de 2 é boa pelos se- guintes motivos: • Para somar dois números inteiros, usa-se o mesmo método. Não precisamos verificar o sinal deles. Com isso, podemos criar um circuito mais rápido. • Descobrir o inverso de um número também é sim- ples. Basta invertermos todos os bits e, em seguida, somarmos 1. Sempre funciona. 13 14 CAPÍTULO 9. REPRESENTAÇÃO NUMÉRICA • O “0” é sempre “0”. Não existe uma versão negativa ou positiva deste número. Por meio desta notação, números tão pequenos como −4.294.967.296 e tão grandes como 4.294.967.295 po- dem ser representados. 9.3 Números Reais Por fim, também é muito útil que computadores possam representar números reais. Vamos estudar agora como eles costumam ser representados em computadores. A forma mais lógica e versátil de representarmos um nú- mero real é por meio da notação científica. Um número decimal em notação científica sempre toma a seguinte forma: N ∗ 10M onde N é sempre um número real maior ou igual à 1 e menor que 10 que pode ser positivo ou negativo enquanto M é um número inteiro qualquer (que pode ser positivo ou negativo). Por exemplo: 3, 15756 ∗ 109 representa aproximadamente quantos se- gundos existe em um século enquanto 1, 00000∗10−9 representa quantos segundos existem em um nanossegundo. Alternativamente, podemos representar também núme- ros em notação científica utilizando uma base binária: 1, 00000 ∗ 10−1 . Lembre-se que aquele “10” significa na verdadee “2” em representação decimal. Ou seja, o número representado é na verdade 0,5 e não 0,1. Enfim, quando temos um número em notação científica binária, ele sempre tem a seguinte forma: S ∗ 1, XXXXX ∗ 10Y Y Y Y Y , onde “S” representa o sinal (que pode ser positivo ou negativo), “XXXXX” são a parte fracionária do número e “YYYYYY” representa o expoente. Então, para representarmos números reais, precisamos representar no espaço de 32 bits os valores do sinal, fra- ção e expoente. No MIPS, isso é feito da seguinte forma: S -- E E E E E E E E -- F F F F F F F F F F F F F F F F F F F F F F F O Sinal é representado em um único bit (1 para negativo e 0 para positivo), o expoente é representado por 8 bitse a fração é representada por 23 bits. Assim, o exemplo 1, 00000 ∗ 10−1 (ou 1/2 em decimal) é representado: 0 -- 1 1 1 1 1 1 1 1 -- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Com esta representação, números quase tão pequenos como −238 ou quase tão grandes como 238 podem ser armazenados. Entretanto, note que a nossa precisão não é perfeita. Exis- tem muitos números que não podem ser representados desta forma. Por isso, sempre é preciso realizar arredon- damentos. E quanto mais operações realizamos, mais er- ros acabam sendo acumulados. Por essa razão, a mai- oria dos computadores possui também uma forma mais precisa de representação de números reais. Essa forma normalmente ocupa o dobro do espaço do que costuma ocupar. No MIPS uma representação desti tipo ocupa 64 bits. Ela funciona da seguinte forma: S -- E E E E E E E E E E E -- F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F Apesar de gastarmos o dobro do espaço de armazena- mento desta forma, aumentamos consideravelmente a faixa de valores representados e a precisão com a qual podemos representá-los. 9.4 Overflow e Underflow Overflow é o nome do resultado incorreto ao qual che- gamos quando tentamos somar números grandes demais e o resultado não pode ser armazenado e nem represen- tado em 32 bits. Ele pode ocorrer quando efetuamos as seguintes operações: • Somamos dois números positivos • Somamos dois números negativos • Subtraímos um número negativo de um positivo. É de responsabilidade do hardware sempre verificar se ocorreu um overflow nestes casos. Normalmente, para fazer a verificação basta conferir os sinais dos números. Em caso afirmativo, ele deve ativar um sinal de exceção. O que é feito caso uma excessão seja detectada depende de cada programa. O MIPS, por exemplo, sempre armazena o endeereço da última instrução que gerou excessão em um registrador especial chamado EPC. A instrução mfc0 (Move from System Control) é usada para copiar este endereço para um registrador de propósito geral que pode ser conferido por algum programa. Cabe ao programador deste pro- grama decidir o que fazer. Em lingüagens de alto nível, o comportamento depende da lingüagem usada. C, por exemplo, ignora todos os Overflows. Ao contrário de Fortran ou Ada que reque- rem que o programa sempre seja avisado. Underflow é o que acontecee quando lidamos com um número real tão próximo de 0 que o valor do expoente não pode ser corretamente representado. Quando um pro- grama requer uma precisão tão grande assim, recomenda- se o uso de pontos flutuantes de dupla precisão (double) para evitar este inconveniente. Capítulo 10 As Operações da Unidade Lógica Aritmética Computadores são máquinas de calcular. Logo, é fun- damental que eles sejam capazes de realizar operações básicas como adição, subtração, divisão e multiplicação. Vamos ver agora como tais operações são implementadas dentro da Unidade Lógica Aritmética de um Processador (ULA). 10.1 A Adição e Subtração A Adição é uma das operações mais simples. Um com- putador realiza ela de uma maneira semelhante à usada por nós humanos. Ele começa somando os bits menos significativos. Caso tenha que somar “1” e “1”, o resul- tado fica sendo “0” e passamos um “vai-um” para o bit à esquerda. Veja abaixo um desenho de um circuito capaz de somar dois números de 8 bits: Embora a imagem mostre apenas um circuito que soma dois números de 8 bits, não é muito difícil perceber que a lógica para fazer um somador é a mesma, tanto para nú- meros com 8 como para 32 bits. Basta adicionar mais so- madores. Perceba que o circuito também é capaz de de- tectar a presença de Overflow no caso de operações com números sem sinal. Ele pode ser usado tanto para somar números com ou sem sinal. Graças à representação de números inteiros por complemento de dois, não é difícil conseguir isso. O mesmo circuito acima também pode ser reaproveitado para realizar subtrações. Basta inverter antes todos os bits do segundo operando e somar 1 à ele. Com isso, estamos na verdade somando o primeiro operando com o negativo 15 16 CAPÍTULO 10. AS OPERAÇÕES DA UNIDADE LÓGICA ARITMÉTICA do segundo operando. 10.2 A Multiplicação Vamos agora estudar como construir um circuito capaz de realizar multiplicações. Primeiro vamos tentar realizar umamultiplicação pelo método convencional que usamos através de papel e caneta. Isso pode nos dar uma pista de como fazer uma operação de multiplicação. Vamos usar a base binária: 1000 x1001 ---- 1000 00000 000000 1000000 ------- 1001000 Perceba que a multiplicação é um conjunto de somas. Sempre estamos somando o valor 0 ou o valor do mul- tiplicador após este passar por uma operação de SHIFT para a esquerda. O que determina se o que iremos so- mar é um 0 ou o valor do multiplicador após um SHIFT são os bits do multiplicando. Se o bit da posição n for um 0, somamos 0 e se for 1, somamos com o valor do multiplicando “shiftado” n vezes. Um exemplo de um circuito seqüencial capaz de somar dois números de 4 bits é mostrado na imagem abaixo: Note que multiplicando números de 4 bits, nós precisa- mos armazenar os 8 bits possíveis para o resultado. Afi- nal, o resultado de uma multiplicação é capaz de ter o número de bits igual à soma dos multiplicandos. Máqui- nas MIPS lidam com o problema dividindo o resultado pela metade. os bits mais significativos terminam em um registrador chamadoHi e os menos significativos acabam em um registrador chamado Lo. Entretanto, o circuito conformemostrado acima temmui- tos problemas. O principal é que ele é muito complexo. Perceba que o circuito para multiplicar número de 4 bits é pelo menos 3 vezes mais complexo e lento que o usado para realizar a adição de 8 bits (afinal, o circuito de multi- plicação precisa realizar a adição de 3 pares de valores de 8 bits). Um circuito destes para calcular a multiplicação de números com um valor ainda maior de bits seria ainda mais complexo que isso. Com isso, chegamos à conclusão que a multiplicação é uma operação complexa demais para ser efetuada por meio de uma simples lógica combinacional de portas ló- gicas. Um circuito de multiplicação combinacional seria muito caro e esquentaria demais. Por isso, sua velocidade teria que ser sacrificada aumentando a distância dos tran- sistores. Por isso, utilizam-se circuitos seqüenciais para realizar esta operação. O diagrama abaixo mostra descreve o funcionamento de um circuito seqüencial capaz de realizar a multiplicação: O que acontece no diagrama acima no caso de multipli- carmos dois números de 32 bits é o seguinte: • 1- O “Produto” é um registrador inicializado em 0. • 2- O produto e o multiplicando são passados para a ULA que soma os dois. • 3- O resultado (o valor do próprio multiplicando) pode ir para o registrador “Produto” ou não. Quem toma a decisão é o “Controle”. • 4- Se o último bit do Multiplicador for “1”, o Con- 10.2. A MULTIPLICAÇÃO 17 trole permite a escrita do registrador “Produto”. Se for “0”, ele impede. • 5- OMultiplicando sofre um shift para a esquerda e o Multiplicador um Shift para a direita. • 6- Se é a 32a vez que você chega à esta instrução, encerre. A multiplicação terminou. Caso contrário, volte ao passo 2. O diagrama acima já é uma forma bem melhor de multi- plicarmos. Mas ainda existem otimizaçãoes que podem ser feitas para acelerarmos ainda mias a multiplicação: • Podemos utilizar um único registrador de 64 bits para armazenar tanto o multiplicador como o pro- duto. O multiplicador vem antes e o produto logo depois. Assim, cada vez que fazemos um shift para a direita no multiplicador, aproveitamos o espaço li- berado mais à esquerda para colocar um novo bit do produto. Desta forma, não é necessário somar números de 32 bits, apenas somar o suficiente para descobrir qual o próximo bit do produto a ser colo- cado. • Compiladoressubstituem multiplicação por potên- cias de 2 por operações de shift que são mais rápi- das. Para multiplicações envolvendo números negativos, basta invetermos os números transformando-os em positivos. Em seeguida, fazemos a multiplicação normalmente e observamos os sinais do multiplicador e multiplicando. Se forem iguais, masntemos os números como positivos. Caso contrário, convertemos o produto para negativo. 18 CAPÍTULO 10. AS OPERAÇÕES DA UNIDADE LÓGICA ARITMÉTICA 10.3 Fontes, contribuidores e licenças de texto e imagem 10.3.1 Texto • Introdução à Arquitetura de Computadores/Capa Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_%C3%A0_ Arquitetura_de_Computadores/Capa?oldid=204857 Contribuidores: Master, Raylton P. Sousa, He7d3r.bot e Anónimo: 1 • Introdução à Arquitetura de Computadores/Introdução Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_%C3% A0_Arquitetura_de_Computadores/Introdu%C3%A7%C3%A3o?oldid=276833 Contribuidores: Master, Thiagoharry, Raylton P. Sousa, He7d3r.bot e Anónimo: 5 • Introdução à Arquitetura de Computadores/Modelo de Von Neumann Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3% A3o_%C3%A0_Arquitetura_de_Computadores/Modelo_de_Von_Neumann?oldid=288328 Contribuidores: Lazarochaves • Introdução à Arquitetura de Computadores/O que é o MIPS? Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_ %C3%A0_Arquitetura_de_Computadores/O_que_%C3%A9_o_MIPS%3F?oldid=199789 Contribuidores: Master, Thiagoharry, Raylton P. Sousa, He7d3r.bot, GrooveDog e Anónimo: 2 • Introdução à Arquitetura de Computadores/Instruções do MIPS Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_ %C3%A0_Arquitetura_de_Computadores/Instru%C3%A7%C3%B5es_do_MIPS?oldid=275828 Contribuidores: Master, Thiagoharry, Raylton P. Sousa, He7d3r.bot, Kernelsafe, Syum90 e Anónimo: 5 • Introdução à Arquitetura de Computadores/Representação das Instruções Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7% C3%A3o_%C3%A0_Arquitetura_de_Computadores/Representa%C3%A7%C3%A3o_das_Instru%C3%A7%C3%B5es?oldid=199791 Contribuidores: Master, Thiagoharry, Raylton P. Sousa e He7d3r.bot • Introdução à Arquitetura de Computadores/As Pseudo-Instruções Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_ %C3%A0_Arquitetura_de_Computadores/As_Pseudo-Instru%C3%A7%C3%B5es?oldid=281434 Contribuidores: Master, Thiagoharry, Mike.lifeguard, Raylton P. Sousa, He7d3r.bot e Anónimo: 2 • Introdução à Arquitetura de Computadores/Suporte à Funções Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7%C3%A3o_ %C3%A0_Arquitetura_de_Computadores/Suporte_%C3%A0_Fun%C3%A7%C3%B5es?oldid=288544 Contribuidores: Master, Thia- goharry, Raylton P. Sousa, He7d3r.bot e Anónimo: 3 • Introdução à Arquitetura de Computadores/Representação Numérica Fonte: http://pt.wikibooks.org/wiki/Introdu%C3%A7% C3%A3o_%C3%A0_Arquitetura_de_Computadores/Representa%C3%A7%C3%A3o_Num%C3%A9rica?oldid=199790 Contribuido- res: Master, Thiagoharry, Raylton P. Sousa, He7d3r.bot e Anónimo: 2 • Introdução à Arquitetura de Computadores/As Operações da Unidade Lógica Aritmética Fonte: http://pt.wikibooks.org/wiki/ Introdu%C3%A7%C3%A3o_%C3%A0_Arquitetura_de_Computadores/As_Opera%C3%A7%C3%B5es_da_Unidade_L%C3% B3gica_Aritm%C3%A9tica?oldid=199785 Contribuidores: Master, Thiagoharry, Raylton P. Sousa e He7d3r.bot 10.3.2 Imagens • Ficheiro:ALU_Block_Diagram.png Fonte: http://upload.wikimedia.org/wikipedia/commons/c/c7/ALU_Block_Diagram.png Licença: GFDL Contribuidores: Own work created with Xilinx ISE 9.2i Artista original: Tapani Taivalantti • Ficheiro:Circuito_multiplicacao.png Fonte: http://upload.wikimedia.org/wikibooks/pt/d/da/Circuito_multiplicacao.png Licença: ? Contribuidores: ? Artista original: ? • Ficheiro:Circuito_soma.png Fonte: http://upload.wikimedia.org/wikibooks/pt/0/00/Circuito_soma.png Licença: ? Contribuidores: ? Artista original: ? • Ficheiro:Cray-1-deutsches-museum.jpg Fonte: http://upload.wikimedia.org/wikipedia/commons/f/f7/Cray-1-deutsches-museum.jpg Licença: CC BY 2.5 Contribuidores: Obra do próprio Artista original: Clemens PFEIFFER • Ficheiro:Diagrama_circuito_multiplicacao.png Fonte: http://upload.wikimedia.org/wikibooks/pt/a/a0/Diagrama_circuito_ multiplicacao.png Licença: ? Contribuidores: ? Artista original: ? • Ficheiro:Logic-gate-index.png Fonte: http://upload.wikimedia.org/wikipedia/commons/9/9f/Logic-gate-index.png Licença: CC-BY- SA-3.0 Contribuidores: ? Artista original: ? • Ficheiro:Toshiba_TC86R4400MC-200_9636YJA_top.jpg Fonte: http://upload.wikimedia.org/wikipedia/commons/6/6e/Toshiba_ TC86R4400MC-200_9636YJA_top.jpg Licença: CC-BY-SA-3.0 Contribuidores: ? Artista original: ? • Ficheiro:Transistor_npn.png Fonte: http://upload.wikimedia.org/wikipedia/commons/2/22/Transistor_npn.png Licença: CC-BY-SA- 3.0 Contribuidores: Transferido de fr.wikipedia para o Commons. Artista original: Este ficheiro foi inicialmente carregado por Pulsar em Wikipédia em francês • Ficheiro:_Kernel_Layout.svg Fonte: http://upload.wikimedia.org/wikipedia/commons/8/8f/Kernel_Layout.svg Licença: CC BY-SA 3.0 Contribuidores: Obra do próprio Artista original: Bobbo 10.3.3 Licença • Creative Commons Attribution-Share Alike 3.0 Capa Introdução O Que é Arquitetura de Computadores Computadores e as Várias Camadas de Abstração Modelo de Von Neumann O que é o MIPS? O Processador MIPS A Filosofia do Projeto do MIPS Instruções do MIPS Instruções Aritméticas Simples Instruções de Operadores Lógicos Instruções de Uso de memória Instruções de Controle de Fluxo Instruções de Comparações Resumo dos Modos de Endereçamento Representação das Instruções As Instruções Tipo R As Instruções Tipo I As Instruções Tipo J As Pseudo-Instruções A Pseudo-Instrução move A Pseudo-Instrução Load Address Suporte à Funções As Etapas Necessárias para Invocar Funções Instruções de Uso de Funções: jal e jr Funções com Muitas Variáveis Funções Recursivas e Sub-Funções Representação Numérica Números Naturais Números Inteiros Números Reais Overflow e Underflow As Operações da Unidade Lógica Aritmética A Adição e Subtração A Multiplicação Fontes, contribuidores e licenças de texto e imagem Texto Imagens Licença
Compartilhar