O documento fornece uma introdução informal sobre arquiteturas de computadores. Ele discute o que é um computador e suas principais características de processamento, memória e comunicação. Também aborda as diferentes etapas de execução de um programa, desde a linguagem de programação até a linguagem de máquina, e como a abstração permite que programas sejam executados em diferentes plataformas de hardware e software.
Criando aplicativos multimídia com director 7 tambein engloba versoes 5, 6...
Arquiteturas de Computadores - slides
1. Arquiteturas
de
Computadore
s informal
Uma abordagem
1
2. O que é um computador?
Computadores são ferramentas
Servem para resolver problemas
2
3. Qualquer sistema computacional possui 3
características em geral
Processamento
Memória (armazenamento)
Comunicação
Um celular, por exemplo, é um sistema
computacional que possui como principal
característica a comunicação
3
4. Curiosidades
No Brasil, segundo o censo de 2010, há 190
milhões de habitantes
Segundo o Portal Teleco, site de informações
sobre telecomunicações, dados de julho de 2011
mostram que há 220 milhões de celulares no país
Pois é, há mais celulares do que pessoas no
Brasil. O mercado para profissionais de computação
é imenso!
4
5. Uma ferramenta deve possuir objetividade
(realizar sem restrições a tarefa para a qual ela foi
criada)
Além disso, há 3 aspectos importantes que
definem sua qualidade:
Desempenho (tempo de processamento)
Custo-benefício
Facilidade de uso
5
6. Você pode optar por uma memória de 2 GB a
R$ 500,00 ou por uma de 4 GB a R$ 600,00. Qual é
a melhor opção?
2 GB 4 GB
6
7. A resposta é: depende
Se a sua aplicação não necessitar de mais de 2 GB
de memória, você estará gastando R$ 100,00 a mais
que o necessário
Isto faz parte da questão do custo-benefício
No caso de carros e TVs, produtos novos e
melhores são lançados a preços mais caros que os
anteriores
Já produtos da indústria computacional tem
preços iguais ou menores que os anteriores, e
ainda assim são geralmente melhores (mais ágeis)
7
8. Ok, mas chega de filosofar...
Vamos à matéria de
Arquiteturas de Computadores! 8
9. Como funciona um computador?
Algoritmos implementados por um programa
escrito em uma sequências
linguagem de de instruções
programação
Programadores se comunicam com computadores
através de uma linguagem de programação
9
10. Para haver comunicação, é necessário que haja
uma linguagem em comum...
...ou um tradutor
10
11. Linguagens em geral...
Mais Mais
complexa chinês português, simples
inglês etc (computador
(usuário entende) entende)
É necessária uma espécie de tradução das
linguagens comuns para a linguagem binária, que é
o que o computador “entende” de fato
Veremos a seguir que, na verdade, tradução é
apenas parte do processo
11
12. A nível de software, Ling. de Prog.
T
N5 R
temos: Alto Nível
A
Compilação D
U
Ç
Lê o código e, usando Montagem N4
Ã
as informações nele O
contidas, manipula a
memória. Montador
Sistema N3
Operacional
Interpretação
Parcial
Macroprogramação N2
Interpretação
12
13. A nível de hardware, Interpretação
temos:
Microprogramação N1
Aqui, há um número muito maior de
instruções do que havia no início.
Com isso, mais circuitos devem ser Só agora são executadas
criados, aumentando o custo. as instruções
Portanto, linguagem simples é
necessária.
Circuitos Digitais N0
13
14. Tradução X Interpretação
O esquema das etapas de execução de um
programa apresentado anteriormente não é uma
generalização
Isto porque existem linguagens compiladas
(utilizam tradução) e outras, interpretadas
A tradução é feita uma vez apenas. Já a
interpretação é realizada cada vez que o programa
é executado
14
16. Mas afinal, para que tantas etapas na
execução de um programa?
O esquema abaixo mostra um dos problemas
que ocorreriam caso as instruções das
linguagens em alto nível fossem executadas
sem todas essas etapas
m C Pascal Cobol C++
.....
n Pentium
4
I7 Xeon AMD .....
16
17. Note que, para cada linguagem diferente, seria
necessária uma maneira diferente de fazer suas
instruções serem executadas. Isso para cada
processador
Para cada nova linguagem ou novo processador,
já haveria uma nova necessidade para que o
programa fosse executado
No total, teríamos m*n
necessidades diferentes!
17
18. Todas aquelas etapas servem então para que,
utilizando o conceito de divisão e conquista, os
processadores não precisem “se preocupar”
com linguagens, e vice-versa
As instruções complexas são reduzidas a
instruções em uma linguagem simples,
entendida por todos os processadores
m C Pascal Cobol C++ .....
n Pentium
4
I7 Xeon AMD .....
18
19. Agora, são apenas m+n maneiras
diferentes de execução de programas
Intuitivamente, temos um custo maior por ter
tantas etapas... mas não é bem assim. Dos níveis
N5 até N3, o custo muitas vezes nem chega ao
usuário, pois o software é compilado antes de
chegar até ele
É importante ressaltar que uma instrução em L2
não pode nunca ser diretamente executada no
nível N0.
Depois de N2, não ocorre mais tradução, apenas
interpretação
19
20. Na interpretação, as instruções são apenas
convertidas nas ordens em que serão executadas,
o que acontece de N1 para N0 no esquema
apresentado anteriormente
Relembrando:
Macroprogramação
L2
Interpretação
Microprogramação
L1
Execução
Circuitos digitais
Instruções
A seguir, uma melhor representação das etapas
de um programa até que ele esteja em L2
20
21. _____________ L5
_____________
_____________
_____________
Compilação
_______ _______ _______
....... + _______
_______
+ _______
_______
+ _______
_______
+ ....... L4
Montagem
010010101101
001010101010 L3 -> L2 + L1
O programa em L3 tem
101011100110
também os endereços de
...
memória envolvidos no
processo
101101010101 L2
010100101101
... 21
22. Curiosidades
Em Delphi, é possível manipular o programa no
nível de montagem. Com isso, pode-se ter uma
noção maior de quanto tempo levará sua execução
Atualmente, no caso de dispositivos móveis, por
exemplo, programa-se em alto nível e depois acessa-
se o programa em nível de montagem, para que
sejam reprogramadas apenas as partes “ruins”
22
23. Com o conceito de linguagens (L1, L2, L3 etc)
apresentado, temos também o conceito de
máquinas virtuais. Por exemplo:
Macroprogramação
Máquina
L2 virtual L3
Microprogramação Máquina virtual L2
L1
Máquina física
Circuitos digitais
Instruções
23
24. Generalizando para o topo, temos:
Linguagem de programação
de alto nível
L5
Compilação
.
.
.
.
.
.
. Máquina
. virtual à vista
. do usuário
. 24
25. Abstração
Considere o seguinte esquema:
C Pascal Java
Compilador B Compilador C
Compilador D
Compilador A
Windows Linux
Política de compatibilidade
da Intel: todas as instruções
Processador Processador
1 2 entendidas por um Pentium
4 são entendidas também
pelo I7 (mais avançado)
25
26. Vimos anteriormente que os compiladores A, B, C
e D não são necessariamente diferentes, assim
como os processadores
Porém, com processadores que não sejam da
Intel, é possível que sejam necessários diferentes
compiladores para cada situação
A linguagem Java, teoricamente, não possui
restrições de plataforma
Veremos a seguir que ela utiliza
uma espécie de disfarce...
26
27. Através da abstração, a JVM (Java Virtual Machine)
“esconde” as complexidades que envolvem as
plataformas
______________
Java ______________
______________
_________________
_________________
_________________
_________________
Java ByteCode
JVM
Máquina Virtual Java
27
29. Mas, complexidade de...? Funcionalidade
Cabe ao arquiteto do sistema saber onde cada
função deve ser implementada
Adição e multiplicação são sempre feitas em
hardware, pois o desempenho é muito melhor.
Mas então, por que não implementar tudo em
hardware?
Custo é a resposta. Operações mais sofisticadas,
se implementadas todas em hardware,
aumentariam demais o custo (circuitos demais)
29
30. Não são poucos os circuitos necessários para
implementar operações de soma e multiplicação
em hardware. Agora imagine implementar um
programa complexo inteiro usando apenas esses
circuitos digitais!
Por outro lado, imagine também o gasto de
tempo desnecessário que haveria se,
para cada vez que precisássemos
somar ou multiplicar, fosse neces-
sário traduzir as instruções em
software para hardware!
30
31. Outra desvantagem de hardware é: se ocorrer
algum problema físico com as peças, como
reparar?
Softwares são mais baratos e, caso haja algum
erro, é muito mais fácil localizar e consertá-lo.
Porém, como já foi citado, o desempenho é
menor.
31
32. Computadores:
Visão geral
Placa
mãe
endereços C
A C
Memória dados C A
RAM Processador /
H C
leitura / escrita CPU
E H
E
Hard Disk (HD) Central Processing
Unit
Disquete / Blu-ray
Rede Wi-Fi Graphics Processing
USB Unit
GPU
.
32
Fonte
33. Vamos começar falando superficialmente sobre o
processador
Sua função é executar programas armazenados na
memória principal, buscando instruções, identificando e
executando as mesmas uma após a outra
Unidade de controle (UC):
É responsável pela busca das instruções na memória
principal e pelas suas identificações
Unidade Lógica Aritmética (ULA):
É responsável pela realização de operações como adição,
AND booleano, entre outras, necessárias para a execução
das instruções
Registradores:
Juntos, formam uma pequena memória de alta velocidade,
que armazena resultados temporários e certas informações
de controle. Cada registrador possui uma determinada
função. Os dois mais importantes são o contador de
programa, PC (responsável por apontar a próxima instrução
a ser executada), e o registrador de instruções, IR
(responsável por armazenar a instrução que será executada)
33
34. O processador executa as instruções através de
uma pequena sequência de passos conhecida
como o ciclo busca-decodifica-executa
Este ciclo é o centro da operação de todos os
computadores
Veremos mais tarde por que o ciclo é tão
determinante na execução das instruções de um
programa
34
35. A memória é a parte do computador onde
programas e dados são armazenados
Sem ela, os processadores não poderiam escrever
informações, então não existiria nenhuma maneira
de um computador armazenar um programa e
dificilmente poderia executar algum
Em um computador, geralmente existe memória
primária e memória secundária
35
36. Memórias primárias:
memórias que o processador pode endereçar
diretamente
elas geralmente fornecem uma ponte para as
memórias secundárias, mas sua função principal é
conter a informação necessária para o processador
num determinado momento – por exemplo, dados
dos programas em execução
Exemplo: a memória principal, sobre a qual
falaremos mais detalhadamente ao analisar o Modelo
de Von Neumann
36
37. Memórias secundárias:
não podem ser endereçadas diretamente; a
informação precisa ser carregada em memória
primária antes de poder ser tratada pelo processador
não são fundamentais para a parte operacional do
computador. Computadores feitos exclusivamente
para efetuar cálculos matemáticos complexos, por
exemplo, não precisam tanto desse tipo de memória
são geralmente não-voláteis, permitindo guardar os
dados permanentemente
Exemplos: HD, CDs e DVDs
37
38. RAM x CACHE
Memória RAM: É a memória principal da máquina,
onde todos os processos necessários para a inicialização
e execução de programas
armazenados em uma memória
secundária são carregados
Memória Cache: É uma
memória com maior veloci-
dade de acesso para o pro-
cessador que a RAM. É localizada embutida no
processador justamente para aumentar a velocidade de
acesso. Entretanto, seus dados são temporários
38
39. Pode-se dizer que o “mundo” do computador se
resume a (esquema do Modelo de Von Neumann):
Busca
Memória Processador
Sequência de bits
0 ou 1
.
. BUSCA próxima instrução L2
. IDENTIFICA (decodifica e entende)
. EXECUTA cada instrução L1
.
39
40. Curiosidades
1 byte equivale a 8 bits
1 kilobyte (KB) equivale a 1.000 bytes, 1 megabyte
(MB) equivale a 1.000.000 bytes, 1 gigabyte (GB)
equivale a 1.000.000.000 bytes, e assim por diante...
...ou não?
40
41. Curiosidades
A memória é contada em potência de 2. Quando
dizemos “1 GB de memória RAM”, estamos usando a
sigla incorreta para gibibytes (GiB)
Portanto, 1 GB coloquialmente representa 1 GiB,
que equivale a 2³: bytes (1.073.741.824 bytes);
quase 7,4% mais do que 1.000.000.000 bytes
Mas você provavelmente
já sabia disso
41
42. A seguir, será descrita mais detalhadamente a
arquitetura interna de um processador
Mas antes, vamos resolver uma espécie de
enigma, apresentado em uma aula de
Arquiteturas de Computadores, pelo professor
Vinod processador
memória
endereços . . .
dados
. . .
controle (r/w)
. . .
42
43. Dado o esquema do slide anterior, deseja-se
que os dados lidos da memória passem por
todos os nove pontos do processador,
utilizando o mínimo possível de fios
Os fios são todos retos, ou seja, a solução
para o problema será o mínimo de linhas retas
que passem por todos os pontos
. . .
Uma configuração
óbvia seria: . . .
. . .
43
44. Com essa solução, temos 5 retas
Será que 5 é realmente o número mínimo de
retas?
Pense mais um pouco e clique para ver a
resposta...
. . . Começando de uma forma diferente
Seguindo por mais 2 pontos...
. . . Podemos usar apenas mais 2 retas!
Por que não fazer isso...
...para depois fazer isso?
. . . E finalmente isso. 4 retas!
44
45. Curiosidades
Por que esta última solução não é tão óbvia
quanto a primeira, se não havia nenhuma restrição
de que as retas não podiam ultrapassar a caixa?
Não estamos acostumados a pensar além do que
temos de concreto. Em países como os EUA, por
exemplo, os alunos são estimulados desde o
primário a “pensar fora da caixa”
Não é à toa que a maioria das descobertas e
invenções vem de países desenvolvidos
Então, lembre-se: “Think outside the box” 45
46. Processadores e
Microprogramação
Vamos agora analisar mais a fundo o Modelo
de Von Neumann
Vamos definir conceitos como registradores,
barramentos, Unidade Lógica Aritmética (ULA),
entre outros
Em seguida, construiremos nosso processador
utilizando todas as componentes apresentadas
46
47. Registradores
Locais onde são armazenadas informações
A diferença dos registradores para as células da
memória principal é que os primeiros estão
localizados dentro do processador. Isso faz com que
informações contidas nos registradores sejam
buscadas bem mais rapidamente para processamento
Representação*:
Registrador
*ATENÇÃO: tanto esta como as outras representações feitas aqui não fazem
parte de nenhum tipo de convenção – são meras ilustrações!
47
48. Barramentos
Conjuntos de fios por onde passam bits de dados
ou de controle
Em outras palavras, artifícios utilizados para
transmitir sinais de um dispositivo para outro
Representação:
ou
n
Onde n é o número de fios
do barramento, lembrando
que por cada fio passa um
bit por vez 48
49. Multiplexadores (MUX)
Circuitos que recebem entradas, selecionam uma
delas através de sinais de controle e as liberam
como saída
Representação:
MUX
49
50. Unidade Lógica Aritmética (ULA)
Dispositivo que recebe dois dados de entrada A e
B, opera-os sobre uma função pré-determinada e
libera um dado de saída
Recebe bits de controle que especificam a
operação a ser realizada
A ULA poderá fazer 4 operações em nossa
abordagem, portanto são necessários 2 bits de
controle (00, 01, 10 e 11 = 4 possibilidades)
Por ora, a única operação relevante é a soma (00)
Representação:
A B
ULA 50
51. Deslocador
Dispositivo que recebe um número binário e
multiplica ou divide por 2, se desejado for, através
do deslocamento à direita ou à esquerda
Deslocar à direita significa “apagar” o bit mais à
direita e adicionar um 0 à esquerda, e o
procedimento é exatamente o oposto no
deslocamento à esquerda
Exemplo: 0010 (=2)
Deslocando à direita (divisão): 0001 (=1)
Deslocando à esquerda (multiplicação): 0100 (=4)
Representação:
DES
51
52. Vamos falar mais detalhadamente sobre
registradores
Sabemos que registradores contém dados que
tanto podem ser lidos quanto sobrescritos
Por isso, cada registrador precisa receber um
bit que controla sua entrada, que chamaremos
de HE, e outro que controla sua saída, HS
Registradores possuem na sua estrutura
interna um circuito flip-flop para cada bit que
armazena, cada um deles conectado a um fio
tanto do barramento de entrada como do
barramento de saída
52
53. Abaixo, esquematizada a estrutura interna de
um registrador de 8 bits:
E
N
T
R
HE (habilita A
D
entrada) A
S
A
HS (habilita Í
saída) D
A
Tri-state buffer 53
54. Tri-state buffers são circuitos que evitam
conflitos entre as saídas para o barramento,
fazendo um tipo de “desconexão virtual” entre
registradores e barramentos
Esses conflitos seriam possíveis porque várias
saídas de registradores estarão conectadas a um
mesmo barramento
Nossa arquitetura terá 16 registradores para
armazenar dados, dentre os quais alguns tem
funções especiais: PC (Program Counter), IR
(Instruction Register) e AC (Accumulator)
54
55. O Program Counter contém o endereço da
próxima instrução a ser buscada na memória
principal
O Instruction Register armazena a instrução
buscada na memória. Ou seja, IR = MP[pc],
sendo IR o conteúdo do registrador e pc um
endereço da memória principal MP
Accumulator é um registrador que armazena
valores intermediários, que não seriam úteis ao
final da operação
Haverá em nossa arquitetura, além dos 16,
outros registradores espalhados no processador:
dois latches, A e B, o Memory Adress Register
(MAR) e o Memory Buffer Register (MBR) 55
56. Os latches servem para “segurar” dados no
barramento e evitar que sejam sobrescritos
Precisamos sempre lembrar que os fios do
barramento apenas conduzem eletricidade, que
já é instável por si mesma
Latches serão importantes então para captar
dados do barramento que estão prontos para
serem processados, isto é, estão estáveis
É como tirar uma foto: é
necessário esperar até que
todos estejam parados
56
57. O MAR é ligado ao barramento de endereços,
que controla exclusivamente o fluxo de
endereços que o processador envia para serem
consultados na memória
O MBR é ligado ao barramento de dados do
sistema, e guarda os dados buscados na
memória que serão processados na CPU ou os
dados resultantes de algum processamento e
que serão escritos na memória, ou até mesmo
processados novamente
57
58. Podemos agora começar a “montar” o nosso
processador
Já foi dito que, para começar, vamos pensar
apenas em somar dados. Para isso, precisamos
simplesmente ler dois deles e somá-los
Dois registradores e uma ULA são necessários
Escolheremos então,
PC
IR dentre nossos 16
AC
R1 registradores, um
R2 registrador R1 e outro R2
. ULA
. para ler e somar seus
.
. dados 58
59. Intuitivamente, ligamos tudo através de
barramentos
Vamos guardar o resultado da soma no
registrador R3
PC
IR
AC
Barramento B
R1
R2 Barramento A
R3
.
.
ULA
.
Barramento C
59
60. Ainda não é o caso, mas se quiséssemos
multiplicar ou dividir um número por 2,
precisaríamos adicionar um deslocador
Posicionando os 2 dispositivos separadamente,
teríamos a vantagem de fazer operações
simultâneas. Colocando ambos juntos, podemos
usá-los consecutivamente, isto é, multiplicar ou
dividir direto o resultado de uma soma, sem
precisar armazená-lo antes
60
61. Mesmo que ainda não seja necessário, vamos
adiantar um deslocador para a nossa máquina,
colocando o mesmo logo após a ULA:
PC
IR
AC
Barramento B
R1
R2 Barramento A
R3
.
.
ULA
.
DES
Barramento C 61
62. Agora, precisamos pensar fisicamente
Imagine se nossa soma fosse R1 ← R1 + R2, isto
é, o registrador R1 receberia o resultado da soma
de seu valor atual com o valor de R2
Enquanto a ULA processa os primeiros bits de
cada dado, o barramento de saída está sendo
modificado e, portanto, os novos valores já estão
sendo salvos em R1, o que poderia causar um
erro na soma
Uma das soluções para esse impasse é adicionar
latches antes da ULA, que guardarão os valores
originais de R1 e R2 enquanto são processados62
63. PC
IR
AC
Barramento B
R1
R2 Barramento A
R3
LA LB
.
.
.
ULA
DES
Barramento C
63
64. Ok, mas temos que pensar também na interação
processador-memória
É preciso adicionar, então, MAR e MBR. O MAR
controla apenas informações (endereços) que
vão do processador para a memória, mas o MBR
controla o fluxo de dados de toda a interação,
incluindo os dados de saída do deslocador, dados
de entrada para a ULA e dados que serão lidos ou
escritos na memória
MAR MBR
64
65. Em nossa arquitetura, o MAR poderá ser
carregado a partir do latch B
É interessante possibilitar o processamento de
dados direto do MBR para a ULA, poupando
assim o tempo de selecionar o registrador (entre
16 deles!) desejado para armazenar o resultado
da operação, e depois selecionar o mesmo
novamente para buscar os bits e processá-los
65
66. Porém, repare que o MBR estará conectado à
ULA, junto com o latch A. Há um conflito visível
nessa configuração
Latch A
MBR
ULA
Lembre-se de que a ULA é apenas um circuito
combinatório. Os bits de controle que recebe são
apenas para especificar a operação a ser feita, o
que significa que está sempre recebendo dados 66
67. PC
IR
AC
Barramento B
R1
R2 Barramento A
R3
LA LB
.
Barramento C .
.
MAR Sem pânico!
ULA
MBR
DES
A solução é simples!
67
68. Basta adicionar um multiplexador, que chamaremos de AMUX
(multiplexador A):
PC
IR
AC
Barramento B
R1
R2 Barramento A
R3
Barramento C
LA LB
.
.
. AMUX
MAR
ULA
MBR
DES
68
69. O multiplexador controlará qual dos dados deve
ser enviado para a ULA
Mas e se a instrução a ser executada fosse
R1 ← R1 + R2 + R3 + R4 ?
Intuitivamente, a solução seria uma ULA com 4
entradas, com a vantagem de resolver essa soma
sem precisar guardar nenhum resultado
intermediário
A B C D
ULA
69
70. Sendo assim, uma ULA com 4 entradas é mais
vantajosa para os casos de soma com 4 parcelas.
O problema é que isto não será econômico se essa
soma não ocorrer com frequência
E pensando bem, de fato ela não é tão comum
quanto uma soma com apenas 2 operandos, para
a qual basta uma ULA com 2 entradas
Unindo o útil ao agradável, por que não pensar
em uma solução alternativa para realizar esta
soma, ainda sem precisar salvar valores
intermediários?
70
71. Eis a solução:
A B C D
ULA 1 ULA 2
E F
ULA 3
A B C D
ULA 4
71
72. Curiosidades
Fabricar 3 ULA’s com 2 entradas é ainda mais
econômico do que projetar uma única ULA com 4
Além disso, outra vantagem em reduzir o tamanho
das ULA’s pode ser explicada fazendo uma analogia
com a forma como são fabricados os próprios
processadores
72
73. Curiosidades
Processadores são obtidos através de fatias
redondas de silício, que podem ser divididas em
partes pequenas ou nem tanto:
73
74. Curiosidades
Podemos pensar em cada um desses pedaços
como uma componente do processador
As fatias, porém, sempre tem impurezas
Imagine, por exemplo, a fatia abaixo, onde as
manchas vermelhas são suas impurezas
74
75. Curiosidades
Cada parte atingida por uma impureza está
inutilizada
Pensando nas partes como componentes, aquelas
que foram atingidas não irão funcionar
Na partição em componentes menores, repare
que bem mais delas saíram ilesas
O que restou:
75
76. Recapitulando, temos então um processador
que realiza a soma que queríamos
Fora do Dentro do
Processador Processador
(memória)
PC
IR
AC
Barramento B
R1
Barramento A
R2
R3
Barramento C . LA LB
.
. AMUX
MAR
ULA
MBR
DES
76
77. É importante ressaltar que as linhas que ilustram
os barramentos estão sendo mostradas apenas
nos caminhos que queríamos para a soma
Na verdade, todos os registradores estão
conectados aos barramentos A, B e C, e uma
estrutura de controle é que determina de onde
são lidos os dados e onde eles são gravados
Falando em controle, já vimos que não são só os
registradores que precisam de bits de controle
para que o processador possa funcionar
A seguir, vamos quantificar os bits de controle
de todas as componentes e descrever para que
eles servem em cada uma delas 77
78. Temos 16 registradores para leitura e escrita
A intenção é ler sempre 2 dados (um vai para o
barramento A e o outro para o barramento B),
realizar uma operação na ULA e/ou no deslocador
e, quando necessário, armazenar o resultado em
outro registrador
Isso faz com que precisemos de 16 bits de
controle para cada uma dessas operações.
Entenderemos o motivo logo a seguir
78
79. A posição do registrador-alvo seria dada pela
posição do bit 1 em meio aos 16 bits de controle
Por exemplo, na operação de leitura cujo controle
é: 0000000000001000 seria lido o dado do
0000000000001000
quarto registrador
0 PC
0 IR
0 AC
1 R1
0 R2
0 R3
.
.
.
0 R13
79
80. Mas não é por mágica que a informação do
registrador é lida quando ele recebe o bit 1
Na estrutura interna dos registradores, vimos que
eles recebem um bit HE para habilitar sua entrada
e outro, HS, para habilitar sua saída
No exemplo anterior, a operação a ser feita era de
leitura. Então, é a saída do registrador que precisa
ser habilitada, para que a informação seja jogada
em um dos dois barramentos (A ou B)
Bits de controle especificam qual dos dois
barramentos será o destino dos dados, mas isso
por ora não tem importância
80
81. Caso a operação fosse de escrita no registrador, o
bit que iria para cada registrador corresponderia
ao HE, e aquele que recebesse 1 seria sobrescrito
Mas, e se quisermos simplesmente gravar o
resultado no MBR, e não gravar em nenhum
registrador?
Para isso, precisamos de um 17º
bit de controle (EnC, Enable C),
ao barramento C, que impeça
escrita em qualquer um dos 16
registradores caso isso não seja
desejado 81
82. Os outros registradores (latches A e B, MAR e
MBR) recebem, separadamente, também 2 bits de
controle (HE e HS), exceto pelo MBR que recebe 4
Os outros 2 bits do MBR são comandos de leitura
e escrita na memória (chamaremos RD, leitura, e
WR, escrita)
Nossa ULA recebe 2 bits de controle para as 4
operações que pode executar a partir de dados de
entrada A e B: 00 para A + B, 01 para a operação
lógica A AND B, 10 para simplesmente retornar A,
e 11 para retornar o inverso de A
82
83. O deslocador também precisa receber 2 bits de
controle (00 para não deslocar, 01 para deslocar à
esquerda, 10 para deslocar à direita e 11 nada faz)
Finalmente, o multiplexador recebe apenas um
bit para controlar qual dos dois dados que ele
recebe deve seguir (0 para seguir o valor de latch
A e 1 para seguir o valor que veio de MBR)
Na ordem, temos então 16 + 16 + 17 + 2 + 2 +2 +
4 + 2 + 2 + 1 = 64
À primeira vista, precisamos apenas de um
registrador especial para controle, de 64 bits, com
um bit para cada sinal
Mas serão todos esses 64 bits realmente
necessários? 83
84. A verdade é que muito
desses bits podem ser
dispensados
Fazendo uma análise mais cuidadosa dos
controles de cada componente, veremos por que
muitos desses sinais são desnecessários
Mas, antes disso, vamos introduzir uma nova
componente que será necessária para nos
livrarmos de alguns bits
84
85. Decodificador
Dispositivo que, para a nossa abordagem,
receberá um número binário de 4 bits e, com ele,
liberará 16 bits onde o bit na posição i será 1 e os
outros, 0
OBS: i é o valor na base 10 do binário original.
Note que i está entre 0 e 15
Exemplo: se o decodificador recebe o binário
0011 (=3), a saída será 00000000000010003 2 1 0
Representação:
DEC
85
86. Afinal, qual a grande utilidade do decodificador?
Pense: se com apenas 4 bits, podemos
representar até o número 15, então é possível
especificar em 4 bits qual o registrador a ser
selecionado
Adicionando decodificadores para A, B e C,
passamos a conta de 16 + 16 + 17 bits
para 4 + 4 + 5, já que o bit EnC
permanece
Pois é, já economizamos 36 bits
de controle
86
87. Os latches A e B são registradores que não precisam
de controle na saída. Precisam apenas controlar os
dados que entram, que vão sobrescrever as
informações que eles guardavam até então
A saída dos latches pode ficar sempre liberada, já que
a função deles é simplesmente salvar valores e não
deixar que outras informações de um barramento
passem por cima deles
HE
HS 87
88. Para a nossa abordagem, o MAR também precisa
de controle apenas na entrada, para controlar os
endereços que nele entram e que serão então
enviados para a memória automaticamente
O mesmo serve para o MBR. Apenas um bit de
controle é necessário, que é enviado para a saída
do MBR, controlando se a informação nele contida
irá ou não para a memória
As operações de leitura e escrita na memória
continuam sendo comandadas pelos bits RD e WR
descritos anteriormente
88
89. Ótimo, precisávamos de um registrador de 64 bits
para controle, e agora conseguimos reduzir este
tamanho para 24
Superficialmente, o que nós temos até então é:
Memória Processador
principal
endereços MAR
Controle
(24 bits)
dados
MBR
controle
(leit/esc)
N1
N2 N0
89
90. Podemos imaginar N0 como um pobre estagiário,
que trabalha e executa ordens
O controle, N1, seria o chefe, quem dá as ordens,
através da busca das instruções e dos recursos
presentes na memória principal
Aos poucos, iremos desvendar
o que está por trás da nuvem
no slide anterior
90
91. A
E nosso proces- 16 4
4
Controle
B
sador ficou assim: 16
4
bits
C
17
0
1
1
Barramento B 2
Barramento A 1
3
16 4
registradores
1 .
Barramento C
LA LB
.
1
.
AMUX
1
.
.
2 .
MAR .
.
ULA .
1
MBR .
23
2
DES
2
91
RD/WR
92. Vamos dessa vez utilizar como exemplo a instrução
R1 ← R1 + R2, para ilustrar como ficam os bits de
controle durante o processo
A B C EnC AMUX ULA RD WR MAR MBR DES LA LB
92
93. Chamaremos o momento inicial de t₀
Os registradores R1 e R2 ficam nas posições 3 e 4,
respectivamente, lembrando que o primeiro
registrador, PC, fica na posição 0. O valor em R1
será jogado no barramento A, e o valor de R2 no
barramento B; logo, A = 0011 e B = 0100
O resultado será armazenado em R1, então o
controle do barramento C deve também ser 0011
93
94. Obviamente, no início do processo ainda não
podemos gravar nada no destino, então EnC tem
de estar “desativado”
Neste momento, não há problemas em
especificar qual dos 2 dados (vindos do MBR ou
do latch A) o AMUX irá direcionar para a ULA.
Sabemos que serão dados vindos de latch A, então
o bit de controle para AMUX será 0
Já vimos que a combinação do controle para que
a ULA opere uma soma é 00
94
95. Nada está sendo lido ou escrito na memória (RD =
0 e WR = 0)
MAR não receberá nenhum endereço de
memória
MBR também não está realizando nenhuma
atividade em t₀
Também já vimos que a combinação que faz com
que o deslocador retorne a própria entrada é 00
As entradas dos latches A e B devem estar
desabilitadas, pois as informações ainda não
foram transferidas para os barramentos A e B
95
96. Temos então, no momento t₀:
A B C EnC AMUX ULA RD WR MAR MBR DES LA LB
t₀ 0011 0100 0011 0 0 00 0 0 0 000 00 0 0
96
97. Após um tempo para busca dos dados, tь, os
únicos controles que se modificam são aqueles
dos latches
Isso porque, agora que os dados já foram jogados
aos barramentos, os latches precisam recebê-los,
quando estáveis, para que sejam transferidos à
ULA
Vamos considerar t₁ = t₀ + tь
97
98. Temos então, no momento t₁ :
A B C EnC AMUX ULA RD WR MAR MBR DES LA LB
t₀ 0011 0100 0011 0 0 00 0 0 0 000 00 0 0
t₁ 0011 0100 0011 0 0 00 0 0 0 000 00 1 1
98
99. Após um tempo de execução, tє, os latches
precisam voltar a ser 0, para que nada presente
nos barramentos A e B sobrescreva os dados
armazenados nos latches, já que não sabemos se
eles virão a ser ainda necessários para a ULA
futuramente
Além disso, se queremos gravar o resultado de
volta em R1, EnC precisa agora passar a ser 1
O resto permanece inalterado
Agora consideremos t₂ = t₀ + tь + tє
99
100. Temos então, no momento t₂ :
A B C EnC AMUX ULA RD WR MAR MBR DES LA LB
t₀ 0011 0100 0011 0 0 00 0 0 0 000 00 0 0
t₁ 0011 0100 0011 0 0 00 0 0 0 000 00 1 1
t₂ 0011 0100 0011 1 0 00 0 0 0 000 00 0 0
100
101. Mas então, é necessário ler toda a sequência de
bits de controle 3 vezes para uma simples
operação de soma?
Vimos pela tabela que pouca coisa se altera
durante o tempo que decorre desde a leitura dos
dados nos registradores até o armazenamento do
resultado em um deles
Então, deve haver uma maneira mais
inteligente e menos custosa de
executar instruções. Afinal,
tempo é sempre precioso
101
102. Relógio (clock)
Este é outro dispositivo importante, que emite
uma sequência de pulsos periódicos que
controlam alguns circuitos da máquina
Se os pulsos são periódicos, quer dizer que
possuem uma determinada frequência
O período de cada pulsação define o ciclo da
máquina
A máquina realiza um conjunto de atividades
durante um ciclo
Representação:
Ciclo
Marcador de 102
frequência
103. Agora, podemos conservar todos os bits que se
mantiveram inalterados na tabela, deixando por
conta do relógio as alterações necessárias
Por exemplo, sabemos que o bit EnC está
diretamente relacionado ao bit HE dos
registradores
Os pulsos enviados pelo clock definem então o
momento exato em que a entrada do registrador
deve ser habilitada, caso se deseje armazenar o
resultado de algum cálculo em um registrador
Isto pode ser feito através de um circuito bastante
simples: CK
HE
EnC
103
104. Com isso, já temos tudo de que precisamos para
começar a ver o que está por dentro da nuvem
que havia em N1
Em outras palavras, vamos agora entender como
funciona toda a máquina de controle do
processador e como ela executa o microprograma
Microprogramas são sequências de instruções
(em binário, evidentemente) que controlam o
funcionamento de cada componente em N0
Cada instrução de um microprograma é
executada em um ciclo
104
105. O processamento de uma microinstrução se
resume a:
Busca da instrução
Identificação da instrução
“Execução”, entre aspas porque engloba na verdade:
Busca dos operandos
Operação
Armazenamento do resultado
Temos então 5 atividades que são realizadas pelo
processador durante um ciclo
105
106. Dentre as 5 atividades listadas, o tempo
necessário para a segunda (identificação de uma
instrução) será quase nulo na nossa abordagem
Isto porque teremos na nossa arquitetura de
controle (N1) um registrador especial chamado
MIR (MicroInstruction Register), para onde cada
microinstrução será carregada
O MIR já “entende” o significado dos bits de uma
instrução de acordo com a posição de cada um
MIR
106
107. Visto isso, o relógio que utilizaremos poderá ser
dividido em 4 subciclos:
Atraso
Atraso
Atraso
1 ciclo
1 subciclo
O relógio terá 4 saídas, das quais 3 possuem
atrasos. Isso faz com que sejam gerados pulsos em
momentos diferentes para cada saída
Cada uma dessas saídas consiste em um subciclo,
como vemos na representação acima 107
108. Teremos também em N1 uma memória, chamada
memória de controle, onde são armazenadas e de
onde serão lidas as microinstruções
Nossa memória de controle poderá armazenar, no
máximo, 256 instruções, cada uma com 32 bits
Se é no MIR onde cada instrução será carregada,
concluímos que a largura do MIR será de 32 bits
Memória de Controle
Carrega instrução
MIR
108
109. Toda memória precisa estar ligada a um MAR e
um MBR, e com a memória de controle não é
diferente
Portanto, vamos adicionar um registrador MAR,
que chamaremos de MPC (MicroProgram
Counter), cuja função é encontrar a próxima
instrução do microprograma a ir para o MIR
Recebe endereço da próxima instrução
MPC
Envia endereço da próxima instrução
Memória de Controle
MIR 109
110. O MBR da memória de controle
já está em N1...
...é o próprio MIR!
Mas precisamos voltar a falar do MPC. De onde
ele recebe a próxima microinstrução?
Podemos supor que as instruções são executadas
sequencialmente. Neste caso, basta incrementar o
endereço atual, e teremos o endereço da próxima
Precisamos então de uma componente simples,
mas que ainda não tínhamos visto
110
111. Incrementador
Circuito relativamente simples de poucas portas
lógicas que, como o nome já diz, recebe um
número binário como entrada e retorna o seu
sucessor
O número binário de entrada, no incrementador
que usaremos no nosso exemplo, será composto
por 8 bits
Representação:
INC
111
112. Temos até agora:
INC MPC
Memória de Controle
MIR
Visivelmente, temos um problema
MPC precisa ser controlado para
não ficar o tempo todo selecio-
nando endereços na memória! 112
113. Vamos inserir agora o relógio, que será uma
componente fundamental para todo o
processador, tanto em N0 quanto em N1
Por enquanto, não falaremos da atuação do
relógio em N0, e já podemos ligá-lo a duas das
componentes de N1 que temos até agora:
I
1 N MPC
C
2
Atraso Memória de
Controle
3
Atraso
Atraso
4 MIR
113
114. Fazendo isso, permitimos que uma instrução seja
carregada da memória para o MIR apenas no
início do ciclo (subciclo 1), que é quando a
instrução começará a ser processada
Além disso, permitimos que a próxima instrução
seja selecionada na memória pelo MPC apenas ao
final de um ciclo (subciclo 4), para que seja
recebida pelo MIR no início do ciclo seguinte
Note que o MIR estará desabilitado e não irá
mudar durante os subciclos 2, 3 e 4. O mesmo vale
para o MPC durante os subciclos 1, 2 e 3
114
115. Nosso nível N1 está quase concluído, mas
precisamos estudar o interior do MIR antes de
continuar
Você certamente achou estranho quando
dissemos que o MIR entende a função de cada bit
de uma instrução apenas pela posição. Observe:
MIR
A U D M M E
M R W
U L E B A n C B A
D R
X A S R R C
115
116. No MIR, os bits da instrução que ele recebe se
encaixam em cada uma das partes da figura
Cada divisão do MIR serve para especificar o destino
em N0 de cada bit. Por exemplo: o bit mais à esquerda
será o controle de AMUX; do bloco DES saem os dois
bits de controle para o deslocador; e assim por diante
Não são mais necessários bits de controle para os
latches. Já que eles possuem um momento certo para
serem ativados e este é o mesmo em todos os ciclos,
podemos deixar os latches por conta do relógio
Para continuar a montagem do interpretador de
microinstruções, precisamos primeiramente do que
está por trás de 116
117. Alguns slides atrás, fizemos uma suposição de que as
instruções do microprograma seriam processadas
sequencialmente. Porém, nem sempre isso acontece
É comum que ocorram desvios de endereços durante
o processamento, e por isso precisamos reservar bits
em uma instrução que especifiquem o endereço da
próxima, para quando for necessário que esse desvio
ocorra
Já podemos substituir por ADDR, conjunto de bits
que representam cada endereço da memória de
controle
Se nossa memória de controle armazena até 256
instruções (= 2⁸), ADDR deve ser composto por 8 bits
para poder representar todos os endereços
117
118. I
1 N MPC
C
2
Atraso Memória de
Controle
3
Atraso
A
4 . . . . D
D
Atraso R
Ops, o problema do conflito de novo
Ainda se lembra da solução?
118
119. MMUX
I
1 N MPC
C
2
Atraso Memória de
Controle
3
Atraso
A
4 . . . . D
D
Atraso R
Basta adicionar um multiplexador
Chamaremos este de MMUX
119
120. É bastante comum que esses desvios de
endereços sejam condicionais
Por exemplo, voltar ao primeiro endereço da
memória de controle se uma condição X for
satisfeita. Senão, selecionar o endereço seguinte
Isto nos leva a revelar o que há por trás de no
nosso MIR: um par de bits, o qual chamaremos de
COND, que determina se ocorrerá desvio ou se o
endereço da próxima instrução será simplesmente
o endereço atual + 1
Se você entendeu isso, então você pode concluir
que COND será o controle de MMUX. Ou pelo
menos parte dele, como veremos mais adiante 120
121. Lógica de microssequenciamento
Diferente de todos os circuitos que apresentamos
até aqui, este foi projetado para uma única situação,
bem específica
Ele recebe da ULA informações sobre o resultado de
uma operação: um sinal N que diz se foi negativo e
um sinal Z que diz se foi igual a 0
Recebe também o par de bits COND do MIR
Enfim, sabendo se o resultado da operação foi
positivo, nulo ou negativo e sabendo a condição de
desvio da microinstrução atual, podemos indicar se o
endereço da próxima microinstrução será
simplesmente o atual + 1 ou algum outro
121
122. Lógica de microssequenciamento
Talvez seja uma explicação confusa. Podemos clareá-
la com um exemplo prático:
x = 5;
if (x > 0)
return x;
Por que o trecho de programa acima é válido?
Temos todas as informações necessárias para decidir
se x será ou não retornado: sabemos qual a condição
para retornar x, e sabemos se x satisfaz a condição
(se x é 5, então x é maior que 0)
A saída será o bit de controle para o nosso MMUX
Representação:
LMS
122
123. Temos enfim: MUX
I
1 N MPC
C
2
Atraso Memória de
Controle
3
Atraso
A C A
U
Atraso
4
M
U
X
O
N
D
L
A . . . . . D
D
R
LMS
N1
N0
ULA
Z N
123
124. Agora, convencionando os significados dos bits
COND:
00 = não desviar; a próxima instrução estará no endereço
seguinte na sequência de instruções
01 = desviar para o endereço em ADDR se N = 1, isto é, se
o resultado da operação realizada pela ULA for negativo
10 = desviar para o endereço em ADDR se Z = 1, isto é, se o
resultado for 0
11 = desviar independente do resultado da ULA
O sinal de controle de MMUX é resultado de
R.N + L.Z + L.R (L é o bit à esquerda, e R é o bit à
direita no par COND)
Relembrando: ‘+’ é o operador lógico OR e ‘ . ’ é AND
124
125. Nosso processador completo, incluindo N0 e N1, fica assim:
Figura retirada e adaptada do livro Organização Estruturada de 125
Computadores, de Andrew S. Tanenbaum (p. 140)
126. Para concluir, falta apenas falar sobre as ligações do
relógio com as componentes de N0, que ainda não
havíamos visto
Para isto, vamos supor um microprograma qualquer
que interpreta a soma de x + y, que foi executada com
x recebendo o valor 3 e y recebendo o valor 5
Para simplificar o exemplo, escolheremos o ciclo em
que a soma será efetuada. Isto significa que as
constantes 3 e 5 já foram buscadas na memória e
armazenadas nos registradores (suponhamos R1 e
R2), e está pré-determinado que o resultado será
armazenado em R3
Assim, a microinstrução deste ciclo será r3 := r1 + r2
(o símbolo “:=“ denota atribuição)
126
127. Para conseguir passar esta microinstrução para
sua forma real (binária), vamos relembrar as
divisões do MIR:
Depois, vamos analisar quais os bits de controle
necessários para cada um desses campos e, dessa
forma, teremos nossa instrução em bits
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
127
128. Sabemos que ambos os operandos virão dos
latches, já que não buscamos nada do MBR. Para
que AMUX direcione à ULA a informação contida
no latch A, o controle deve ser 0
Não há desvios nesta instrução, então COND = 00
A operação é de soma. Esta operação é realizada
pela ULA quando o controle é igual a 00
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
0 00 00
128
129. Nada será feito além da soma, então o controle
do deslocador precisa ser 00 para que sua saída
seja igual à entrada
Nada sairá de MBR para a memória ou vice-versa
O campo MAR também será 0 já que não enviará
nenhum endereço para a memória principal
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
0 00 00 00 0 0
129
130. Nada será lido da memória neste ciclo (RD = 0)...
...nem escrito (WR = 0)
O bit EnC deve ser 1 porque neste ciclo haverá
armazenamento de um valor (o resultado da soma
está sendo atribuído a R3 na microinstrução).
Evidentemente, o relógio irá ditar o momento
certo do armazenamento
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
0 00 00 00 0 0 0 0 1
130
131. PC 0
Lembra-se dos nossos registradores? IR 1
AC 2
Começando da posição 0, R1, que .
R1 3
.
R2 4
contém o primeiro operando, está na .
R3 5
.
posição 3. Logo, A = 0011 (3 na base 2) .
R2, que contém o segundo operando, .
.
está na posição 4. Logo, B = 0100
Enfim, R3, destino do resultado, está na posição
5. Logo, C = 0101
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
0 00 00 00 0 0 0 0 1 0101 0100 0011
131
132. Agora só nos resta o campo ADDR. Nossa
microinstrução contém uma simples soma, sem
desvio de endereços. Então, podemos atribuir
qualquer valor para ADDR, já que ele será
ignorado. Sendo assim, vamos optar por todos os
bits sendo 0
Enfim, nossa microinstrução na forma binária é:
00000000000101010100001100000000
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
0 00 00 00 0 0 0 0 1 0101 0100 0011 00000000
132
133. Agora, podemos começar a processar a instrução
No subciclo 1, o relógio ativa apenas o MIR,
porque estamos ainda na etapa da busca da
instrução
Vimos que a instrução é automaticamente
identificada no MIR e não leva praticamente
tempo algum. Consideramos então que a
identificação também ocorre no subciclo 1
Memória de Controle
0 00 00 00 0 0 0 0 1 0101 0100 0011 00000000
.
.
.
.
.
MIR
133
134. No subciclo 2, os bits dos campos A e B do MIR
serão enviados aos decodificadores, para habilitar
as saídas dos registradores R1 e R2
Com isso, os valores 3 e 5 são jogados aos
barramentos A e B, respectivamente
Neste subciclo, o relógio ativa os latches, para
que possam receber esses valores
Retomaremos a figura do livro Organização
Estruturada de Computadores para mostrar o
caminho dos dados durante este subciclo
134
136. O subciclo 3 é o intervalo em que ULA e
deslocador irão operar sobre os dados recebidos
Aqui seria também o momento certo para que o
MAR fosse carregado, se fosse necessário. Mas a
microinstrução deste ciclo não envolve essa
necessidade, e por isso tivemos o bit 0 na parte do
MIR destinada ao MAR
5+3 00 (soma)
8
--- 00 (saída = entrada)
136
8
137. E finalmente, é no subciclo 4 em que ocorre o
armazenamento do resultado em um dos nossos 16
registradores, quando a instrução assim determina
Nossa microinstrução r3 := r1 + r2 atribui o resultado
da soma a R3, o que significa que temos, sim, que
armazenar dados em um dos 16 durante este ciclo
O valor 8, neste instante, está no barramento C
Já vimos que EnC é 1 durante todo o ciclo, pois é um
dos sinais de controle fornecidos pelo MIR. Cabe ao
relógio habilitar a entrada de R3 no momento certo,
que é o subciclo 4 para qualquer microinstrução
Agora que 8 está em R3, podemos começar um novo
ciclo com uma nova microinstrução, caso ela exista
137
138. Podemos dividir o nosso MIR em 2 conceitos:
A
A C U D M M E
M O R W D
U N L E B A n C B A
D R D
X D A S R R C
R
OPCODE Operandos
(determina a operação da microinstrução)
ADDR é formado por 8 bits, e A, B e C por mais 4
cada. Ou seja, 20 bits compõem os operandos
Os outros 12 do MIR compõem então o código da
operação. Isto quer dizer que temos 2¹² (= 4096)
possíveis instruções diferentes
138
139. Porém, queremos economizar
novamente. Será que é possível?
Com uma análise mais cuidadosa,
veremos que podemos reduzir de
4096 para 2048 possibilidades
Para iniciar nossa “eco-
nomia”, precisamos ter
em mente que alguns
pares de bits do MIR não
admitem todas as 4
combinações (00, 01, 10
e 11) 139
140. Mais especificamente, o par de bits RD e WR não
admite a combinação 11, já que é impossível que
aconteçam simultaneamente operações de leitura
e escrita na memória
Vamos raciocinar: tínhamos 2¹² possibilidades
0 ou 1
2 2 2 2 2 2 2 2 2 2 2 2
= 2x2x2x2x2x2x2x2x2x2x2x2 = 2¹²
Quantas possibilidades teríamos se o par RD/WR
apenas admitisse a combinação 11, isto é, se RD
fosse sempre 1 e WR fosse sempre 1?
2 2 2 2 2 2 2 2 2 1 1 2
= 2x2x2x2x2x2x2x2x2x1x1x2 = 2¹⁰
140
141. Daí, temos que o nosso total de possibilidades
agora é 2¹² - 2;:, isto é, 4096 - 1024 = 3072
Podemos usar um raciocínio análogo para o
deslocador, que nunca receberá a combinação 11
Teremos 3072 - 1024 = 2048 microinstruções
Assim, já reduzimos as possibilidades de
instruções pela metade. Poderíamos levar em
conta outras restrições, mas chega de ser pão
duro e vamos voltar ao que interessa
141
142. Pilhas
Você já deve saber que uma pilha
é uma estrutura de dados que
consiste em um amontoado de valo-
res (empilhados, daí o nome)
Pilhas serão importantes na execução
de programas. Veremos a seguir como
elas são utilizadas
142
143. Toda pilha possui duas operações básicas: PUSH, que
consiste em adicionar um valor
na pilha; e POP, que retira da pilha o
valor presente no topo
Para a nossa arquitetura, pilhas serão
blocos contíguos presentes na memó-
ria principal que conterão dados a serem
processados, com um ponteiro SP (Stack Pointer) que
indicará o endereço onde está o topo da pilha
À medida que descemos pela memória, os endereços
aumentam. Ou seja, sempre que adicionarmos um
valor na pilha (PUSH), o ponteiro SP apontará para o
endereço atual – 1, um endereço acima
O contrário acontece para a operação POP 143
144. A pilha do exemplo a seguir começa no endereço
1000 da memória, e seu topo está em 996
.
.
.
.
.
.
996 9
997 4
7
SP
998
999 2
1000 5
.
.
.
.
.
144
145. Fazendo PUSH 3, o valor 3 será acrescentado na
pilha, e o topo será o endereço 996 – 1 = 995
.
.
.
.
.
.
995 3
996 9
997 4
7
SP
998
999 2
1000 5
.
.
.
.
.
145
146. Por outro lado, se tivéssemos feito POP, sairia o valor 9
que está no topo da pilha e o novo topo estaria em 996
+ 1 = 997
.
.
.
.
.
.
996 9
997 4
7
SP
998
999 2
1000 5
.
.
.
.
.
146
147. Algumas linguagens de programação são
organizadas em blocos (escopos)
Em Java, por exemplo, o escopo de uma classe
são todos os procedimentos existentes naquela
classe, e no escopo de cada procedimento existem
todas as operações realizadas por ele, inclusive
eventuais chamadas a outros procedimentos
147
148. Para essas linguagens, é interessante utilizar
pilhas durante a execução de um programa para
liberar o espaço ocupado pelas variáveis locais de
um procedimento, quando ele é finalizado
Variáveis locais são variáveis utilizadas e
conhecidas exclusivamente nos procedimentos
onde foram inicializadas, e no nível de
macroprogramação são geralmente carregadas
nas pilhas
Já as variáveis globais são variáveis conhecidas
em todo o programa e a princípio estão presentes
em endereços da memória que não fazem parte
da pilha de um procedimento em particular 148
149. Além das operações PUSH e POP, outra operação
útil para pilhas é mover arbitrariamente o
ponteiro SP, sem inserir dados inicialmente
Isto é útil para quando a execução entrar em um
procedimento que utilizará variáveis locais, de
maneira que SP será decrementado (topo subirá)
para reservar espaço para essas variáveis
Em Pascal, isso fica fácil de ser visto, já que as
variáveis locais são inicializadas antes da palavra
begin, que indica o começo do procedimento
O exemplo a seguir mostra o começo do método
de ordenação BubbleSort, em Pascal
149
150. procedure BubbleSort(var A: ArrayType);
var i, j: integer;
begin
.
.
.
Repare que as variáveis i e j são inicializadas. Em
seguida, a palavra begin indica o começo das
operações do procedimento – é neste ponto onde
SP é decrementado em 2
A pilha agora ocupa mais 2 espaços: os espaços
de i e j, que eventualmente receberão valores
durante a execução do procedimento
E se o topo da pilha atingir endereços que já
estão sendo usados pelo programa? 150
151. Familiar?
Agora vamos supor uma função, também em
Pascal, que recebe duas entradas e retorna como
resultado o produto entre elas
Perceba como fica sua pilha de execução
151
152. function produto(a, b: integer): integer;
var p, j: integer;
begin
if (a = 0) or (b = 0) then
produto := 0
else
begin
p := 0;
for j := 1 to a do
p := p + b;
produto := p;
end
end;
j Ao final desta linha, precisamosvariáveis
Quando a função termina, os espaços das de 2
p locais são liberados. Em outras palavras, SP é um
espaços para as variáveis a e b, mais
SP end. ret. Já aopara o endereço de retorno, de
incrementado em 2, voltando a ser o endereço de
espaço final desta linha, a execução estava
precisamos de
retorno. Este endereço dirá onde
mais 2que a as variáveis locais p e j
b
modo paraafunção saberáepara onde a
quando chamou função produto, ela continuará
a 152
partir daquele ponto terminar
retornar quando
153. Com apenas estas descrições, fica a
impressão de que a função foi inútil,
já que a pilha guardou apenas seus
valores de entrada e manipulou as variáveis locais
Mas é óbvio que isto não é verdade. De que
maneira então foram usadas as variáveis
a e b para chegar até o resultado final,
e onde ele foi parar?
Todos os resultados de operações intermediárias
foram sendo armazenados no nosso registrador
AC (Accumulator). O mesmo vale para o resultado
final da função, que pode ser apenas um valor
intermediário para o resto do programa 153
154. O endereço de retorno está relacionado a outro
registrador, o Program Counter
Quando a função produto termina, o endereço de
retorno é desempilhado e salvo em PC
Caso você não se lembre, AC e PC são dois dos
nossos 16 registradores conectados aos
barramentos A, B e C em N0
Isso nos dá bagagem suficiente para falar sobre o
nível de macroprogramação
154
155. Macroprogramação
Vimos que existem milhares de possibilidades de
microinstruções diferentes
Surge a necessidade de haver instruções em um
nível mais alto, para consequentemente reduzir o
conjunto de instruções de forma significativa
Veremos no slide seguinte uma tabela, mais uma
vez do livro Organização Estruturada de
Computadores, com todas as macroinstruções da
nossa máquina e suas descrições
Repare como diminuímos de mais de 2 mil para
menos de 25 instruções 155
157. Antes de entender melhor a tabela, é importante
ressaltar que seus bits não devem nunca ser
confundidos com os bits das microinstruções! Até
porque microinstruções são formadas por 32 bits,
enquanto as macro possuem 16 apenas
Dito isto, perceba que da 1ª até a 15ª instrução,
nunca se repete uma combinação para os 4
primeiros bits. Isto quer dizer que é possível
identificar instruções que não comecem por 1111
apenas pelos 4 primeiros bits
Porém, quando a instrução começa por 1111, é
necessário analisar os bits seguintes
157
158. Diferentemente das microinstruções, que tinham
um número fixo para OPCODE e outro para os
operandos, a parte de OPCODE varia nas macro
A instrução LODD, por exemplo, possui 4 bits de
operação, 0000, enquanto todos os outros
representam seu operando. Já as instruções que
começam por 1111 precisam de mais bits OPCODE
para que possam ser diferenciadas entre si
158
159. Para ilustrar como é feita a identificação das
macroinstruções, precisamos primeiro tornar
aqueles nossos 16 registradores um pouco mais
complexos
Além de PC, IR e AC, precisamos de mais
registradores com funções especiais para que seja
possível implementar um microprograma que
interprete nossas macroinstruções corretamente
Mais uma vez, trabalharemos em cima de uma
figura do livro Organizações Estruturadas de
Computadores, que mostra os registradores
adequadamente nomeados
159
160. O registrador SP armazena o endereço do
topo da pilha
TIR armazena uma cópia temporária da
macroinstrução que está sendo executada, ou
seja, uma cópia de IR. É usado para
decodificar o OPCODE
Os 3 registradores que seguem contém as
constantes 0, +1 e -1
AMASK contém a chamada máscara de
endereços e é usado para separar bits
OPCODE dos bits de endereço, através da
operação AND do seu conteúdo com a
macroinstrução da qual se quer separar os
bits
SMASK é útil nas instruções INSP e DESP, que
contém 8 bits de operandos, pois a operação
AND de seu conteúdo com a macroinstrução
isolará esses 8 bits
Os demais registradores permanecem sem
160
funções específicas
161. É preciso convencionar os nomes de algumas
operações feitas em microinstruções
Para as operações da ULA, utilizaremos a + b para
soma, band(a, b) para AND, a para retornar a própria
entrada e inv(a) para retornar o inverso do primeiro
operando
Para operações do deslocador: lshift(a) desloca a
entrada 1 bit para a esquerda, e rshift(a) faz o oposto
Desvios condicionais serão representados por if b
then goto addr, que significa: se o bit b for 1, vá para
o endereço addr
No nosso microprograma, b será N ou Z, os dois bits
da ULA que indicam se o resultado foi menor que 0
ou igual a 0, respectivamente 161
162. Veja a seguir quais valores cada conjunto de bits
assume no MIR para os seguintes exemplos de
microinstruções, em uma nova tabela do livro:
Dito tudo isso, podemos ver um microprograma
que interpreta macroinstruções 162
164. O microprograma começa com um loop principal,
que só termina quando acabar o macroprograma, isto
é, quando não mais houver macroinstruções a serem
interpretadas
Na linha 0, o MAR recebe o conteúdo de PC, que é o
endereço da macroinstrução a ser interpretada.
Também nesta linha, RD é ativado, para que a
macroinstrução desejada comece a ser lida na
memória a partir do endereço do MAR
Na linha 1, o microprograma aproveita para
incrementar o conteúdo de PC, já que isso alguma
hora teria que acontecer. Se isto não fosse feito, a
linha 1 seria desperdiçada, porque a macroinstrução
ainda não chegou até o MBR. Pelo mesmo motivo, RD
continua ativado, pois ainda estamos lendo a
macroinstrução na memória 164
165. Na linha 2, a macroinstrução em MBR é salva em
IR. Aqui ainda há tempo para testar o primeiro bit
da instrução, da esquerda para a direita: se este
não for 0, já sabemos que a macroinstrução não é
nenhuma das 8 primeiras da nossa tabela, então
podemos ir para a linha 28 e testar o segundo bit
165
166. Tanto na linha 28 quanto na linha 3, repare que o
teste do desvio condicional é exatamente o
mesmo: tir := lshift(ir + ir);
Não é uma percepção trivial à primeira vista, mas
o que acontece nesse teste é o deslocamento de
dois bits à esquerda do conteúdo de IR
Recordando, deslocar um bit à esquerda em um
número binário é o mesmo que multiplicar o seu
valor por 2. Fazer ir + ir é equivalente a fazer 2 * ir,
ou seja, deslocar um bit à esquerda de ir. Fazer
lshift(2 * ir) então é o mesmo que deslocar 2 bits
Porém, lembre-se de que os testes são feitos
sempre em função dos bits N e Z liberados pela
ULA 166
167. Vamos voltar a focar nas primeiras linhas do
microprograma. Na linha 3 (tir := lshift(ir + ir); if n
then goto 19;), a interpretação irá para a linha 19
caso o bit N da saída da ULA seja 1
Isto quer dizer que o teste é feito em cima da
instrução vinda de IR deslocada um bit à
esquerda, pois o segundo deslocamento à
esquerda (feito por lshift) é feito somente no
deslocador, e não mais na ULA
Caso N tenha sido 0, passamos à linha 4
(tir := lshift(tir); if n then goto 11;). Aqui, o
registrador TIR receberá seu próprio conteúdo
deslocado em um bit à esquerda 167
168. Só que este deslocamento é novamente feito por
lshift, e opera em cima do próprio conteúdo de TIR.
Isso significa que a ULA receberá tir como um dos
operandos e retornará ele mesmo – lembrando que
tir já é o conteúdo de IR deslocado 2 bits à esquerda,
por causa do que aconteceu na linha 3
Então, se na linha 3 testamos o segundo bit da
instrução, na linha 4 testa-se o terceiro, e só depois
desse teste o conteúdo de tir é novamente deslocado
(lshift(tir))
Na linha 5 (alu := tir; if n then goto 9;), alu é uma
pseudovariável que representa que o conteúdo de TIR
apenas passará pela ULA para que seja testado seu
primeiro bit (4º da instrução original) 168
169. Na linha 5, se o bit testado for 1, significa que o
OPCODE da instrução é 0001, e STOD é a única
macroinstrução cujo início é 0001. Por isso
desviamos para a linha 9, linha onde STOD é
executada em microinstruções
Se o bit testado for 0, o OPCODE é 0000, então
basta prosseguir para a linha seguinte, que é onde
LODD é executada
Esse processo teste-desvio-execução é a base do
microprograma que interpreta macroinstruções
Acompanhe a seguir um trecho, bastante simples,
de um programa qualquer
169
170. se (i ≤ j) faça // ‘i’ e ‘j’ são variáveis quaisquer
m = a[i*2] // ‘a’ é um vetor e ‘m’ uma variável
// qualquer
fim se
Vamos expressar este algoritmo em nível de
macroprogramação, e depois em microinstruções,
para enfim nos despedirmos
da nossa máquina-exemplo
170
171. Serão realizadas 4 operações nesse algoritmo: Macroprograma
i ≤ j?
i*2 LODD j
buscar valor em a[i * 2] SUBD i
m := a[i * 2] JNEG saida
Testar se i ≤ j é o mesmo que testar se i - j ≤ 0
Atenção: ‘i’ e ‘j’ são variáveis globais
Com a instrução LODD passando j (entenda as
variáveis passadas no macroprograma como o
endereço onde essas variáveis estão, e não seus
respectivos valores), armazenamos no
registrador AC o valor contido no endereço saida (continuação
passado do programa)
.
Precisamos agora subtrair do valor de i. Com a .
.
instrução SUBD, o resultado já será armazenado .
em AC
Hora de implementar o desvio condicional:
caso o conteúdo de AC seja negativo (j > i),
desviamos para o final do ‘se’ do algoritmo. Para
isso, criaremos um label “saida” 171