Buscar

Arquitetura do Microprocessador 8086

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

PONTIFÍCIA UNIVERSIDADE CATÓLICA DO RIO GRANDE DO SUL
FACULDADE DE ENGENHARIA
Vanessa Borba de Souza
Márcia Federizzi
Arquitetura Intel x8086� – Simuladores
Trabalho desenvolvido para a disciplina de
 Arquitetura de Computadores - EC.
 
 
 
 Profº. Eduardo Bezerra
Porto Alegre, 28 de Abril de 2009
�
Sumário
3Introdução	�
4Arquitetura do microprocessador 8086	�
5Registradores de Uso Geral	�
6Registradores de Segmento	�
7Apontador de Instrução: IP	�
7Registrador de FLAGS	�
9Memória	�
10Modos de Endereçamento	�
11Linguagem Assembly	�
12Introdução ao Projeto dos Simuladores	�
13Decodificação das Instruções	�
16Exemplo de Fluxo de Instruções no Diagrama de Blocos	�
17Sobre o arquivo teste	�
18Simuladores	�
18Simulador da arquitetura 8086 – Sem Pipeline	�
18Executando o programa	�
19Funcionamento	�
21Cálculo do CPI	�
22Simulador da arquitetura 8086 – Com Pipeline	�
22O Pipeline	�
22Conflitos do Pipeline	�
22Hazards Estruturais	�
22Hazards de Controle	�
23Hazards de Dados	�
24Executando o programa	�
24Funcionamento	�
26Cálculo do CPI	�
27Sinais de Controle	�
29Conclusão	�
30Referências Bibliográficas	�
��
Introdução 
O 8086 é um dos mais antigos e conhecidos microprocessadores de 16 bits. Sua popularidade se deve a ter sido escolhido como processador para a linha de computadores pessoais da IBM. Na verdade, o IBM-PC tradicional usa uma versão simplificada do 8086, o 8088. Novos membros da família IBM-PC (como o PC AT e o PS/2) usam extensões (versões melhoradas e parcialmente �compatíveis) do 8086.
�
Arquitetura do microprocessador 8086
O microprocessador 8086 da Intel é um microprocessador de 16 bits, de forma que sua unidade lógica e aritmética, os seus registradores internos, e a maior parte das suas instruções foram projetados para trabalhar com palavras de 16 bits.
Além disso, o 8086 tem um barramento de dados de 16 bits, ou seja, pode ler e escrever na memória ou nos portos de E/S utilizando 16 bits de uma só vez. O barramento de endereços é de 20 bits, de forma que o 8086 pode endereçar 1 MB (220�) posições de memória. Cada uma destas posições de memória é ocupada por um Byte�.
O processador está dividido em duas unidades funcionais que cooperam entre si:
	• A Unidade de Execução – ("Execution Unit" - EU): Esta unidade é responsável exclusivamente pela execução das instruções. Ela não se ocupa da transferência de informações entre o microprocessador e os demais componentes do sistema. Quando a execução de uma instrução exige o acesso a algum operando externo ao microprocessador, a EU gera uma solicitação à BIU.
	• A Unidade de Interface com o Barramento – ("Bus Interface Unit" - BIU): Esta unidade se ocupa exclusivamente com a transferência de informações entre o microprocessador e o restante do sistema, ou seja, é responsável pelo endereçamento do barramento de endereços, lê instruções da memória, lê e escreve dados nas portas e na memória. 
	Figura 1.0: Diagrama de blocos da arquitetura interna de um processador 8086/88
�
A Figura 1.0 mostra a arquitetura interna dos microprocessadores 8086 e 8088. Existem basicamente duas diferenças entre eles: a largura do barramento externo de dados (8 bits no 8088, e 16 bits no 8086), e o tamanho do bloco "fila de instruções" (4 bytes no 8088 e 6 bytes no 8086).Nesta mesma figura podem ser visualizados os principais blocos são da arquitetura, sendo eles abaixo descritos: 
Unidade Aritmética e Lógica (ALU ): unidade capaz de executar operações sobre 8 ou 16 bits. Executa operações lógicas e aritméticas, realiza a manutenção do estado do microprocessador e das flags de controle, além de manipular os registros de uso geral e dos operandos das instruções.
Banco de Registradores, constituído de: 
Registradores de Uso Geral: AX, BX, CX, DX, SP, BP, SI e DI;
Registradores de Segmento: CS, DS, SS e ES;
Apontador de Instrução: IP;
Registrador de FLAGS.
Registradores de Uso Geral
 
São registradores de 16 bits, utilizados para armazenar qualquer informação durante a execução do programa. 
Os registradores de uso geral são subdivididos em dois conjuntos de 4 registradores:
Registradores de Dados: AX, BX, CX e DX. Seus bytes superiores (AH, BH, CH e DH) e inferiores (AL, BL, CL e DL) podem ser acessados de modo independentes, ou seja, cada registrador pode ser usado como um registrador de 8 ou 16 bits. Evitando assim o uso de registradores de 16 bits quando se realizam operações de 8 bits. Eles podem ser utilizados sem restrições na maioria das operações lógicas e aritméticas, mas algumas instruções utilizam certos registradores de forma implícita, permitindo uma poderosa forma de codificação.
 Registradores Apontadores e de Indexação: SP, BP, SI e DI. O acesso a esses registradores é sempre feito em 16 bits.
Podem também participar da maioria das operações lógicas e aritméticas.
Registrador AX (AH e AL):
 É também denominado Acumulador Primário. Todas as operações de I/O são realizadas através deste registrador. As operações que utilizam dados imediatos necessitam de menos memória quando são feitas através de AX.
Geralmente é utilizado como hospedeiro� para valores retornados de sub-rotinas.
Registrador BX (BH e BL):
É também denominado Registrador Base. Usado preferencialmente como apontador da base de uma tabela de dados. Todas as referências à memória que usam esse registrador no cálculo do endereço usam o registrador DS como segmento padrão.
Registrador CX (CH e CL):
É também denominado Contador, sendo usado prioritariamente para contar o número de interações no interior de um loop e também na manipulação de strings. Ele é decrementado durante as operações envolvendo loops e strings. Também utilizado na rotação e deslocamento de vários bits.
Registrador DX (DH e DL):
É também chamado de registrador de dados ou endereçador de I/O. É usado para guardar dados de 16 bits nas operações com a ULA e controle indireto de I/O. Pode ser usado por compiladores para retornar valores de subrotinas.
Registrador SP:
É denominado Stack Pointer (Ponteiro de Pilha). Utilizado juntamente com BP para acessar dados no segmento da pilha. Armazena o “offset” do endereço do topo da pilha. Todas as referências ao SP, por definição, utilizam juntamente o registrador de segmento SS. Também pode ser usado como operando em operações lógicas e aritméticas de 16 bits.
Registrador BP:
É denominado Base Pointer (Ponteiro da Base). Permite acessar dados no segmento da pilha. Tipicamente é usado para acessar parâmetros que foram passados pela pilha. Também pode ser usado como operando em operações lógicas e aritméticas de 16 bits.
Registradores de Indexação (SI e DI):
São denominados Source Index (Índice de Origem) e Destination Index (Índice de Destino). São usados para acessar dados na memória de dados. São extensivamente usados nas operações com strings. Também podem ser usados como operando em operações lógicas e aritméticas de 16 bits.
Registradores de Segmento
A memória do 8086/88 é dividida em segmentos lógicos de até 64 Kb. A CPU tem acesso simultâneo a até 4 segmentos, utilizando os registradores CS, DS, SS e ES como seletores de endereço. Estes registradores estão localizados na BIU, sendo acessíveis para programas, podendo ser manipulados por várias instruções. As principais funções de cada um destes registradores:
Registrador CS:
É denominado Code Segment (Segmento de Código). É utilizado para montar o endereço de uma instruçã (code) a ser buscada (fetch) na memória. Este define o endereço base (segmento) e deveser somado ao registrador IP (também localizado na BIU) para formar o endereço de 20 bits da instrução. Em outras palavras, aponta para o segmento de código de instrução em uso.
Registrador DS:
É denominado Data Segment (Segmento de Dados). Aponta para os segmentos de dados onde geralmente são armazenadas as variáveis de programa. Em conjunto com IP define o endereço efetivo do dado a ser lido ou escrito na memória.
Registrador SS:
É denominado Stack Segment (Segmento de Pilha). Aponta para o segmento da pilha em uso. Todos os acessos à pilha utilizam os registradores SP e BP e utilizam como referência o registrador de segmento de pilha (SS).
Registrador ES:
É denominado Extra Segment (Segmento Extra). É uma opção extra para apontar a base de um segmento de dados (strings). Por exemplo, ele é utilizado juntamente com o DI para formar o endereço da base de strings de dados.
Apontador de Instrução: IP 
É denominado Instruction Pointer (Ponteiro de Instruções). Este registrador é atualizado pela BIU e contém a distância em bytes (offset) da próxima instrução em relação ao início do código que está sendo executado, isto é, ele aponta para a próxima instrução. Os programadores não têm acesso direto a esse registrador.
Registrador de FLAGS
O microprocessador 8086 contém em seu interior um total de 9 sinalizadores, também conhecidos como flags. Eles existem para indicar resultados obtidos sempre na última operação lógica ou aritmética executada, ou para definir o comportamento do microprocessador na execução de certas instruções. Estes 9 flags estão agrupados, para facilidade de acesso, em um registrador de 16 bits, chamado de Registrador de Flags, Registrador de Estado ou Palavra de Estado do Programa, sendo localizado na unidade EU. 
Como mostra a figura 2.0, ele utiliza bits para armazenar informações de estado (status) e de controle.
	15
	14
	13
	12
	11
	10
	9
	8
	7
	6
	5
	4
	3
	2
	1
	0
	-
	-
	-
	-
	OF
	DF
	IF
	TF
	SF
	ZF
	-
	AF
	-
	PF
	-
	CF
Figura 2.0 –Registrador dos Flags.
�
Flags de Estado:
Os bits de estado refletem certas propriedades de resultados de operações lógicas e aritméticas realizadas na EU, a qual é responsável por “setar” estes bits no registrador.
AF - Flag de Carry Auxiliar: indica o transporte para fora do nibble menos significativo - do bit 3 para o bit 4 - do resultado produzido pela ULA. É utilizado quando se manipula operandos representados em código BCD ou ASCII, ou seja, AF = 1 -> caso exista o "vai um" do bit 3 para o bit 4 de uma adição caso não exista "empréstimo" do bit 4 para o bit 3 numa subtração; AF = 0 -> caso contrário.
CF - Flag de Carry: CF = 1 -> após instruções de soma que geram "vai um" após instruções de subtração que não geram "empréstimo" ("empresta um"); CF = 0 -> caso contrário.
OF - Flag de Overflow: OF = 1 -> qualquer operação que produza overflow; OF = 0 -> caso contrário.
SF - Flag de Sinal: utilizado para indicar se o número resultado é positivo ou negativo em termos da aritmética em Complemento de 2 (se não ocorrer erro de transbordamento - overflow). SF = 1 -> número negativo SF = 0 -> número positivo.
ZF - Flag de Zero: ZF = 1 -> caso o resultado da última operação aritmética ou lógica seja igual a zero; ZF = 0 -> caso contrário.
PF - Flag de paridade: Este sinalizador é ativado, quando o número de 1s nos 8 bits menos significativos do resultado produzido pela ULA é par, e desativado caso contrário, ou seja PF = 1 -> caso o byte inferior do resultado de alguma operação aritmética ou lógica apresentar um número par de "1's"; PF = 0 -> caso contrário (número impar).
Flags de Controle
São os flags que podem ser setados pelos programas, alterando as operações do processador:
DF - Flag de Direção: Há instruções que envolvem os registradores de índice na formação do endereço efetivo dos operandos. Algumas destas instruções implicam na alteração do conteúdo do registrador de índice. Dependendo do conteúdo deste sinalizador, os registradores de índice serão incrementados ou decrementados automaticamente, quando tais instruções são executadas. DF = 1 -> decremento do endereço de memória (DOWN); DF = 0 -> incremento do endereço de memória (UP).
IF- Flag de Interrupção: este sinalizador determina, se o processador está habilitado ou desabilitado a atender interrupções. IF = 1 -> habilita a ocorrência de interrupções;IF = 0 -> inibe interrupções tipo INT externas.
TF - Flag de Trap (armadilha): TF = 1 -> após a execução da próxima instrução, ocorrerá uma interrupção; a própria interrupção faz TF = 0; TF = 0 -> caso contrário. 
�
Memória
Do ponto de vista do programador, a memória se comporta como um conjunto de endereços onde é possível “escrever” e “ler” informações. Cada locação, ou endereço é identificado por um número.
A memória pode ser vista como uma longa lista de endereços, ou como um agrupamento de endereços em blocos denominados páginas. Os dígitos mais significativos do endereço representam a página, e os dígitos menos significativos identificam a posição dentro da página, como por exemplo, a página 10 compreenderá os endereços de 1000 a 10FF. 
Com 16 bits para endereçamento é possível endereçar 216 = 64K locações. Para aumentar essa faixa de endereços pode-se estender o tamanho de palavra de endereço, ou utilizar técnicas de gerenciamento de memória. Os microprocessadores 8086/88 utilizam o gerenciamento de memória por segmentos.
	Durante a execução de um programa no 8086, há 4 segmentos ativos:
segmento de código: endereçado por CS
segmento de dados:endereçado por DS
segmento de pilha: endereçado por SS (stack segment)
segmento extra: endereçado por ES.
Gerenciamento de memória por segmentação:
O 8086 possui 20 bits para acessar posições de memória física o que corresponde a 220 = 1.048.576 bytes (1 Mbyte) de posições endereçáveis. Exemplos de endereços:
0000 0000 0000 0000 0000b -> 00000h
0000 0000 0000 0000 0001b -> 00001h
1111 1111 1111 1111 1111b -> FFFFFh
O 8086 opera internamente com 16 bits para gerar endereços com 20 bits ele utiliza a idéia de segmentação de memória.
Cada segmento de memória corresponde a um bloco de 64 Kbytes de posições de memória consecutivas, identificado por um número de segmento.
Para acessar um byte ou palavra particular na memória, é necessário um offset, ou seja, uma distância em bytes do início do segmento. O endereço real de memória de 20 bits é o resultado da soma de um registrador de segmento (deslocado de 4 bits para a esquerda) e um offset de 16 bits . O registrador de segmento e a fonte do offset dependem do tipo de referência à memória desejado:
	Tipo de Referência a Memória
	Segmento Default
	Segmento Alternativo
	Offset
	Busca de instrução
	CS
	nenhum
	IP
	Pilha
	SS
	Nenhum
	SP
	Variável
	DS
	CS,ES,SS
	Endereço efetivo
	String fonte
	DS
	CS,ES,SS
	SI
	String destino
	ES
	Nenhum
	DI
	BP como registrador base
	SS
	CS,ES,SS
	Endereço efetivo
Figura 3.0- Tipos de Referência a memória.
O endereço efetivo mencionado na tabelada figura 3.0 corresponde ao resultado da avaliação de um modo de endereçamento. Nos casos em que um segmento alternativo aparece na tabela, o segmento default pode ser substituído usando-se um prefixo de segmento.
A referência a uma posição de memória é dada por:
		reg_segmento : reg_offset
Por exemplo: CS:IP, SS:SP, DS:SI, DS:DI
Modos de Endereçamento
Os processadores 80x86 permitem acessar a memória de vários modos diferentes. Os modos de endereçamento de memória do 80x86 oferecem flexibilidade no acesso à memória, permitindo acessar facilmente variáveis, arrays, registros, ponteiros e outros tipos de dados mais complexos. 
Modo Registrador e Imediato
Registrador: os operandos fonte, destino ou ambos estão contidos em registradores. Exemplo: MOV CX, BX
Imediato: os dados em 8 ou 16 bits podem ser especificadoscomo parte da instrução. Exemplo: MOV CX, 24h 
Modo de Endereçamento de Memória
Direto: O endereço efetivo do operando (offset) no correspondente segmento é obtido diretamente a partir de um determinado dado, sem envolver quaisquer registradores. Exemplo:
	.DATA
	START DW 39FAH
	...
	MOV BX, START
Indireto registrador: O endereço efetivo de um operando na memória pode ser obtido a partir de um dos registradores de base ou índice. (BX, BP, SI,DI)
Baseado: O endereço efetivo é calculado a partir de uma constante e dos registradores de base BX ou BP. Quando não se excede à pilha o endereço de 20 bits é calculado a partir de DS:BX. Quando se excede à pilha esse endereço é calculado a partir de SS:BP.
Indexado: O endereço efetivo é obtido a partir de uma constante e dos registradores de índice SI u DI.
Indexado baseado: O endereço efetivo é calculado a partir de uma constante, dos registradores de base (BX, BP) e dos registradores de indice (SI, DI).
De strings: utiliza-se o registrador SI para apontar para o primeiro byte ou word de uma string origem e o registrador DI para apontar para o primeiro byte ou word do destino, quando é utilizada uma instrução para strings.
Linguagem Assembly�
O processador x8086 possui um grande conjunto de instruções, que podem ser divididas em: instruções de movimentação de dados, instruções aritméticas, instruções lógicas, instruções de manipulação de strings, instruções de desvio e controle de fluxo.
Aqui somente serão descritas as instruções do subconjunto formado para implementação nos simuladores�.
�
Introdução ao Projeto dos Simuladores
O projeto visa aprendizagem da arquitetura x8086. A implementação dos simuladores consiste em uma implementação simplificada da arquitetura do microprocessador 8086 com um subconjunto restrito de instruções assim como algumas funcionalidades básicas desta arquitetura. 
Após o estudo da arquitetura x8086 foi realizado um estudo do conjunto de instruções do processador e a maneira como este as decodifica�. Para tanto, definimos apenas o subconjunto de instruções formado pelas instruções: MOVE� (Im/Reg, Reg/Reg, Mem/Reg, Mem/Acum), ADD e LOOP. Na decodificação documentada já está apresentada também alguma relação com a programação dos simuladores.
O desenvolvimento do projeto foi divido em três etapas de implementação, visando facilitar a compreensão e organização da estrutura do simulador. Na primeira etapa, desenvolveu-se o simulador sem recurso de pipeline. Com base no funcionamento descrito no datasheet do x8086, criou-se o projeto para simular as unidades básicas de funcionamento do microprocessador estudado, sendo estruturadas rotinas para simular a unidade de memória (dividida em segmentos de dados, de código e de registradores, mas fisicamente uma unidade), a unidade de processamento lógico e aritmético (ula), a unidade de cálculo de endereços (somador), o banco de instruções� e unidade de execução (reconhecimento da instrução e busca de registradores ou informação da memória). Rotinas auxiliares foram implementadas devido à limitação da linguagem escolhida para montagem do simulador, tais como rotina para conversão de números hexadecimais para binários e de números binários para decimais. 
A figura 4.0 mostra o diagrama de blocos da arquitetura implementada nos simuladores. 
Figura 4.0 –Diagrama de Blocos da Arquitetura Interna Implementada na Simulação da Arquitetura 8086.�
 A segunda etapa do projeto consiste em, dado que a implementação da seqüência de rotinas para simular as etapas de processamento do x8086 para o conjunto de instruções mov reg/reg, mov regacum/memória, mov reg/imediato, mov reg/memória, add e loop estava correta, implementar as rotinas e controles que tornem possíveis as aplicações do recurso de pipeline para o simulador.
Decodificação das Instruções
As instruções do processador x8086 não apresentam tamanho fixo �(quantidade de bits de cada uma das instruções), variando de acordo com cada uma delas, assim como o número de bits que podemos considerar como opcode da instrução. 
Na decodificação das instruções é necessário conhecer o significado de alguns bits utilizados no formato da instrução. Segue abaixo a forma de decodificação:
MOVE
	Im/Reg, Reg/Reg, Mem/Reg , Mem/Acum
Im/Reg: move um imediato para um registrador.
Formato da instrução:
	7 0
	7 0
	7 0
	1 0 1 1 w reg
	data (parte baixa)
	data se w=1 (arte alta)
Reg é o código do registrador destino da operação.
Se w=1 significa que o valor do imediato esta ocupando 16 bits, se w=0 o imediato esta apenas ocupando a parte baixa do dados, isto é, somente 8 bits (instrução operando com word ou com byte).
O opcode da instrução move de imediato para registrador é definido pelos bits de 7-4 = B em hexa.
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8 
	9	16
	17 24�
	7 4
	3 0
	7 0
	 7 0
	1 0 1 1
	w reg
	 Data 
	Data se w=1
	B
	-
	-
	-
As posições dos bits: 1-4 = opcode , 5 = w, 6-8= Reg, dependendo de w o imediato pode estar de 9-16 ou 9-24,
Instrução de leitura da memória e escrita no banco de registradores.
�
Reg/Reg: move o conteúdo de um registrador para outro registrador.
Formato da instrução:
	7 0
	7 0 
	1 0 0 0 1 0 d w
	mod reg r/m 
W identifica instrução operando com Word se w=1 ou com byte w= 0.
D defini �a direção dos dados, no caso como a direção é de registrador para registrador este será sempre igual a zero.
Como operamos com dois regs, mod terá o valor 11 implicando no campo r/m ser um registrador.
Os bits de r/m simbolizam o registrador destino da operação sendo os bits de reg o registrador fonte.
Logo a identificação da instrução poderá ser feita por: 88 ou 89.
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8 
	9 12
	13 16
	7 6 5 4 
	3 2 1 0
	7 6 5 4
	3 2 1 0
	1 0 0 0
	1 0 d w
	mod reg
	reg r/m
	8
	8, se w=0
	11 x x
	x x x x
	
	9 se w =1
	
	
As posições dos bits: 1-8 = opcode, 8 = w, 11-13 = Reg, 14-16 = R/m.
Instrução de leitura e escrita no do banco de registradores.
Mem/Reg : move um valor da memória para um registrador.
Formato da instrução:
	7 0
	7 0 
	1 0 0 0 1 0 d w
	mod reg r/m 
W identifica instrução operando com word se w=1 ou com byte w= 0.
D defini a direção dos dados, no caso como a direção é de memoria para registrador este será sempre igual a um.
Reg é o registrador destino.
Logo a identificação da instrução poderá ser feita por: 8A ou 8B (considerando os bits 7-8).
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8
	9 12 
	13 16
	7 6 5 4 
	3 2 1 0
	7 6 5 4
	3 2 1 0
	1 0 0 0
	 1 0 d w
	Mod Reg
	Reg rm/m
	8
	B, se w=1
	
	
	
	A, se w=0
	
	
As posições dos bits: 1-8 = opcode, 8 = w,11-13 = Reg
Instrução de Leitura da memória e escrita no banco de registradores.
Mem/Acum: move um valor contido na memória para o registrador acumulador de 16nits Ax, ou acumulador 8 bits AH.
Formato da Instrução:
	7 0
	7 0 
	7 0
	1 0 1 0 0 0 0 w
	Addr-low
	Addr-high
W identifica instrução operando com Word se w=1 ou com byte w= 0.
Move da memória para o registrador Ax cumulador 16bits, ou AH acumulador8bits.
A identificação da instrução poderá ser feita por: A.
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8
	9 16
	17 24
	7 6 5 4
	 3 2 1 0
	7 6 5 4 3 2 1 0
	 7 6 5 4 3 2 1 0
	1 0 1 0
	 0 0 0 w
	Addr_low
	Addr_high
	A
	 0 0 0
	
	
As posições dos bits: 1-4 = opcode, 8= w, endereço da memória =
Ax ou AL = 000 = Reg
Instrução de leitura da memória e escrita no banco de registradores
ADD 
Reg/Reg: soma do conteúdo de dois registradores.
Formato da Instrução:
	7 0
	7 0 
	0 0 0 0 0 0 d w
	mod reg r/m 
W identifica instrução operando com Word se w=1 ou com byte w= 0.
D defini a direção dos dados, no caso como a direção é de registrador para registrador este será sempre igual a zero.
Como operamos com dois regs, mod terá o valor 11 implicando no campo r/m ser um registrador.
Os bits de r/m simbolizam o registrador destino da operação sendo os bits de reg o registrador fonte.
Logo a identificação da instrução poderá ser feita por : 01 ou 00.
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8
	9 10
	11 13
	14 16
	7 6 5 4
	3 2 1 0
	7 6
	5 4 3
	2 1 0
	0 0 0 0
	0 0 d w
	mod
	Reg
	R/m
	0
	 1, se w=1,
	
	
	
	
	0, se w=0
	
	
	
	
	
	
	
	
�
As posições dos bits: 1-8 = opcode, 8 = w, 11-13 = Reg, 14-16 = R/m.
Instrução de leitura e escrita no do banco de registradores.
LOOP
A instrução é um salto condicional, que testa o valor do registrador Cx, verificando se este é diferente de 0, se for executa o salto, caso contrário, não realiza o salto. Formato da instrução:
	7 0
	7 0
	1 1 1 0 0 0 1 0
	disp
Disp é o deslocamento que deve ser subtraído do endereço do IP para achar o endereço a partir do qual recomeça o laço. Este valor está representado em complemento de dois.
Logo a identificação da instrução poderá ser feita por:E2.
Para decodificação desta instrução nos simuladores utilizamos a contagem dos bits seqüencialmente iniciando em 1, formando a seguinte tabela:
	1 4
	5 8
	9 16
	7 6 5 4 
	3 2 1 0 
	7 6 5 4 3 2 1 0
	1 1 1 0
	0 0 1 0
	disp
	E
	2
	
	
As posições dos bits: 1-8 = opcode, 9-16 = deslocamento.
Exemplo de Fluxo de Instruções no Diagrama de Blocos
Para melhor compreensão do funcionamento da arquitetura, efetuamos o fluxo da instrução ADD no diagrama de blocos, conforme mostra a figura 5.0�.
Figura 5.0 – Execução da Instrução ADD
Inicialmente, a instrução ADD é lida da memória pela Unidade de Interface de Barramento (BIU). Em seguida, a Unidade de Execução (EU) decodifica a instrução e solicita a BIU os valores dos operandos. Por sua vez, a BIU retorna para a EU os valores lidos nos registradores. Depois a EU é novamente acionada para que a unidade ULA processe a operação de soma. Em seguida, a BIU transfere o valor da saída da ULA para o registrador destino. Durante esse processo a unidade sinais de controle está sendo atualizada. Toda a execução é sincronizada pelo Controle de Tempo (clock).
Sobre o arquivo teste
Para testar o funcionamento dos simuladores foi implementado o programa (arquivo programafunciona�.asm), em linguagem de montagem para o processador x8086, que executa a série de Fibonacci para os dez primeiros números da série, apresentando o valor do décimo número da série. No desenvolvimento do programa teste, foram avaliadas as instruções que poderiam ser utilizadas para esse execução, segundo o critério de opcode diferenciado o que facilitou a implementação das instruções mov reg/reg, mov reg/imm, mov mem/reg, mov mem/acumulador, add e loop. O código objeto do arquivo assembler �foi gerado no montador NASM em sistema operacional Linux, conforme consta no cabeçalho dos fontes dos simuladores.
�
Simuladores
Simulador da arquitetura 8086 – Sem Pipeline
Executando o programa
Após iniciar a execução do programa (duplo clique sobre o arquivo SimuladorSPipeline.exe), abrirá a tela do simulador conforme mostra a figura 6.0. No campo “Informe o caminho do arquivo (.lst), clique no botão de abrir, para que a janela de busca de arquivos seja aberta. Selecione e abra arquivo com extensão .lst gerado a partir de código programado em assembly no montador NASM.
Para abrir o arquivo teste busque por:
Diretório:\T1MarciaFederizzi_VanessaBorba\SimuladorSPipeline programafunciona.lst
Figura 6.0 – Simulador Sem Pipeline. Em destaque os botões de seleção de arquivo e execução do programa.
Observações: 
1 - Antes de abrir o arquivo .lst é necessário editá-lo linha a linha. A edição é referente ao caracter de quebra de linha, que no arquivo original não é o caracter padrão para enter. Nesse caso, ao final de cada linha tecle enter para marcar o final de linha no arquivo. Após abrir o arquivo, clique em Executar Programa para iniciar a simulação de processamento do x8086.
2 - O arquivo .lst deverá ser gerado no nasm, no sistema operacional Linux, através do comando: diretorio/nasm –f elf –l arquivo.lst arquivo.asm
Funcionamento
Inicialmente o sistema irá acessar o arquivo informado e carregá-lo, linha a linha, para a lista Seqüência e instruções do programa. Ao gravar as linhas nessa lista, o programa já está tratando e desconsiderando linhas em branco e possíveis comentários contidos no arquivo, por meio da rotina ArmazenaLinha. A rotina LeArquivoLST é responsável por gerenciar a leitura das linhas do arquivo e efetuar a chamada da rotina ArmazenaLinha. Essa lista é composta de duas colunas: índice e instrução. Sua montagem e exibição foram projetadas para facilitar o acompanhamento das instruções que serão processadas pelo simulador. Para tanto, a coluna índice que faz referência a cada linha de programa do arquivo, também será exibida nas listas especificadas abaixo:
Posição de Memória/Instrução: contém o programa no formato de código objeto permitindo acompanhar como cada linha do código em assembly foi montada para execução. O preenchimento dessa lista é implementado pela rotina CarregaMemoria que percorre o objeto Seqüência e instruções do programa e monta o que simularia o modo como o 8086 trata a memória, isto é, segmento de dados e segmento de código representados pela lista Posição de Memória/Instrução e a área de registradores de uso geral, representada pela lista Conteúdo dos registradores, mas que simbolizam serem fisicamente uma única memória�. Despreza a coluna de instruções escritas em assembly, montando apenas a coluna de índices (referência constante no simulador para a linha de processamento).
Processamento das Instruções: exibe a sequência de dados em cada registrador durante a execução do programa.
Conteúdo dos registradores: simula a área de registradores de uso geral, tendo os valores constantemente atualizados conforme seqüência do programa. Mostra o conteúdo dos registradores após o término do programa.
 
As rotinas de simulação da arquitetura 8086 começam a serem �executadas no instante em que o programa já foi carregado na memória (no simulador, após carregar a lista Posição de Memória Instrução).
As linhas de programa são processadas em série e somente após o término dos estágios de execução de uma instrução, o simulador reinicia a rotina buscando nova instrução. A busca é realizada até que a área de programa tenha sido executada por completo. 
A rotina ProcessaInstrucoes percorre a lista memória e gerencia o reconhecimento de cada instrução. Após identificar a instrução, por meio do opcode, o controle de processamento é passado para as rotinas de tratamento das instruções. Os métodos MovMemRe, MovRegReg,MovImedReg, MovMemAcum, Loop e Add implementam as instruções mov memoria/registrador, mov registrador/registrador, mov imediado/registrador, mov memoria/registrador acumulador, loop e add. Na implementação de cada um dos métodos citados, há a chamada para procedimentos que simulam a unidade de controle que executa a instrução e determina, conforme posicionamento das informações na instrução, o próximo passo de execução, isto é, busca de dado no registrador, na memória ou cálculo de endereços. Para essas três tarefas, a unidade lógica aritmética é acionada. Tal unidade está sendo representada no sistema pelas rotinas:
IdentRegistrador: função que recebe por parâmetro o código destinado para os registradores concatenado com o valor de w e retorna o registrador utilizado na instrução.
CalculaEndereco: responsável por efetuar cálculo do endereço de salto, a partir do endereço atual e do endereço efetivo passados na decodificação da instrução.
RetornaIP: função que retorna o IP calculado e informado na coluna de endereço da lista Posição de Memória/Instrução.
LeRegistrador: função que recebe o endereço do registrador e retorna o conteúdo referenciado pelo mesmo.
LocalizaDado: função que recebe um endereço da área de dados e retorna o conteúdo referenciado por esse endereço de memória.
ULA: função que representa a unidade aritmética, implementando as operações de soma e subtração. A unidade lógica, para comparação de valores, é implementada entre as rotinas listadas acima, como a de reconhecimento do registrador na instrução (IdentRegistrador).
Ao término da execução da instrução, ainda no procedimento ProcessaInstrucoes, a seqüência de processamento da instrução é inclusa na lista Processamento de Instruções.
Complementando as rotinas que representam as funcionalidades do processador, a função EscreveRegistrador, é utilizada pelas instruções que buscam dados na memória e armazenam em registradores. Seu funcionamento consiste em receber por parâmetro o endereço do registrador e o conteúdo (dado) e armazená-lo na posição de memória referenciada pelo registrador.
As linhas de programa são processadas em série e somente após o término dos estágios de execução de uma instrução, o simulador reinicia a rotina buscando nova instrução. A busca é realizada até que a área de programa tenha sido executada por completo. 
Devido a escolha por uma linguagem de programação que permitisse maiores recursos gráficos para a montagem do simulador, mas que não é projetada para manipular informações em binário e hexadecimal, foi necessário implementar algumas rotinas �para simular unidades já existentes em linguagens própria para programação de processadores. Abaixo serão listadas essas rotinas com descrição de sua funcionalidade.
HexaBin: função que recebe um caracter em hexadecimal e retorna seu valor em binário.
BinarioDecimal: função que recebe como parâmetro um valor binário e retorna o valor correpondente em decimal.
Expoente: função para elevar um número a qualquer expoente.
Rotinas implementadas apenas para a parte visual do simulador:
LimpaCampos: limpa os objetos na tela do simulador antes de iniciar nova execução do programa.
RegistraProcesso: inclusão das informações processadas na lista de Processamento das instruções.
Cálculo do CPI
Para auxiliar a visualização das vantagens do pipeline sobre a arquitetura, foi inclusa a rotina de cálculo de CPI (Ciclos por Instrução). Nesse simulador, em cada estágio da instrução foi incluso um contador para simbolizar a quantidade de ciclos gastos por instrução, já que na linguagem Delphi, não é possível ativar a rotina segundo um clock definido. Ao término da execução do simulador, é contabilizado o número total de instruções contidas no programa. O total de ciclos gastos é dividido pelo total de instruções executadas e resultado é informado no campo CPI.
�
Simulador da arquitetura 8086 – Com Pipeline
O Pipeline
É uma técnica de implementação de processadores que permite a sobreposição temporal de diversas fases da execução de instruções, sendo a base para implementação de técnicas que permitem aos processadores atuais, rodarem os programas mais rapidamente.
É valido ressaltar que o pipeline otimiza a performance do processador por meio do aumento do throughput das instruções, ou seja, aumentando o número de instruções executadas por unidade de tempo, e não por meio da diminuição do tempo de execução de cada instrução.
Conflitos do Pipeline
 A dificuldade de implementar o pipeline está na possibilidade de termos inconsistências ao processar instruções durante a execução de um programa, dependendo da seqüência de instruções do código. Tais conflitos, também chamados de hazards, podem ser tratados com a inclusão de unidades que permitam detectar antecipadamente o conflito e que insiram um tratamento durante o processo de pipeline, em meio à execução das instruções.
Os hazards são divididos em: estruturais, de controle e de dados. 
Hazards Estruturais
Ocorrem quando o hardware não pode suportar a combinação de instruções que o pipeline deseja executar no mesmo ciclo de clock. Exemplo: em uma arquitetura que possui uma memória para instruções e dados, não seria possível adiantar a leitura de uma instrução se uma instrução de leitura de dados estivesse sendo executada no mesmo ciclo de clock. No simulador x8086, a unidade de controle deverá testar o tipo de instrução antes de liberar sua execução para o próximo estágio. Caso a instrução não possa ser executada, a primeira tentativa de solução seria o adiantamento do resultado, caso esse também não fosse possível, a solução dada é a inclusão da instrução de Não Operante (NOP) para os estágios do pipeline, afim de que a instrução complete a parte do ciclo conflitante, para dar segmento ao estágio.�
Hazards de Controle
Origina-se da necessidade de se tomar uma decisão com base nos resultados de uma instrução, enquanto outras estão sendo executadas. Exemplo: instruções com salto condicional, loops. Para esses casos as soluções propostas dividem-se:
�
Parada ou Bolha: inserção de uma instrução NOP para que não haja “progresso” no processamento da informação enquanto o resultado da instrução anterior não estiver executado. Problema: essa solução embora seja mais fácil de implementar implica em perda da performance do processamento, pois o pipeline é eficiente após seu preenchimento total. Com a parada, há perda de ciclos e perde-se mais tempo para “encher” novamente o pipeline depois de interromper o progresso das instruções por intermédio do pipeline. Esse recurso é aplicável no simulador proposto nesse trabalho, pois embora não implemente instruções de desvio �condicional, há seqüências de instruções em que não será possível efetuar o adiantamento do resultado e para esses casos, o uso da bolha impede o conflito de dados.
Predição: hardware para “adivinhar” qual a próxima instrução a ser executada em caso de desvios condicionais (se salta para um dado endereço ou executa a instrução seguinte). Em geral os processadores adotam a predição para tratar os desvios condicionais executados em pipeline. Um esquema simples é sempre predizer que os desvios condicionais vão falhar. Estando certo, o pipeline prossegue na velocidade máxima. Se errado, há a necessidade de atrasar o avanço normal das instruções por meio do pipeline e garantir que as instruções já executadas não irão interferir no resultado correto. Esse recurso satisfaz o conflito que pode ocorrer com o uso da instrução loop. Pretende-se implementar uma lista de predição dinâmica em que os resultados das quatro primeiras ocorrências são armazenados e a média de ocorrência determinará a ação que deverá ser assumida para a próxima execução�. Em caso de erro da predição, inclusão de bolhas para limpar o pipeline, caso o resultado processado afete a seqüência do programa.
Hazards de Dados 
Ocorrem quando a execução de uma instrução depende do resultadode outra, que ainda está no pipeline. Exemplo: processar uma soma em que um dos operadores ainda não teve seu valor alterado pela instrução anterior, salvo no registrador.
Para solucionar esse conflito é necessária a inclusão de uma unidade que constantemente verifica os conteúdos dos registradores e os compara, para verificar se haverá algum conflito de dado em algum estágio. Para que essa unidade possa efetuar os testes, torna-se indispensável um conjunto de sinais de controle que deverá ser constantemente atualizado durante processamento das instruções de cada estágio. Ao efetuar comparações entre a ação indicada pelos sinais de controle (exemplo escrita/leitura da memória ou escrita/leitura de um registrador) e os endereços de memória e os dados apontados por cada instruções, em cada estágio do pipeline, é possível detectar que ocorrerá um conflito. Nesse instante, realiza-se um teste para verificar se é possível adiantar o resultado de algum estágio antes de ocorrer o processamento da instrução em que ocorreria o conflito. Em caso positivo, a unidade de adiantamento (Forwarding) irá buscar o resultado contido em um dos registradores (ou o caminho para encontrar o registrador e o dado) para inclusão como uma entrada para o processamento da instrução seguinte. Dessa forma, no exemplo da soma, os operandos seriam processados com os valores corretos antes mesmo do resultado da instrução anterior ter sido gravado no registrador destino. 
O simulador implementa esse conceito e o resultado adiantado é salvo nos registradores de estágio do pipeline para serem passados aos registradores manipulados nas instruções.
Executando o programa
Após iniciar a execução do programa (duplo clique sobre o arquivo SimuladorSPepiline.exe), abrirá a tela do simulador conforme mostra a figura 1.0. No campo “Informe o caminho do arquivo (.lst), clique no botão de abrir, para que a janela de busca de arquivos seja aberta. Selecione e abra arquivo com extensão .lst gerado a partir de código programado em assembly no montador NASM.
Para abrir o arquivo teste busque por:
Diretório\T1MarciaFederizzi_VanessaBorba\SimuladorSPipeline\programafunciona.lst
Observações: 
1 - Antes de abrir o arquivo .lst é necessário editá-lo linha a linha. A edição é referente ao caracter de quebra de linha, que no arquivo original não é o caracter padrão para enter. Nesse caso, ao final de cada linha tecle enter para marcar o final de linha no arquivo. Após abrir o arquivo, clique em Executar Programa para iniciar a simulação de processamento do x8086.
2 - O arquivo .lst deverá ser gerado no nasm, no sistema operacional Linux, através do comando: diretorio/nasm –f elf –l arquivo.lst arquivo.asm
Funcionamento
O simulador da arquitetura com pipeline possui uma interface parecida com a interface do simulador sem pipeline, como podemos ver na figura 5.0. Foram acrescentadas as listas Registradores do Pipeline e Estágios do Pipeline. As demais listagens existentes na implementação anterior permanecem com as mesmas funcionalidades, permitindo visualizar, ao final do programa, a seqüência de execução e os valores dos registradores nas listas Processamento das Instruções e Conteúdo dos registradores, respectivamente, para verificação da execução do programa fornecido para a arquitetura do simulador. Também as rotinas expostas em Simulador Sem Pipeline foram mantidas nesse projeto com Pipeline. 
Para implementação do pipeline foi necessário modificar a estrutura dos procedimentos: MovMemRe, MovRegReg, MovImedReg, MovMemAcum, Loop e Add. A alteração consiste em, para cada ciclo que a instrução em execução for processada, alguns dados de controle, tais como endereços de registradores, dado lido, endereço de memória, etc, devem ser armazenadas em registradores de controle do pipeline correspondente ao estágio de execução da instrução. Como a linguagem escolhida para desenvolver o simulador, não permite execução simultânea de rotinas, não é possível incluir, efetivamente, mais de uma instrução no mesmo ciclo de processamento. No entanto, montamos a estrutura analisando como seria implementado em uma linguagem sem essa restrição, conforme será efetuado na segunda etapa do projeto, quando o processador será implementado em linguagem VHDL, que permite paralelismo na execução de rotinas. Dessa forma, o pipeline foi projetado para ser implementado em cinco estágios, controlados por quatro registradores de pipeline IFID, IDEX, EXMEM, MEMWB. A seguir serão especificados cada estágio e informações passadas para cada registrador de controle.
Busca da Instrução (IF): estágio que efetua a leitura da instrução na memória usando para tanto o endereço armazenado em IP. A instrução e o IP incrementado são armazenados no registrador de controle IFID.
Decodificação da Instrução e leitura dos registradores de uso geral (ID): é responsável pela decodificação e leitura dos operandos, seja na memória ou no banco de registradores. Da parte inicial desse estágio, a informação de qual(is) o(s) endereço(s) do(s) registrador(es) utilizado(s) na instrução, já decodificado(s), é armazenada ainda no registrador IFID. 
Execução ou cálculo de endereço (EX): processa a instrução (executa). São guardados no registrador IDEX o endereço dos registradores origem e destino, se houver, os sinais que indicam se é escrita/leitura no banco de registrador, se é escrita/leitura na memória, o endereço do dado imediato não calculado e o IP incrementado.
Acesso à memória (ME): estágio reservado para escrita na memória. Armazena no registrador de controle EXMEM o registrador destino, os sinais de: escrita/leitura no banco de registrador, controle do desvio condicional, escrita/leitura da memória e o endereço calculado na ULA.
Escrita no banco de registradores (WB): processo de escrita no banco de registradores. Armazena no registrador MEMWB o registrador destino, os sinais de: escrita/leitura no banco de registrador, escrita/leitura da memória e o dado localizado que será armazenado.
Com base nas informações armazenadas nos registradores de estágios do pipeline, durante cada ciclo de execução das instruções, é possível testar esses valores e identificar se haverá conflitos de controle ou dados. 
O procedimento AtualizaEstagios é chamado a final da execução de cada ciclo da instrução para armazenar os dados conforme o estágio que a instrução está sendo processada. As informações armazenadas são visíveis no simulador, sendo os registradores de estágios representados pelas colunas da lista Registradores de Estágios. 
Durante a passagem do ciclo atual para o novo ciclo, além da atualização dos dados nos registradores é executada a chamada da rotina UnidadeDectHazard. Essa função implementa o funcionamento da unidade para detectação de hazards de dados e de controle, por meio de testes com os valores dos sinais de controle e endereços de registradores utilizados em cada instrução, informações essas contidas nos registradores de estágio do pipeline. Quando é possível tratar o hazard, a UnidadeDectHazard efetua a chamada da rotina de adiantamento (forwarding).
Forwarding: função que, conforme solicitação passada por parâmetro pela unidade de detecção de hazard, retorna o valor a ser adiantado para um registrador que irá utilizar essa informação, não disponível ainda pela instrução anterior, no estágio seguinte. 
Conforme mencionado anteriormente, não é possível executar essas funcionalidades em paralelo�. No entanto, para simular a progressão dos estágios conforme a entrada e saída de instruções no pipeline, foi implementada a rotina ExecutaInstrucoesPipe. Esse procedimento é disparado assim que o arquivo contendo as instruções do programa é inteiramente processado. Nesse instante, a lista Registradores do Pipeline que contém a seqüência de armazenamentos dos registradores do pipeline está completa. A partir dessa lista, a rotina ExecutaInstrucoesPipe simula a execução da entrada das instruções por ciclo, o que resulta, após o pipeline estar “cheio”,em cinco instruções sendo executadas em paralelo. Como resultado, o simulador apresenta a progressão de estágios na lista Estágios do Pipeline. Os estágios são simbolizados conforme sigla informada acima, entre parênteses, para descrição dos estágios do pipeline. Quando a unidade de detecção de hazard verificar que não é possível efetuar adiantamentos, a instrução NO (Não Operante) será informada para o(s) estágio(s) até que a informação do estágio anterior esteja disponível para o estágio que não está operante.
A interface alterada com a inclusão das novas listas para o simulador com pipeline pode ser visualizada na figura 7.0. 
Figura 7.0 – Simulador Com Pipeline.
Cálculo do CPI
É possível comparar o CPI do simulador sem pipeline com esse simulador em que o recurso está implementado. Ao executar o programa exemplo no simulador sem pipeline o tempo o CPI resultou em 3,97826086956522.
Executando o programa exemplo no simulador com pipeline esse valor foi reduzido para 1,17857142857143.
Para contabilizar o número de ciclos gastos no programa executado, a contagem passou a ser realizada ao final da rotina ExecutaInstrucoesPipe. Para tanto, o número de estágios na última linha da lista de Estágios do Pipeline é contado, e esse valor é dividido pelo total de instruções executadas. O resultado é informado no campo CPI.
Analisando os valores obtidos é possível notar que a diferença entre os CPI’s está elevada, se considerarmos o número de instruções executadas no programa exemplo. Mas é válido lembrar que para uma representação precisa dos CPI’s seria necessário um clock no sistema, o que não é possível implementar (limitação da linguagem utilizada para o simulador). Essa rotina foi implementada, com base nas rotinas que simulariam os ciclos, apenas para dar noção da diferença entre processadores com técnicas diferentes para execução de instruções.
Sinais de Controle�
Para gerenciar as informações sobre as unidades utilizadas durante a execução de uma instrução, bem como a ação executada, se haverá leitura ou escrita no banco de dados ou registradores, por exemplo, foi implementada a unidade de controle representada pela rotina AtualizaSinaisControle. O princípio de funcionamento dessa rotina consiste em inicializar os sinais de controle para gerenciamento de hazard, leitura e escrita de dados em registradores ou endereços de memória. A tabela 1.0 mostra a configuração de sinais passada para a unidade de controle conforme o estágio do pipeline e instrução executada. 
Tabela 1.0 - Conteúdo dos registradores do pipeline.
	Registrador do Pipeline
	Instrução
	Conteúdo (Sinais nos registradores)
	IDEX
	Geral
mov memreg
mov regreg
mov imedreg 
mov memacum
mov add 
loop 
	RegDest1+RegDest2
reg1vazio+reg2+rw=1(escreve)+rm='0'
reg1+reg2+rw=1(escreve)+rm=' '(inoperante)
reg1vazio+reg2+rw=1(escreve)+rm=' '(inoperante)
reg1vazio+reg2+rw=1(escreve)+rm='0'
reg1+reg2+rw=1(escreve)+rm=' '(inoperante)
reg1vazio+reg2+rw=1+rm=' '(inoperante)
	EXMEM
	Geral
mov memreg
mov regreg
mov imedreg 
mov memacum
mov add 
loop 
	RegDestEM+RWmem+RWReg+ DvC;
reg2+rw=1(escreve)+rm='0'+'0'(sem desvio)
reg2+rw=1(escreve)+rm=' '(inoperante)+ '0'(sem desvio)
reg2+rw=1(escreve)+rm=' '(inoperante)+'0'(sem desvio)
reg2+rw=1(escreve)+rm='0'+'0'(sem desvio)
reg2+rw=1(escreve)+rm=' '(inoperante)+ '0'(sem desvio)
reg2+rw=1+rm=' '(inoperante)+ '1'(com desvio)
	MEMWB
	Geral
mov memreg
mov regreg
mov imedreg 
mov memacum
mov add 
loop 
	RegDestMW+RW+ MemULaReg;
reg2+rw = 1(escreve)+rm='0'
reg2+rw = 1(escreve)+rm=' '(inoperante)
reg2+rw = 1(escreve)+rm=' '(inoperante)
reg2+rw = 1(escreve)+rm='0'
reg2+rw = 1(escreve)+rm=' '(inoperante)
reg2+rw = 1+rm=' '(inoperante)
�
Abaixo serão especificados os sinais utilizados pela unidade de controle, com respectiva ordenação de preenchimento e número de posições ocupadas (caracteres) por cada sinal:
SinaisIFID: é um vetor contendo o conjunto de posições que representam os registradores origem (RegDest1 – 3 posições) e destino (RegDest2 – 3 posições) da instrução, armazenados em ordem da esquerda para a direita.
SinaisIFID[RegDest1+RegDest2]
 
SinaisIDEX: do estágio ID em diante faz necessário controlar as ações que a instrução, já identificada irá executar na seqüência do pipeline. Para tanto, esse vetor contém os sinais em seqüência, da esquerda para a direita, que identificam o registrador origem (RegDestIE – 3 posições), registrador destinto (RegDestIE2 – 3 posições), sinal de que comanda a leitura/escrita no banco de registradores - RWReg (0 - Ler/1 – Escrever; 1 posição) e por fim, o registrador que comanda leitura/escrita na memória - RwMem(0 - Ler/1 – Escreve; 1 posição).
SinaisIDEX[RegDestIE+RegDestIE2+RWReg+RwMem]
SinaisEXMEM: vetor composto pelos sinais de registrador destinto (RegDestEM – 3 posições), controle se executa desvio condicional (0 – sem desvio/ 1 – com desvio, 1 posição), sinal de que comanda a leitura/escrita no banco de registradores - RWReg (0 - Ler/1 – Escrever; 1 posição) e o registrador que comanda leitura/escrita na memória - RwMem(0 - Ler/1 – Escreve; 1 posição).
SinaisEXMEM[RegDestEM+DvC+RWmem+RWReg]
SinaisMEMWB: vetor composto dos sinais de registrador destinto (RegDestMW – 3 posições), de controle para verificar se o dado é fornecido a partir da saída da ULA ou da memória de dados - MemULaReg (0 – Dado da memória/1 – Dado da ULA – 1 posição) e o sinal de que comanda se é escrita no banco de registradores ou na memória - RW(0 – Escreve na memória/ 1 - Escreve no banco de registradores).
SinaisMEMWB:= RegDestMW+MemULaReg+RW;
�
Conclusão
Com o projeto dos simuladores da arquitetura do processador x8086 podemos adquirir um conhecimento mais amplo sobre seu funcionamento o que implica numa maior facilidade de desenvolvê-lo em uma linguagem que atenda as necessidades de simultaneidade para implementação da arquitetura, principalmente com o uso da técnica de implementação Pipeline. No projeto dos simuladores não foi implementada uma arquitetura completa, mas apenas as suas unidades básicas e necessárias para a execução do subconjunto de instruções definido. No entanto, foi o suficiente para que conseguíssemos identificar as principais diferenças, vantagens e desvantagens, entre arquiteturas que implementam e que não implementam a técnica de pipeline.
Para a segunda parte do trabalho, com implementação em linguagem VHDL, serão necessárias modificações, pois o código será adaptado de uma execução não paralela para uma execução paralela. Isso implica, entre outras modificações, em alterar a forma de representação das unidades da arquitetura, pois no simulador, foram utilizados recursos próprios da linguagem Delphi para representar as estruturas físicas da arquitetura de forma simplificada. Para a nova implementação do projeto, que visa o desenvolvimento em uma linguagem própria para descrição de hardware, VHDL, tem-se a visão de que, os resultados serão mais satisfatórios do que a realizada em uma linguagem mais limitada referente à simulação de funcionamento de um hardware.
�
Referências Bibliográficas�
http://www.ee.pucrs.br/~dbarros/d2005_1/Microproc/Grupo_5/t1-microprocessadores.pdf
http://www.dee.ufcg.edu.br/~scaico/facisa/oac/8086-8088_(slides).pdf
http://pessoal.utfpr.edu.br/gustavo/asm8086.pdf
htttp://pessoal.utfpr.edu.br/gustavo/modos%20de%20enderecamento.doc
http://www.dee.ufcg.edu.br/~scaico/facisa/
http://infobase.2it.com.br/upload/y9ydu2mbh5_obclm_ee_cap3.pdf
http://www.ppgia.pucpr.br/~santin/cc/2007/1/arquitetura.html
http://www.ppgia.pucpr.br/~santin/cc/
Organização e Projetos de Computadores: A Interface Hardware/Software – John L. Henessy, David A. Patterson, James R. Larus 2ª Editora LTC, Rio de Janeiro, cap.6 – Pipeline.
�A arquiteturanão é conhecida por essa notação. Daria para utiliza 80x86 (onde o x representa 1, 2, 3 ou 4: 80186, 80286, 80386, 80486), ou apenas x86 (sem o 80 na frente). Porém, como no trabalho a ênfase é no 8086, sugiro remover o ‘x’ da frente do 8086 em todo o texto.
�Códigos binários do 8086/8088 executam perfeitamente nos processadores mais recentes – total compatibilidade.
�??
�Porém, o 8086 é uma arquitetura de 16 bits, com um barramento de dados de 16 bits, podendo ler e escrever palavras inteiras de 16 bits na memória, sem precisar realizar acessos byte a byte.
�Acho que algo tipo “local para armazenamento” ficaria melhor.
�Essa seção do texto parece um pouco incompleta. Não deveria conter alguma explicação sobre a linguagem assembly do 8086?
�Sugestão: alterar para “da arqitetura proposta nesse trabalho”.
�“e executa”
�MOV, sem o ‘E’.
�??
�Substituir por “apresentam um tamanho variado”
�Padronizar e melhorar a representação das tabelas. Por exemplo, ao incluir essa linha nessa tabela, procurar fazer o mesmo em todas. Informar logo no início, antes de apresentar a primeira tabela, como todas as tabelas estão organizadas (ex. a primeira linha mostra a identificação dos bits na seqüência utilizada pelo simulador. A segunda linha ...). 
�define
�Porquê 5.0? Poderia ser apenas 5.
�Alterar o nome para algo mais intuitivo: fib10.asm, fibonacci.asm
�assembly
�Essa frase ficou um pouco longo e confusa (“simularia”? “simbolizam semrem”?
�ser
�Poderiam ter aproveitado e implementado também a rotina “unix2dos” (ou algo do gênero) para realizar a conversão do “salto de linha”no arquivo texto de entrada.
�Qual a relação entre essa explicação e o título da seção “hazards estruturais”.
�... não implemente, AINDA, ...
�Será que apenas quatro ocorrências são suficientes para se chegar a uma conlcusão sobre mudar ou não o tipo de previsão?
�Usando threads daria para dar uma “simulada” em um paralelismo real. Deve existir alguma classe Thread em Delphi.
�Nessa seção poderiam ter, também, uma tabela resumo contendo os valores para cada um dos bits a serem usados como sinais de controle. Algo tipo o que foi visto em aula para controle do pipeline do MIPS. Mostrei algumas tabelas do livro do Patterson com os nomes dos sinais de controles, e os valores a serem utilizados conforme o tipo de instrução. Seria muito complicado montar tal tabela resumo?
�Nas referências, normalmente, procura-se evitar a utilização de sites web. O motivo é que não se sabe se o site ainda estará no ar daqui algum tempo, quando alguém estiver consultado o trabalho de vocês. Poderiam ter colocado, pelo menos, uma referência a um livro do 8086.
�PAGE �
�PAGE �1�

Outros materiais