Introdução à Organização de Computadores e - IC

Propaganda
Introdução à Organização de Computadores
e Linguagens de Montagem
Ricardo Anido
© Draft date 10 de Março de 2011
Capítulo 2
Organização de básica de
computadores e linguagens de
montagem
Agora que já sabemos um pouco sobre codificação da informação na memória, vamos examinar o funcionamento básico de um computador. A Figura
2.1 mostra o esquema simplificado de um computador típico, ilustrando a interligação entre três componentes: memória, processador e um bloco representando dispositivos de entrada e saída, tais como monitor de vídeo, teclado,
impressora, discos, etc.
Interligando os três componentes vemos os barramentos. Um barramento é simplesmente um conjunto de fios, cada um dos quais a cada momento
pode ou não ter corrente elétrica fluindo. A presença ou ausência de corrente
elétrica são usadas para distinguir entre dois estados, de forma que a cada
momento um barramento carrega informação que pode ser interpretada da
mesma forma que uma informação na memória. Os barramentos são usados
para transferir informações entre dois componentes. No momento da transferência, o componente que possui a informação coloca as tensões adequadas
nos fios do barramento, e o componente destino faz a leitura das tensões nos
fios e desta forma adquire a informação.
Note que na Figura 2.1 são usados três barramentos: um de dados, um
de endereço e um de controle. Note também que os barramentos de dados
e controle são desenhados com setas nas duas extremidades, indicando que
5
6
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Barramento de dados
Processador
Barramento de controle
Memória
Barramento de endereço
Entrada
e
Saída
Figura 2.1: Esquema simplificado de um computador
os dados podem trafegar nas duas direções, enquanto que no barramento de
endereços a informação trafega em uma única direção. O barramento de endereços contém tantos fios (bits) quantos forem necessários para endereçar
todas as palavras da memória. O número de fios (bits) do barramento de
dados é igual ao tamanho de cada palavra na memória. Assim, para comunicação com uma memória organizada como 2 MB palavras de 32 bits (total
de 8 MB), o processador deve dispor de um barramento de dados com 32 fios
(largura da palavra), e um barramento de endereço com pelo menos 21 fios
(para endereçar 2 MB palavras).
A comunicação entre o processador e a memória é feita da seguinte maneira. Quando o processador necessita de um dado na memória, ele especifica
pelo barramento de endereços qual o endereço de memória da palavra que
contém o dado. Feito isto, o processador especifica pelo barramento de controle que a operação é de leitura em memória (note que isto pode ser realizado
com apenas um fio do barramento). A memória coloca então o valor da palavra
especificada no barramento de dados, que é finalmente lido pelo processador.
A operação de escrita na memória é similar. O processador coloca no
barramento de endereços o endereço da palavra que deve ser modificada, e no
barramento de dados o valor a ser escrito. O processador indica pelo barra-
2.1. FUNCIONAMENTO DO PROCESSADOR
7
mento de controle que a operação é de escrita, e a operação é executada pela
memória.
2.1 Funcionamento do processador
Vamos examinar mais detalhadamente o funcionamento do computador através da introdução de um processador didático, o Faíska. A Figura 2.2 mostra
alguns dos componentes internos do Faíska.
Processador
B. de dados
r0
ip
r1
ir
B. de controle
r2
op1 op2
ALU
r15
B. de endereço
result
Figura 2.2: Esquema simplificado do processador Faíska.
Os componentes mostrados no interior do processador (r0, r1, r2, . . .,
r15, ip e ir) são chamados registradores. Um registrador é basicamente
uma palavra de memória interna ao processador. A diferença é que acesso
a um registrador é muito mais rápido que o acesso a qualquer palavra de
memória externa ao processador. O Faíska possui vários registradores. Os
registradores r0 a r15 são de propósito geral, e podem ser usados para manipular dados do usuário, armazenar valores intermediários, etc. Todos os
registradores do Faíska são de 32 bits. Na Figura 2.2 são mostrados ainda
dois registradores especiais. O registrador de instruções ir (em inglês, instruction register) armazena o código da instrução que está sendo executada,
enquanto que o registrador apontador de instruções ip (em inglês, instruction
pointer) contém o endereço da próxima instrução a ser executada. O usuário
não tem acesso direto aos registradores especiais ip e ir; eles são mostrados
nas figuras para facilitar o entendimento do funcionamento do processador.
O processador conta ainda com uma Unidade Aritmética e Lógica (ALU,
do nome em inglês), capaz de realizar, como o nome indica, operações aritméticas (por exemplo adição) e lógicas (por exemplo ou-exclusivo). Os operandos
8
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
das instruções aritméticas e lógicas podem ser registradores ou uma palavra
de memória.
O processador funciona em passos – cada instrução é composta por um
número variável de passos, dependendo da complexidade da instrução. Os
passos básicos de uma instrução são:
• busca de instrução na memória,
• busca de operando na memória,
• execução e
• armazenamento do resultado na memória.
No passo busca de instrução na memória o processador executa uma operação de leitura à memória, no endereço indicado pelo valor corrente do registrador ip, para ler o código da instrução que deve ser executada. O valor do
registrador ip é incrementado para apontar para a próxima palavra na memória. A palavra lida é colocada no registrador ir, e os próximos três passos,
que podem ou não ocorrer, dependem da instrução lida. No passo busca de
operando na memória, se necessário para a instrução, mais um acesso à memória é realizado, para buscar um operando para a instrução. No passo execução o processador utiliza a sua unidade de processamento lógico e aritmético
para realizar a operação especificada (por exemplo, adição ou subtração). E
finalmente, no passo armazenamento do resultado na memória, se necessário
para a instrução, é feito um acesso de escrita à memória para armazenar o
resultado da instrução.
Vamos ilustrar o funcionamento do processador através da execução de
uma instrução típica. Suponha que o código 11000102h represente a instrução “adicione o valor do registrador r1 ao valor do registrador r2 e coloque o
resultado em r1”, e que em um dado momento a memória e os registradores
contenham valores mostrados abaixo:
2.1. FUNCIONAMENTO DO PROCESSADOR
9
Processador
Memória
r1
80 00 11 11
r2
80 00 00 ab
ip
00 00 02 00
208h
02 00 03 00
204h
11 00 01 02
200h
Os passos da execução dessa instrução são:
1. Busca de instrução na memória: o processador lê a palavra de memória apontada por ip (endereço 0200h) e coloca o valor lido (11000102h)
em ir (não mostrado na figura). O registrador ip é avançado para a
próxima palavra: ip passa a valer 0204h.
2. Busca de operandos na memória: nada a fazer no caso desta instrução.
3. Execução: o processador executa a instrução correspondente ao código
11000102h: o processador aciona a Unidade Aritmética e Lógica tendo
como entrada os valores dos registradores r1 e r2 e efetua a soma. O
resultado é colocado no registrador r1
4. Armazenamento de resultado na memória: nada a fazer no caso desta
instrução.
A configuração da memória (que neste caso não é alterada) e do processador (com os registradores que foram alterados destacados em cinza) após a
execução desse passo é:
Processador
Memória
r1
00 00 11 bc
r2
80 00 00 ab
ip
00 00 02 04
208h
02 00 03 00
204h
11 00 01 02
200h
10
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Note que, como o registrador ip é incrementado no passo busca de instrução, a próxima execução a ser executada é a de código 02000300h, presente
no endereço de memória 204h.
A codificação de instruções no Faíska é bastante simples. Toda instrução
tem uma ou duas palavras. A primeira palavra é sempre dividida em quatro
campos de um byte cada:
31
24
instr
16
imd
8
dest
0
fonte
O campo instr representa o tipo da instrução a ser executada; no exemplo anterior mostramos que este campo deve ter o valor 11h para instruções
de soma. O campo imed terá sua utilização explicada mais adiante. Os campos fonte e destino codificam os registradores usados como fonte e/ou destino a
serem utilizados na instrução. Os registradores são identificados nestes campos pelos seus números, ou seja, o registrador r0 tem como representação o
valor 0, e o registrador r1 tem como representação o valor 1. A utilização
dos campos fonte e destino dependem da instrução em questão; algumas utilizam apenas o campo destino, outras apenas o campo fonte e algumas utilizam
ambos os campos.
Podemos agora entender a codificação da instrução “adicione o valor do
registrador r1 ao valor do registrador r2 e coloque o resultado em r1”, usada
como exemplo anteriormente:
instr
imd
dest
fonte
11h
-
01h
02h
Note como os campos fonte e destino foram utilizados. A instrução de
soma requer dois operandos fonte; por convenção, no Faíska neste caso o registrador destino é utilizado também como um dos operandos. Note também
que os campos que não são significativos para uma dada instrução (neste caso,
imd) podem ter qualquer valor, mas normalmente são codificados com zeros.
A codificação do Faíska é exageradamente simples. Em processadores
reais a codificação é bem mais complexa, devido a fatores internos da arquitetura de cada processador (como por exemplo a maneira pela qual é feita a
decodificação das instruções) e devido também ao fato de que existe um compromisso entre simplicidade e compactabilidade do código.
2.1. FUNCIONAMENTO DO PROCESSADOR
11
2.1.1 Modos de endereçamento
Na seção anterior nós vimos um exemplo de instrução que utiliza apenas registradores como operandos. Obviamente, os processadores possuem também
instruções de transferência de dados entre memória e registradores. Instruções de leitura de memória copiam (“carregam”) o valor de uma posição de
memória em um registrador, e instruções de escrita em memória copiam o
valor de um registrador em uma posição de memória.
Em instruções que fazem acesso à memória é necessário indicar qual a
palavra de memória que deve ser utilizada. Ou, mais precisamente, é necessário especificar como deve ser calculado o endereço da palavra de memória a
ser utilizada (chamado endereço efetivo do operando).
Existem diversas formas possíveis de cálculo do endereço efetivo. Essas
diferentes formas dão origem a diferentes modos (ou tipos) de endereçamento;
cada instrução do processador define precisamente o modo de endereçamento
utilizado. Nesta seção vamos apresentar apenas um modo de endereçamento,
o chamado endereçamento imediato. Outros modos de endereçamento serão
vistos mais adiante.
2.1.2 Endereçamento direto
Um dos modo mais simples de endereçamento é o chamado endereçamento
direto, no qual o endereço de uma palavra de memória (endereço do operando)
faz parte da codificação da instrução. O endereçamento direto pode ser utilizado por exemplo para copiar em um registrador o conteúdo de uma palavra
de memória.
No Faíska, a instrução que copia o conteúdo de uma palavra de memória
em um registrador é “carrega registrador com endereçamento direto”, que é
codificada utilizando-se duas palavras de memória. A primeira palavra especifica o tipo de operação (carrega registrador com endereçamento direto) e
o registrador destino (para onde a palavra de memória deve ser copiada). A
segunda palavra da instrução contém o endereço da palavra de memória cujo
conteúdo deve ser carregado no registrador destino. Vamos examinar o funcionamento do processador na instrução “carrega registrador r10 com o conteúdo da palavra de memória de endereço 2000h”. A primeira palavra dessa
instrução é 03000a00h e a segunda palavra 00002000h:
12
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
instr
imd
dest
fonte
03h
-
0ah
-
palavra 1
palavra 2
00002000h
Note que os campos imd e fonte não têm significado para essa instrução,
e são preenchidos com zeros.
Suponha a configuração de processador e memória mostrada na Figura 2.3.
Memória
Processador
02004h
22 22 22 22
r10
02000h
55 55 55 55
0fffch
ip
00 00 02 04
Antes
00 00 20 00
00208h
03 00 0a 00
00204h
Figura 2.3: Exemplo de instrução carrega registrador r10 com o conteúdo da
palavra de memória 2000h.
A sequência de operações realizadas pelo processador a partir dessa configuração será:
1. Busca de instrução na memória: o processador faz um acesso à memória para ler a palavra de memória apontada por ip (endereço 0204h) e
coloca o valor lido (02000000h) no registrador ir. O registrador ip é
avançado do número de bytes lidos: ip passa a valer 0208h. Note que
neste momento o registrador ip aponta para a palavra de memória que
contém o endereço do valor a ser carregado.
2. Busca de operando na memória: o processador faz um acesso à memória para ler a palavra de memória apontada por ip; o valor lido
(00002000h) é armazenado em um registrador interno do processador
(não mostrado). O processador faz um outro acesso à memória, com o
2.1. FUNCIONAMENTO DO PROCESSADOR
13
endereço lido anteriormente (00002000h), para finalmente ler o valor a
ser carregado, que é então armazenado no registrador destino r10. O
registrador ip é avançado para apontar para a próxima instrução, passando a valer 0210h.
3. Execução: nada a fazer no caso desta instrução.
4. Armazenamento de resultado na memória: nada a fazer no caso desta
instrução.
A configuração final da memória e do processador é mostrada na Figura 2.4, com os registradores que tiveram seus valores alterados destacados
em cinza.
Memória
Processador
02004h
22 22 22 22
r10
02000h
22 22 22 22
0fffch
ip
00 00 02 10
Depois
00 00 20 00
00208h
03 00 0a 00
00204h
Figura 2.4: Exemplo de instrução carrega registrador r10 com endereçamento
direto (após execução).
Note que também neste caso ao término da execução da instrução o registrador ip aponta para a próxima instrução a ser executada.
2.1.3 Um pequeno programa
Com a informação de como é a codificação das instruções no processador, vamos escrever um “programa” bastante simples.
14
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Exemplo 1 Vamos escrever um trecho de programa que calcule a soma dos
valores contidos nas palavras de endereço 2000h e 2004h e armazene o resultado no registrador r1.
03000200
00002000
03000100
00002004
11000102
carrega r2 com
na palavra com
carrega r1 com
na palavra com
soma r1 com r2
valor contido
este endereço
valor contido
este endereço
e coloca o resultado em r1
Colocando este trecho de programa em qualquer posição da memória, e
fazendo com que o registrador ip aponte para o endereço inicial do trecho, a
sequência de instruções especificada será executada. Por exemplo, se a configuração inicial da memória e processador for a mostrada na Figura 2.5, ao
final da execução do trecho a configuração da memória e processador será a
mostrada na Figura 2.6 com os registradores que tiveram seus valores alterados destacados em cinza.
Processador
r1
aa aa aa aa
r2
bb bb bb bb
Memória
33 33 33 33
02004h
22 22 22 22
02000h
0fffch
ip
00 00 01 00
Antes
11 00 01 02
00110h
00 00 20 04
0010ch
03 00 01 00
00108h
00 00 20 00
00104h
03 00 02 00
00100h
Figura 2.5: Memória e processador antes da execução do trecho do exemplo 1.
2.2. INTRODUÇÃO A LINGUAGENS DE MONTAGEM
Processador
r1
55 55 55 55
r2
22 22 22 22
15
Memória
33 33 33 33
02004h
22 22 22 22
02000h
0fffch
ip
00 00 01 14
Depois
11 00 01 02
00110h
00 00 20 04
0010ch
03 00 01 00
00108h
00 00 20 00
00104h
03 00 02 00
00100h
Figura 2.6: Memória e processador após a execução do trecho do exemplo 1.
2.2 Introdução a linguagens de montagem
Já deve ter ficado claro que a programação feita manualmente, no nível das
instruções do processador, no estilo do exemplo 1 seria uma tarefa árdua, pois
teríamos que conhecer a codificação de cada instrução. Além disto, este método é muito sujeito a erros.
Entretanto, este foi o método utilizado pelos primeiros programadores,
no início da era dos computadores (cérebros eletrônicos!). Esses programadores pioneiros logo descobriram que necessitavam de uma maneira mais confiável de montar as sequências de instruções de um programa. Assim surgiram
as primeiras linguagens de montagem (em inglês, assembly languages).
Uma linguagem de montagem é basicamente uma linguagem de programação bastante simples; tão simples que o compilador de uma linguagem de
montagem não é chamado propriamente de compilador, mas apenas de montador (em inglês, assembler). Assim como em linguagens de alto nível, um
programa em uma linguagem de montagem é uma sequência de comandos.
Mas, para facilitar a tarefa do montador, os comandos são simples (não há
comandos estruturados como for ou if da linguagem C) e o formato de um pro-
16
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
grama em linguagem de montagem é considerávelmente rígido (por exemplo,
deve haver apenas um comando de linguagem de montagem em cada linha do
programa).
Os comandos da linguagem de montagem são identificados por palavras
reservadas do montador, isto é, palavras que têm um significado fixo para
o montador e não podem ter o seu significado redefinido pelo programador.
Já vimos dois exemplos de palavras reservadas: set e add. Normalmente
cada comando em linguagem de montagem é traduzido pelo montador em uma
instrução de máquina. Operandos devem aparecer à direita do comando, e, se
mais de um operando é necessário, eles devem ser separados por vírgulas.
No Faíska usaremos a convenção de que o operando que será modificado pela
instrução aparece mais à esquerda na lista de operandos.
Um exemplo de comando em linguagem de montagem é
ld r1,2004h
Quando encontrada pelo montador, este comando em linguagem de montagem é traduzido na sequência de palavras binárias
03000100h
00002004h
Um outro exemplo de comando, para outra instrução do processador que
já vimos, é
add r1,r2
Quando encontrada pelo montador, este comando em linguagem de montagem é traduzido na palavra
11000102h
Para documentação do programa, a linguagem de montagem permite a
inclusão de comentários. Um comentário é iniciado pelo caractere ‘;’ e se estende até o final da linha. Comentários e linhas em branco são desconsidera-
2.2. INTRODUÇÃO A LINGUAGENS DE MONTAGEM
17
dos pelo montador.
A linguagem de montagem permite também a associação de um rótulo
definido pelo programador a um endereço de memória. Rótulos devem aparecer obrigatóriamente no início de uma linha e são usados para definir pontos
importantes em um programa (início de um procedimento, por exemplo), para
definir variáveis, ou simplesmente para documentação.
Cada linha de um programa em linguagem de montagem pode ter o seguinte formato, onde a notação [comp] indica que a presença do componente
comp é opcional (a ordem de cada um dos componentes na linha, no entanto, é
fixa):
[rótulo:] [comando]
[lista_de_operandos]
[; comentário]
onde rótulo é uma sequência de letras, dígitos ou o caractere ‘_’, que se
inicia com uma letra, é um comando da linguagem de montagem, lista de
operandos é uma lista de nomes ou expressões separadas por vírgulas.
Exemplo 2 Escrever um trecho de programa, em linguagem de montagem,
que calcule a soma dos valores contidos nas palavras de endereço 2000h e
2004h e armazene o resultado no registrador r1.
1
2
3
4
inicio:
ld
ld
add
r2,2000h
r1,2004h
r1,r2
; carrega primeiro termo da soma
; carrega segundo termo
; e soma os dois termos
Note que o montador traduz este trecho de programa em linguagem de
montagem exatamente na sequência de instruções de máquina do Exemplo 1.
2.2.1 Diretivas do Montador
Além das instruções uma linguagem de montagem inclui também diretivas.
Diretivas da linguagem de montagem, ao contrário das instruções, não são
traduzidas em código de máquina. Elas servem para transmitir informações
adicionais ao montador, como por exemplo definir uma constante que será
18
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
utiliza em vários pontos do programa. A linguagem de montagem do Faíska
inclui diretivas para definir constantes, reservar espaço na memória para armazenamento de variáveis, indicar o endereço inicial de montagem e indicar
o final do programa.
Diretiva de definição de constantes
Constantes podem ser definidas em qualquer parte do programa em linguagem de montagem, mas usualmente as definimos no início do programa, para
documentação e facilidade de leitura. Uma constante é introduzida pela diretiva EQU, cuja sintaxe é
nome equ
valor
Após a diretiva, toda ocorrência de nome é substituída por valor.
Exemplo 3
1
2
3
4
5
6
; definição de constantes
VERDADEIRO
FALSO
MAXVAL
MINVAL
equ
equ
equ
equ
0ffh
0
1000
MAXVAL/2
Diretiva de reserva de espaço em memória
Podemos reservar espaço na memória do Faíska de duas maneiras: inicializando o espaço com um valor conhecido, ou deixando o espaço não inicializado
(e portanto contendo um valor desconhecido). Essas duas formas de reservar espaço na memória são similares às formas de definição de variáveis na
linguagem C:
Exemplo 4
2.2. INTRODUÇÃO A LINGUAGENS DE MONTAGEM
1
2
3
4
5
6
19
// exemplo de declaração de variáveis não inicializadas em C:
int a,b[1000];
// exemplo de declaração de variáveis inicializadas em C:
int c=-1, d[4]={1,2,3,4};
Para simplesmente reservar espaço em memória usamos a diretiva ds,
que tem o formato geral
[rótulo:] ds
[expressão_inteira]
[; comentário]
Esta diretiva reserva expressão_inteira bytes de memória (os valores iniciais dos bytes são indefinidos).
Exemplo 5
1
2
3
4
5
6
7
8
9
; exemplo de reserva de espaço na memória para variáveis
; vamos primeiro definir uma constante
TAMANHO
equ
4
; agora reservamos espaço para algumas variáveis
contador:
ds
1
x:
ds
TAMANHO
final:
ds
4
Diretivas de reserva e inicialização de espaço em memória
Além de reservar espaço na memória para definição por exemplo de variáveis, é possível também atribuir valores iniciais a posições de memória. Esses
valores são carregados na memória do computador juntamente com o código
executável do programa. Assim, quando o programa inicia sua execução, as
variáveis definidas por essa diretiva já contêm os valores especificados (por
isso dizemos que é uma diretiva de inicialização de memória).
Para reservar e inicializar espaço em memória, usamos as diretivas db
(para reservar e inicializar bytes) e dw (para reservar e inicializar palavras).
20
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Reserva e inicialização de bytes
A diretiva db reserva e inicializa bytes:
[rótulo:] db
[lista_de_valores]
[; comentário]
A lista_de_valores é uma lista, separada por vírgulas, onde cada elemento pode ser uma expressão inteira, um caracter, ou uma sequência de caracteres entre aspas simples. O montador computa o valor de cada elemento
da lista e monta os valores resultantes nos bytes de memória, em sequência,
a partir do endereço associado a rótulo. Note que o processador, durante a
execução do programa montado, não executa nenhuma operação para que esses bytes de memória sejam inicializados. É o montador que coloca, no código
executável, informação para que essas posições de memória estejam com esses
valores no início da execução do programa.
Exemplo 6
1
2
3
4
5
6
7
8
9
10
; exemplo de reserva de espaço na memória para variáveis
; vamos primeiro definir uma constante
MAXVAL
equ
256
; agora reservamos espaço para algumas variáveis
contador:
db
1
estado:
db
0
x:
db
MAXVAL - 1
letra:
db
’a’
num:
db
-1
O espaço de memória reservado pela sequência de diretivas do Exemplo 6
é mostrado na Figura 2.7, onde a memória é apresentada no formato de um
vetor de bytes.
Para facilitar a definição de sequências de bytes, os valores podem ser
separados por vírgulas.
Exemplo 7
2.2. INTRODUÇÃO A LINGUAGENS DE MONTAGEM
21
Memória
num
ff
letra
61
x
ff
estado
00
contador
01
endereços
crescentes
Figura 2.7: Memória reservada pelo Exemplo 6.
1
2
3
4
5
6
7
; exemplo de reserva de espaço na memória para variáveis
; vamos primeiro definir uma constante
MAXVAL
equ
256
; agora reservamos espaço para algumas variáveis
dir:
db
128, 0feh, ’a’, MAXVAL-1
esq:
db
1, 0, 33
O espaço de memória reservado pela sequência de diretivas do Exemplo 7
é mostrado na Figura 2.8.
Memória
21
00
01
ff
endereços
crescentes
61
fe
80
Figura 2.8: Memória reservada pelo Exemplo 7.
Uma outra abreviação permitida é a utilização de aspas simples para a
definição de cadeias de caracteres. Ou seja, a diretiva
22
1
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Cadeia:
db
biriba, 0
db
‘b’,‘i’, ‘r’, ‘i’, ‘b’, ‘a’, 0
é equivalente a
1
Cadeia:
Reserva e inicialização de palavras
A diretiva de reserva de espaço de memória em palavras dw é similar à diretiva db, mas uma palavra inteira (quatro bytes) é reservada e um valor é
atribuído a essa palavra. O formato geral da diretiva dw é
[rótulo:] dw
[lista_de_valores]
[; comentário]
onde lista_de_valores é uma lista, separada por vírgulas, onde cada elemento pode ser uma constante numérica, um caracter, ou uma sequência de
caracteres entre aspas simples.
Exemplo 8
1
2
3
4
5
6
7
8
9
10
; exemplo de uso da diretiva dw
; primeiro definimos algumas constantes
ALTO
equ
32000h
BAIXO
equ
2000h
var_x:
var_y:
ultimo:
dw
dw
dw
dw
ALTO-1
BAIXO*2
31,32
-1
O espaço de memória reservado pela sequência de diretivas do Exemplo 8
é mostrado na Figura 2.9, onde a memória é apresentada no formato de um
vetor de palavras.
2.2. INTRODUÇÃO A LINGUAGENS DE MONTAGEM
23
Memória
ultimo
ff ff ff ff
00 00 00 20
00 00 00 1f
var_y
00 00 40 00
var_x
00 03 1f ff
endereços
crescentes
Figura 2.9: Memória reservada pelo Exemplo 8.
Note que programas escritos em linguagens de alto nível também oferecem maneiras de inicializar variáveis (ou seja, atribuir valores iniciais a
variáveis). Em C, por exemplo,
Diretiva para indicar endereço de montagem
Durante a montagem, o montador mantém um contador de montagem que
indica o endereço corrente de montagem, isto é, o endereço da próxima palavra a ser montada. Durante o processo de montagem, esse contador é incrementado do número de palavras da instrução a cada instrução montada.
O mesmo acontece quando o montador reserva espaço na memória: a cada
espaço reservado o contador é incrementado do número de bytes ou palavras
correspondente ao espaço.
Para alterar o valor do contador de montagem, utilizamos a diretiva org,
que tem o formato
org
[expressão_inteira]
[; comentário]
Ao encontrar esta diretiva, o montador toma expressão_inteira como o
novo valor do contador de montagem.
Exemplo 9
24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
; exemplo de reserva de espaço na memória para variáveis
; vamos primeiro definir algumas constantes
MAXVAL
TAM_BLOCO
NUM_BLOCO
equ
equ
equ
256
16
64
; agora definimos o endereço inicial de montagem do bloco
org
TAM_BLOCO * (NUM_BLOCO - 1)
bloco1:
dw
0,1,2
; este outro bloco deve começar em outro endereço
org
200h
bloco2:
db
10,11,12,13,14,15
O espaço de memória reservado pela sequência de diretivas do Exemplo 9
é mostrado na Figura 2.10.
Memória
00 00 00 03
3f8h
00 00 00 02
3f4h
00 00 00 01
3f0h
00 00 0f 0e
204h
0d 0c 0b 0a
200h
Figura 2.10: Memória reservada pelo Exemplo 9.
Diretiva para indicar final de montagem
A diretiva end indica ao montador que o programa que está sendo montado
chegou ao fim.
end
[; comentário]
2.3. COMO O MONTADOR FUNCIONA
25
Ao encontrar esta diretiva, o montador termina a montagem, ignorando
qualquer linha subsequente.
2.3 Como o Montador funciona
O montador traduz um arquivo texto, contendo o programa, como uma sequência de linhas, contendo comandos e diretivas em linguagem de montagem,
para um arquivo binário, contendo dados e instruções em linguagem de máquina.
Vamos ilustrar o funcionamento de um montador simples, de dois passos. Esse tipo de montador, a cada passo, lê do início ao fim o programa dado
como entrada. No primeiro passo o montador estabelece os valores de todos
os rótulos que foram definidos no programa (isto é, os endereços associados a
cada rótulo). No segundo passo o montador realmente produz o arquivo binário contendo as instruções e dados que compõe o programa. Como exemplo,
vamos considerar o seguinte trecho de programa em linguagem de montagem:
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
; exemplo de funcionamento do montador
; vamos primeiro definir uma constante
MINVAL
equ
256
; o endereço inicial de montagem é 0000h, vamos
; definir uma variável
var1:
dw
-1
; suponha que o programa propriamente deva se
; iniciar no endereço 1000h, por isso alteramos
; o endereço de montagem
org
1000h
inicio:
ld
r5,var1
ld
r6,var2
add
r5,r6
; o programa continua com outros comandos não mostrados
;
...
; o endereço de montagem é alterado novamente
org
2000h
; vamos definir outra variável
var2:
dw
MINVAL*2
end
O montador mantém uma Tabela de Rótulos, que associa um endereço de
memória a cada rótulo encontrado no programa, uma Tabela de Constantes,
que associa uma cadeia de caracteres a cada nome de constante definida com
a diretiva equ e uma Tabela de Comandos, que o montador utiliza para consultar as informações sobre cada comando (basicamente tamanho em bytes e
formato da instrução do processador correspondente ao comando). A variável interna PontoDeMontagem armazena o endereço corrente de montagem,
que inicialmente é zero (início da memória). O montador lê e processa cada
linha do programa individualmente. Em caso de erro, o montador interrompe
o processamento, emitindo uma mensagem com a causa do erro.
2.3. COMO O MONTADOR FUNCIONA
27
Vamos seguir linha a linha a execução do montador. Linhas contendo
apenas comentários (como a linha 1), ou linhas vazias (como a linha 5) são
ignoradas pelo montador e não são comentadas.
Passo 1
Neste passo, o montador irá calcular o valor correto de endereço a ser associado a cada rótulo do programa.
Linha 4: definição de constante, o montador inicialmente verifica se o nome
da constante (MINVAL) já está definido na Tabela de Constantes. Se já está é
um erro, pois significa que a constante já foi definida anteriormente, e nesse
caso o montador interrompre o processamento. Como MINVAL não foi definido anteriormente, o montador cria uma entrada na Tabela de Constantes,
associando a palavra MINVAL à cadeia de caracteres “256” (note que não associa ao valor inteiro 256).
Linha 8: o montador encontra o rótulo var1 e inicialmente verifica se já existe
uma entrada na Tabela de Rótulos com esse nome (se existe é um erro, o
mesmo rótulo está já foi utilizado anteriormente no programa). Como não encontra um rótulo com esse nome definido, cria uma entrada na Tabela de Rótulos, associando var1 ao endereço 0 (valor corrente de PontoDeMontagem).
O montador encontra a diretiva dw (reserva e inicialização de palavras), com
um único operando (o valor −1), e portanto o montador avança PontoDeMontagem de quatro bytes, deixando reservado na memória o espaço para o valor
declarado.
Linha 15: ao encontrar esta diretiva, o montador altera PontoDeMontagem
para o valor 1000h.
Linha 16: o montador encontra o rótulo inicio, determina que não foi ainda
defindo, e cria uma entrada na Tabela de Rótulos, associando o rótulo encontrado ao valor 1000h (valor corrente de PontoDeMontagem).
Linha 17: o montador encontra o comando ld e consulta a Tabela de Comandos para determinar quantos bytes a instrução correspondente utiliza. Como
vimos, essa instrução utiliza duas palavras e portanto o montador atualiza
PontoDeMontagem para 1008h, deixando reservado na memória o espaço para
essa instrução. O montador encontra var1 como operando, consulta a Tabela
de Rótulos e, como o rótulo já está definido, não há nada mais a fazer.
28
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
Linha 18: o montador encontra o comando ld e consulta a Tabela de Comandos para determinar quantos bytes a instrução correspondente utiliza,
e atualiza PontoDeMontagem para 1010h. O montador encontra var2 como
operando, consulta a Tabela de Rótulos e, como um rótulo com esse nome não
está definido, cria uma entrada para o rótulo, marcando-o como ainda não
definido.
Linha 19: o montador encontra o comando add e consulta a Tabela de Comandos para determinar quantos bytes a instrução correspondente utiliza. Como
vimos, essa instrução utiliza uma palavra e portanto o montador atualiza PontoDeMontagem para 1014h.
Linha 24: ao encontrar esta diretiva, o montador altera PontoDeMontagem
para o valor 2000h.
Linha 28: o montador encontra o rótulo var2 e inicialmente verifica se já
existe uma entrada na Tabela de Rótulos com esse nome (se existe e o rótulo já está associado a um endereço de memória é um erro: o mesmo rótulo
já foi utilizado e definido anteriormente no programa). Como encontra o rótulo na Tabela de Rótulos, mas este está marcado como indefinido, atualiza a
Tabela de Rótulos, associandovar2 ao endereço 2000h (valor corrente de PontoDeMontagem). O montador encontra a diretiva dw (reserva e inicialização
de palavras), com um único operando (o resultado da expressão MINVAL*2),
e portanto o montador avança PontoDeMontagem de quatro bytes.
Linha 30: o montador encontra a diretiva end marcando o final da execução do
passo 1. O montador então verifica se todos os rótulos presentes na Tabela de
Rótulos estão definidos (caso contrário é um erro, pois significa que o operando
de algum comando ficou indefinido).
Passo 2
Neste passo, o montador irá produzir o arquivo binário correspondente ao programa. O arquivo binário deve conter informações que permitam que, quando
carregado na memória do computador, o programa seja corretamente executado. Não entraremos aqui em detalhes quanto ao formato do arquivo binário,
informando apenas quais valores devem ser armazenados em quais endereços.
No início do passo 2 a variável interna PontoDeMontagem é reinicializada para zero.
2.3. COMO O MONTADOR FUNCIONA
29
Linha 4: definição de constante, tratada apenas no passo 1, ignorada no passo
2.
Linha 8: o montador encontra o rótulo var1, que é ignorado no passo 2. O
montador encontra a diretiva dw (reserva e inicialização de palavras), com
um único operando (o valor −1), e portanto escreve no arquivo de saída uma
palavra com o valor −1 (ffffffffh) no endereço corrente de PontoDeMontagem
(0h). O montador então avança PontoDeMontagem de quatro bytes. O arquivo
binário contém nesse momento
Endereço (em hexa)
00000000
Valor (em hexa)
ffffffff
Linha 15: ao encontrar esta diretiva, o montador altera PontoDeMontagem
para o valor 1000h.
Linha 16: o montador encontra o rótulo inicio, que é ignorado neste passo.
Linha 17: o montador encontra o comando ld e consulta a Tabela de Comandos para determinar a codificação da instrução correspondente. Como vimos,
essa instrução utiliza duas palavras. A primeira palavra da instrução contém
o código da instrução (03h) no quarto byte (o mais significativo). O montador encontra o registrador destino (r5) como primeiro operando do comando e
monta o valor correspondente (05h) no segundo byte da primeira palavra. O
montador escreve no arquivo binário o valor 03000500h no endereço corrente
de montagem (1000h) e atualiza PontoDeMontagem para 1004h. A segunda
palavra da instrução deve conter o endereço do operando; o montador encontra var1 como segundo operando do comando, consulta a Tabela de Rótulos,
e escreve, no endereço corrente de montagem (1004h) o valor associado ao
rótulo var1 (0h). Nesse momento, o arquivo de saída contém
Endereço (em hexa)
00000000
00001000
00001004
Valor (em hexa)
ffffffff
03000500
00000000
Linha 18: o montador encontra o comando ld e consulta a Tabela de Comandos para determinar a codificação da instrução correspondente, e determina
30
CAPÍTULO 2. ORGANIZAÇÃO BÁSICA DE COMPUTADORES
que a instrução utiliza duas palavras. A primeira palavra da instrução contém o código da instrução (03h) no quarto byte (o mais significativo). O montador encontra o registrador destino (r6) como primeiro operando do comando
e monta o valor correspondente (06h) no segundo byte da primeira palavra. O
montador escreve no arquivo binário o valor 03000600h no endereço corrente
de montagem (1008h) e atualiza PontoDeMontagem para 100ch. A segunda
palavra da instrução deve conter o endereço do operando; o montador encontra var2 como segundo operando do comando, consulta a Tabela de Rótulos,
e escreve, no endereço corrente de montagem (100ch) o valor associado ao rótulo var2 (2000h). O montador avança PontoDeMontagem para 1010h. Nesse
momento, o arquivo de saída contém
Endereço (em hexa)
00000000
00001000
00001004
00001008
0000100c
Valor (em hexa)
ffffffff
03000500
00000000
03000600
00002000
Linha 19: o montador encontra o comando add e consulta a Tabela de Comandos para determinar a codificação da instrução correspondente. Como vimos,
essa instrução utiliza uma palavra, com o código 11h no quarto byte (o mais
significativo). O montador encontra o registrador destino (r5) e monta o seu
valor (05h) no segundo byte da instrução; o montador encontra o registrador
fonte (r6) e monta o seu valor (06h) no primeiro byte (o menos significativo)
da instrução. Finalmente, o montador escreve a palavra correspondente à
instrução (11000506h) no endereço corrente de montagem (1010h) e atualiza
PontoDeMontagem para 1014h. Nesse momento, o arquivo de saída contém
Endereço (em hexa)
00000000
00001000
00001004
00001008
0000100c
00001010
Valor (em hexa)
ffffffff
03000500
00000000
03000600
00002000
11000506
2.3. COMO O MONTADOR FUNCIONA
31
Linha 24: ao encontrar esta diretiva, o montador altera PontoDeMontagem
para o valor 2000h.
Linha 28: o montador encontra o rótulo var2, que é ignorado no passo 2. O
montador encontra a diretiva dw (reserva e inicialização de palavras), com um
único operando (a expressão MINVAL*2). Consultando a Tabela de Rótulos o
montador determina que MINVAL não é um rótulo, devendo então ser uma
constante. O montador consulta a Tabela de Constantes, determina que MINVAL foi definido como 256, substitui MINVAL por 256 na expressão, calcula o
resultado da expressão e escreve no arquivo de saída uma palavra com o valor
do resultado (200h) no endereço corrente de montagem, definido por PontoDeMontagem (2000h). O montador então avança PontoDeMontagem de quatro
bytes. O arquivo binário contém nesse momento
Endereço (em hexa)
00000000
00001000
00001004
00001008
0000100c
00001010
00002000
Valor (em hexa)
ffffffff
03000500
00000000
03000600
00002000
11000506
00000200
Linha 30: o montador encontra a diretiva end marcando o final da execução
do passo 2 e do processo de montagem.
Download