Você está na página 1de 6

Instituto Federal de Educação, Ciência e Tecnologia de Goiás

Campus Anápolis
Departamento de Áreas Acadêmicas 1/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I

Trabalho N1 – Tipo 4 (versão 1) – Valor: 10%

O objetivo deste trabalho é compreender como o ciclo de instrução da Máquina de von Neumann. Para isso, cada dupla de
alunos deverá implementar um “simulador” de uma CPU com o conjunto de instruções (ISA – Instruction Set Architecture),
o conjunto de registradores arquiteturais e o formato de instrução listados abaixo. Esse simulador deve mostrar o conteúdo
dos registradores no fim de cada ciclo de máquina, quando haverá uma pausa até apertar uma tecla para iniciar o próximo
ciclo.
O prazo de entrega é 07/04/2022, sexta-feira, às 23:59 via Moodle. Como de praxe, cópia ou semelhança nas implemen-
tações serão punidas com nota zero para todas as duplas em que isso for detectado. Passar o seu código para o colega
é antiético, antiprofissional e está atrapalhando no desenvolvimento dele. Além disso, corre-se o risco da punição e, no fim
do semestre, todo ponto faz diferença entre ser aprovado ou não.
Os entregáveis são: todos os códigos-fonte necessários para a compilação e o programa compilado, assim como
instruções de compilação e de uso do programa.
Ele deve ser implementado em linguagem C. Não é C++ e, sim, C. Portanto, sem orientação a objeto, pois só complica
desnecessariamente o desenvolvimento deste trabalho em específico. Para facilitar, a memória deve ser um vetor de
palavras de oito bits de 154 posições, o que, consequentemente, totalizará essa mesma quantidade em bytes. Em outras
palavras, unsigned char memoria[154]. Não serão aceitas implementações onde os registradores sejam um vetor de carac-
teres ou a memória, uma matriz de caracteres. O programa deve ser colocado na memória na forma binária respeitando os
formatos das palavras de instrução abaixo.
O simulador deve possuir uma maneira de ler um arquivo texto para carregar a memória com instruções e dados como
apresentado na última página. É importante ressaltar, porém, que o simulador não precisa ser “bonito”, mas precisa ser fácil
de usar.
Além disso, a CPU a ser implementada processa palavras de 16 bits contendo apenas números inteiros e, portanto, não há
nenhuma operação com ponto-flutuante. Ademais, não é necessário implementar nenhuma representação de aritmética
sinalizada. Embora o formato de instrução permita endereçar até 211 = 2.048 palavras de oito bits na memória, a memória
possui apenas 154 endereços, como apresentado acima, abrangendo os endereços de 0 (0x0) a 153 (0x99).
De maneira muito simplificada, o diagrama da CPU com os registradores arquiteturais é:

Arith. and Logic Unit

A B T

Arithmetic and
Logic circuits

Memory
MBR

IBR PC

IR MAR

IR LR

Control circuits

Control Unit
Instituto Federal de Educação, Ciência e Tecnologia de Goiás
Campus Anápolis
Departamento de Áreas Acadêmicas 2/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I
E a função de cada registrador arquitetural é:
1. MBR – Memory Buffer Register – contém a palavra a ser armazenada na memória. Também é o registrador usado
para receber uma palavra lida da memória. Todo o tráfego de e para a memória RAM deve passar pelo MBR. Deve
ser implementado como uma variável de 32 bits (unsigned int mbr);
2. MAR – Memory Address Register – especifica o endereço de memória da palavra a ser lida da ou escrita na memó-
ria. Todo endereço de memória deve ser indicado nesse registrador antes da execução da instrução. Teoricamente,
ele deveria ter o tamanho de 11 bits, mas como não existe variável de 11 bits na linguagem C, ele deve ser imple-
mentado como uma variável de 16 bits (unsigned short int mar);
3. IBR – Instruction Buffer Register – contém a instrução a ser decodificada no próximo ciclo de máquina. Contudo,
deve-se atentar para o fato de que a busca de instruções ocorre em clocks alternados, seguindo o valor do registra-
dor LR. Se LR = 0, deve-se buscar uma palavra de instrução de 32 bits, que contém duas instruções de 16 bits cada.
Assim, ao buscar a instrução à esquerda, a instrução à direita vem junto. Dessa forma, quando LR = 0, a instrução
da esquerda terá os seus campos divididos em IR, MAR e IMM abaixo durante o estágio de decodificação, seguindo
para a execução, enquanto a instrução à direita apenas é armazenada em IBR. Ao fim do ciclo de máquina, LR é
alterado para 1. Daí, o estágio de busca durante o próximo ciclo de instrução buscará a instrução contida no IBR e
não na memória, seguido da divisão dos seus campos durante o estágio de decodificação e posterior execução. Ao
fim, atribui-se o valor 1 a LR. O IBR deve ser implementado como uma variável de 16 bits (unsigned short int
ibr);

4. IR – Instruction Register – contém o opcode da instrução a ser executada. Teoricamente, ele deveria ter o tamanho
de cinco bits, mas como não existe variável de cinco bits na linguagem C, ele deve ser implementado como uma
variável de oito bits (unsigned char ir);
5. IMM – Immediate – contém o operando imediato da instrução. Teoricamente, ele deveria ter o tamanho de 11 bits,
mas como não existe variável de 11 bits na linguagem C, ele deve ser implementado como uma variável de 16 bits
(unsigned short int mar);
6. PC – Program Counter – contém o endereço da próxima palavra de instrução a ser buscada na memória. Caso não
haja nenhum desvio, halt ou nop, o PC deve ser incrementado em cada ciclo de instrução. Deve ser implementado
como uma variável de 16 bits (unsigned short int pc);
7. E, L e G – registradores internos que armazena as flags ‘equal to’, ‘lower than’ e ‘greater than’. Cada uma delas
contém um bit indicando se o conteúdo do registrador A é, ao ser comparado pela instrução cmp, respectivamente
1) igual a, 2) menor do que ou 3) maior do que o conteúdo do registrador B. Como não há maneira de implementar
variáveis de um bit, devem ser implementados como variáveis de oito bits ( unsigned char e, unsigned char l,
unsigned char g);

8. LR – Flag Left/Right – registrador interno que armazena uma flag que varia entre 0 e 1 para indicar, respectivamente,
a decodificação e a execução da instrução da esquerda ou da direita, conforme explicado acima. Como não há
maneira de implementar variáveis de um bit, deve ser implementado como uma variável de oito bits (unsigned char
lr);

9. A – Register A – utilizado para manter temporariamente os operandos na ALU. Deve ser implementado como uma
variável de 16 bits (unsigned short int a);
10. B – Register B – utilizado para manter temporiamente os operandos na ALU. Deve ser implementado como uma
variável de 16 bits (unsigned short int b);
11. T – Registrador T – utilizado como um espaço temporário apenas pela instrução xchg explicada abaixo. Deve ser
implementado como uma variável de 16 bits (unsigned short int t).
Finalmente, o conjunto de instruções é:
Instituto Federal de Educação, Ciência e Tecnologia de Goiás
Campus Anápolis
Departamento de Áreas Acadêmicas 3/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I
Mnemônico Opcode Descrição
HALT: o processador não faz nada. Em outras palavras, nenhum registrador tem o seu valor alterado durante a
hlt 0b00000
execução de hlt. Deve-se colocar no fim do programa.
NO OPERATION: Se 𝐿𝑅 = 1, o PC é incrementado, mas nenhum outro registrador tem seu valor alterado du-
nop 0b00001 rante a execução de nop, com exceção de LR, que segue o funcionamento apresentado acima. Caso 𝐿𝑅 = 0,
nenhum registrador, com exceção de LR, tem seu valor alterado.
add 0b00010 ADD REGISTER: A = A + B
sub 0b00011 SUBTRACT REGISTER: A = A − B
mul 0b00100 MULTIPLY REGISTER: A = A × B
div 0b00101 DIVIDE REGISTER: A = A ÷ B
COMPARE REGISTER: compara a palavra no registrador A com a palavra no registrador B e preenche os regis-
tradores internos E, L e G os valores fazendo sequencialmente os seguintes testes:
cmp 0b00110 1. Se A = B, então E = 1; senão E = 0;
2. Se A < B, então L = 1; senão L = 0;
3. Se A > B, então G = 1; senão G = 0.
EXCHANGE: alterna o conteúdo entre os registradores A e B usando o registrador interno T como espaço tempo-
rário:
xchg 0b00111 1) 𝑇 ← 𝐴;
2) 𝐴 ← 𝐵;
3) 𝐵 ← 𝐴.
and 0b01000 LOGICAL-AND ON REGISTER: A = A & B
or 0b01001 LOGICAL-OR ON REGISTER: A = A | B
xor 0b01010 LOGICAL-XOR ON REGISTER: A = A ^ B
not 0b01011 LOGICAL-NOT ON REGISTER: A = ! A
je M[X] 0b01100 JUMP IF EQUAL TO: muda o registrador PC para o endereço de memória X caso E = 1.
jne M[X] 0b01101 JUMP IF NOT EQUAL TO: muda o registrador PC para o endereço de memória X caso E = 0.
jl M[X] 0b01110 JUMP IF LOWER THAN: muda o registrador PC para o endereço de memória X caso L = 1.
JUMP IF LOWER THAN OR EQUAL TO: muda o registrador PC para o endereço de memória X caso E = 1 ou
jle M[X] 0b01111
L = 1.
jg M[X] 0b10000 JUMP IF GREATER THAN: muda o registrador PC para o endereço de memória X caso G = 1.
JUMP IF GREATER THAN OR EQUAL TO: muda o registrador PC para o endereço de memória X caso E = 1 ou
jge M[X] 0b10001
G = 1.
jmp M[X] 0b10010 JUMP: muda o registrador PC para o endereço de memória X.
lda M[X] 0b10011 LOAD A: carrega o registrador A com uma palavra de 16 bits da memória que se inicia no endereço X.
ldb M[X] 0b10100 LOAD B: carrega o registrador B com uma palavra de 16 bits da memória que se inicia no endereço X.
STORE A: armazena em uma palavra de 16 bits que começa a partir do endereço de memória X o conteúdo do
sta M[X] 0b10101
registrador A.
STORE B: armazena em uma palavra de 16 bits que começa a partir do endereço de memória X o conteúdo do
stb M[X] 0b10110
registrador B.
LOAD A WITH WORD POINTED BY B: carrega o registrador A com uma palavra de 16 bits da memória que se
ldrb 0b10111
inicia no endereço contido no registrador B.
MOVE IMMEDIATE TO LOWER A: zera o registrador A e move os oito bits menos significativos (0:7) do imediato
movial imm 0b11000
para a parte inferior (0:7) do registrador A.
MOVE IMMEDIATE TO HIGHER A: move os oito bits menos significativos (0:7) do imediato para a parte superior
moviah imm 0b11001
(8:15) do registrador A, enquanto os bits menos significativos do registrador A são mantidos intactos.
addia imm 0b11010 ADD A WITH IMMEDIATE: A = A + IMM
subia imm 0b11011 SUBTRACT A WITH IMMEDIATE: A = A − IMM
mulia imm 0b11100 MULTIPLY A WITH IMMEDIATE: A = A × IMM
divia imm 0b11101 DIVIDE A WITH IMMEDIATE: A = A ÷ IMM
lsh imm 0b11110 LEFT SHIFT: desloca a palavra no registrador A em IMM bits à esquerda.
rsh imm 0b11111 RIGHT SHIFT: desloca a palavra no registrador A em IMM bits à direita.

As instruções são codificadas da seguinte forma:


Opcode Memory address or immediate Opcode Memory address or immediate

0 4 15 20 31

Pode-se observar que uma palavra de instrução pode armazenar duas instruções independentes, uma à esquerda (0:15) e
outra à direita (16:31). Independentemente de que lado da palavra as instruções estão, elas são codificadas como mostrado
abaixo:
Instituto Federal de Educação, Ciência e Tecnologia de Goiás
Campus Anápolis
Departamento de Áreas Acadêmicas 4/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I
Mnemônico Formato da instrução
hlt
nop
add
sub
mul
div Opcode 0
cmp
xchg 0 4 15

and
or
xor
not
ldrb
je M[X]
jne M[X]
jl M[X]
jle M[X]
jg M[X] Opcode Memory address
jge M[X]
jmp M[X] 0 4 15
lda M[X]
ldb M[X]
sta M[X]
stb M[X]
movial imm
moviah imm
addia imm Opcode Immediate
subia imm
mulia imm
0 4 15
divia imm
lsh imm
rsh imm

Observe que o simulador deverá ser capaz de simular qualquer programa que for adicionado na memória. O programa deve
ser colocado na memória na forma binária respeitando os formatos das palavras de instrução ilustradas na tabela acima.
Dessa forma, o funcionamento do programa deve seguir a seguinte sequência:
Preenche as Executa cada instrução do
Início posições de programa, mostrando todo o Fim
memória contexto da CPU no monitor

Para a primeira etapa – carregar a memória – o simulador deve ler um arquivo texto como apresentado na última página.
Essa etapa deve continuar enquanto o programa não encontrar a linha contendo ‘ hlt’ (sem os apóstrofos). A conversão
preencherá a memória em uma maneira semelhante à observada abaixo.
End. inicial
Conteúdo Conteúdo codificado em binário Conteúdo codificado em hexadecimal
de memória
lda C
0x0 1001 1000 0000 1100 1010 0000 0000 1110 98 0C A0 0E
ldb E
add
0x4 0001 0000 0000 0000 1100 1000 0010 0000 10 00 C8 20
addia 20
sta 10
0x8 1010 1000 0001 0000 0000 0000 0000 0000 A8 10 00 00
hlt
0xA 15 0000 0000 0000 1111 00 0F
0xC 8 0000 0000 0000 1000 00 08
Instituto Federal de Educação, Ciência e Tecnologia de Goiás
Campus Anápolis
Departamento de Áreas Acadêmicas 5/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I
Você pode observar na última coluna da tabela acima que os valores estão agrupados em pares de valores hexadecimais,
onde cada um deles é um byte (ou o equivalente a uma posição de memória). Dessa forma, o mapa de memória fica assim
(os endereços de memória e os seus conteúdos estão em hexadecimal):
Endereço Conteúdo Endereço Conteúdo Endereço Conteúdo Endereço Conteúdo
0 98 8 A8 10 ... 18 ...
1 1E 9 22 11 ... 19 ...
2 A0 A 00 12 ... 1A ...
3 20 B 00 13 ... 1B ...
4 10 C 00 14 ... 1C ...
5 00 D 0F 15 ... 1D ...
6 C8 E 00 16 ... 1E ...
7 20 F 08 17 ... 1F ...
O que estará na memória é o que está nessa tabela.
A segunda etapa – exibir o funcionamento da CPU executando o programa – o trabalho deve exibir algo assim (considerando
que todos os conteúdos de registradores e da memória, incluindo os seus endereços, estão em hexadecimal):
CPU:
A: 0xFFFF B: 0xFFFF T: 0xFFFF
MBR: 0xFFFFFFFF MAR: 0xFFFF IMM: 0xFFFF
PC: 0xFFFF IR: 0xFF LR: 0xF
E: 0xF L: 0xF G: 0xF

Memória:
00: 0xFF 01: 0xFF 02: 0xFF 03: 0xFF
... ... ... 99: 0xFF

Pressione uma tecla para iniciar o próximo ciclo de máquina ou aperte CTRL+C para finalizar a execução
do trabalho.

Deve-se exibir o conteúdo dos registradores e da memória ao fim de cada ciclo de máquina, com o usuário devendo pressi-
onar uma tecla para iniciar a execução do próximo ciclo.
Para ajudar no desenvolvimento do trabalho, teste-o com os dois programas abaixo, considerando que eles já estão no
formato esperado de arquivo esperado de arquivo a ser lido pelo trabalho. Todos os dados, endereços e imediatos estão
representados em hexadecimal. Observe que as linhas que estão no formato endereço;instrução/dado;palavra de ins-
trução ou palavra de dado. Em todo caso, o endereço inicial de memória que aquela instrução ou dado ocupará é dado
em hexadecimal, assim como os valores numéricos nas instruções. Além disso, observe que as instruções sempre ocupam
quatro bytes e os dados, dois bytes
10
4 10
𝐴 = 32 + 3 × 𝐴=∑ + 3 × (2 − 1)
5−3 5
1
0;i;lda 90/ldb 92
0;i;lda 96/ldb 98
4;i;div/sta 88
4;i;sub/xchg
8;i;lda 96/lda 98
8;i;lda 94/div
c;i;sub/lda 94
c;i;ldb 92/mul
10;i;mul/lda 88
10;i;ldb 90/add
14;add/ldb 8a
14;i;sta 8e/hlt 18;i;add/sta 8a
90;d;20
1c;i;lda 8c/ldb 8e
92;d;3
20;i;addia 1/sta 8c
94;d;4
24;i;cmp/jle 0
96;d;5
28;i;hlt/hlt
98;d;3 8a;d;0
8c;d;1
8e;d;a
90;d;a
92;d;5
Instituto Federal de Educação, Ciência e Tecnologia de Goiás
Campus Anápolis
Departamento de Áreas Acadêmicas 6/6
Curso de Bacharelado em Ciência da Computação
Disciplina de Arquitetura e Organização de Computadores I
94;d;3
96;d;2
98;d;1

Você também pode gostar