. . . . . . . . . .
... ...
... .
Universidade Federal de Pernambuco
Centro de Informática – Cin
Processador MIPS
Projeto de Infra-Estrutura de
Hardware
. . . . . . . . . .
... ...
... .
Lista de Autores...5
Introdução...6
Objetivos...6
Especificações do Sistema...7
Formato 1...8
Modelo da instrução F1...8
Representação da instrução F1...8
Formato 2...9
Modelo da instrução F2...9
Representação da instrução F2...10
Formato 3...10
Modelo da instrução F3...10
Representação da instrução F3...11
Dispositivos Oferecidos...12
ULA...12
Banco de Registradores...13
Registrador de 32 bits...13
Memória...13
Shift N... 17
Mult / Div...18
Memory Data Register...18
PreStore...19
Desloc Const...19
Unidade de Controle...19
Notas de Design...21
Diagrama de Fluxo...21
Máquina de Estados...21
Simulação...23
Simulação de Exceções...25
Tratamento de Exceções...32
controlunit.vhd...35
desloc_const...53
ex_adr_sel...53
extensao_sinal.vhd...53
instr_reg.vhd...54
mdr.vhd...55
multidiv.vhd...57
prestore.vhd...62
processor.vhd...63
sel_ld_pc.vhd...83
shift_left.vhd...83
shift_left_26bits.vhd...83
shiftleft2.vhd...84
shiftn.vhd...84
banco_reg.vhd...86
memoria.vhd...90
registrador.vhd...97
Ula32.vhd...98
mux21_4bits.vhd...103
mux21_32bits.vhd...103
mux31_32bits_adr.vhd...103
mux41_5bits.vhd...104
mux41_28bits.vhd...104
mux41_32.vhd...105
mux41_32bitsnor.vhd...105
mux81.vhd...106
mux81_pc.vhd...107
Lista de Autores
Allan Diego Silva Lima
Curso de Ciência da Computação – CIn/UFPE [email protected]
Cléviton Vinicius Fonseca Monteiro
Curso de Ciência da Computação – CIn/UFPE [email protected]
Jobson Ronam Jerônimo Silva
Curso de Ciência da Computação – CIn/UFPE [email protected]
Osmany Barros de Freitas
Curso de Ciência da Computação – CIn/UFPE [email protected]
Paulo Henrique Padovan
Curso de Ciência da Computação – CIn/UFPE
[email protected]
Definições do Projeto
“... a melhor oportunidade para dominar o funcionamento e
implementação da arquitetura RISC e do processador MIPS...”.
Introdução
Com o objetivo aprimorar o ensino da disciplina de Infra-Estrutura de Hardware e levar o aluno à prática do conteúdo trabalhado em sala de aula, a Dra. Edna Barros, do Centro de Informática da Universidade Federal de Pernambuco, aplica semestralmente o projeto de implementação de um subconjunto de instruções do núcleo básico do MIPS.
Por ser uma arquitetura RISC (Reduced Instruction Set Computer) o MIPS, oriundo de um projeto da Universidade de Stanford, se caracteriza pela simplicidade de sua arquitetura interna, podendo ser implementado com o estado da arte em tecnologia e com menor gasto de área. Isto implica em uma relação custo/desempenho bem melhor que a dos microprocessadores convencionais, que consomem mais área e, devido à complexidade de projeto, não conseguem acompanhar o último passo em termos de tecnologia de fabricação.
Tendo em vista suas aplicações comerciais (principalmente em sistemas embarcados) e na adequação à didática de microprocessadores, este projeto constitui a melhor oportunidade para dominar o funcionamento e implementação da arquitetura RISC e do processador MIPS oferecida ao aluno de graduação em Ciência e Engenharia da Computação.
Objetivos
Vamos projetar uma implementação que inclui um subconjunto das instruções do núcleo básico do
MIPS. Esse conjunto não inclui todas as instruções inteiras nem quaisquer das instruções de ponto
flutuante. No entanto, todos os princípios fundamentais do projeto de um caminho de dados e de uma
unidade de controle são trabalhados nesse projeto.
Especificações
Especificações do Sistema
A arquitetura proposta trabalha através da manipulação direta de registradores. Possuindo 32 registradores de propósito geral, cada um de 32 bits, nosso processador possui um conjunto de 34 instruções, veja tabela 1, cada uma de 32 bits e apresentam-se sob três formas distintas.
Instrução Opcode Funct Descrição
nop 000000 000000 No operation (todos os outros campos são zero).
lw reg,
desl(reg_base) 100011 Carrega palavra localizada a partir do endereço dado por (reg_base + desl) no registrador reg.
sw reg,
desl(reg_base) 101011 Escreve registrador reg a partir do endereço de memória dado por (reg_base + desl).
lb reg,
desl(reg_base) 100000 Carrega byte localizado no endereço dado por (reg_base + desl) no byte menos significativo do registrador reg. O sinal deve ser extendido.
lh reg,
desl(reg_base) 100001 Carrega meia palavra localizada a partir do endereço (reg_base + desl) na parte menos significativa do registrador reg. O sinal deve ser extendido.
sb reg,
desl(reg_base) 101000 Escreve byte menos significativo do registrador reg no endereço de memória dado por (reg_base + desl). Somente um byte é escrito na memória.
sh reg,
desl(reg_base) 101001
Escreve meia palavra menos significativa do registrador reg a partir do endereço de memória dado por (reg_base + desl). Somente dois bytes são escritos na memória.
lui reg, constante 001111 Carrega constante na parte mais significativa do registrador reg = constante, os demais bits são iguais a zero.
mfhi rd 000000 010000 Carrega reg hi para rd.
mflo rd 000000 010010 Carrega reg lo para rd.
add regi, regj, regk 000000 100000 regi = regj + regk (com overflow).
addi regi, regj, cte 001000 regi = regj + cte (com overflow).
sub regi, regj, regk 000000 100010 regi = regj – regk (com underflow).
addu regi, regj,
regk 000000 100001 regi = regj + regk (sem overflow).
addiu regi, regj,
cte 001001 regi = regj + cte.
subu regi, regj,
regk 000000 100011 regi = regj – regk.
and regi, regj, regk 000000 100100 regi = regj and regk.
andi regi, regj, cte 001101 regi = regj and cte.
xor regi, regj, regk 000000 100110 regi = regj xor regk.
xori regi, regj, cte 001110 regi = regj xor cte.
divisão
sra regd, regs, n 000000 000011 Desloca registrador regs para a direita n vezes (aritmético) e armazena o valor deslocado no registrador regd.
srlregd, regs, n 000000 000010 Desloca registrador regs para a esquerda n vezes (lógico) e armazena o valor deslocado no registrador regd.
sll regd, regs, n 000000 000000 Desloca registrador regs para a esquerda n vezes e armazena o valor deslocado no registrador regd.
beq regi, regj, desl 000100 PC = PC + (desl * 4) se regi == regj.
bne regi, regj, desl 000101 PC = PC + (desl * 4) se regi <> regj.
slt regi, regj, regk 000000 101010 regi = 1 se regj < regk, senão regi = 0.
slti regi, regj, cte 001010 regi = 1 se regj < cte, senão regi = 0.
j end 000010 Desvio para end (PC = end).
jr regi 000000 001000 PC = regi.
jal end 000011 $31 = PC; PC = end.
ret 010000 010000 Retorno de exceção
break 000000 001101 Pára a execução do programa.
Tabela 1: Repertório de Instruções.
As instruções descritas na tabela estão classificadas em três tipos de formatos reconhecidos pela Unidade de Controle
Formato 1
Instruções aritméticas (add e sub), lógicas (xor e and), comparativas (stl – set less than), deslocamento (sra e sll) e jr (jump register).
Modelo da instrução F1
Opcode RS1 RS2 RD Count Funct
6 bits 5 bits 5 bits 5 bits 5 bits 6 bits
Representação da instrução F1
Instruções aritméticas, lógicas e SLT (Set Less Than).
Opcode
Especifica o código da instrução a ser executada. Em caso de opcodes idênticos, o Controle prepara o mesmo comportamento para essas instruções modificando, então, apenas as
Instruções de deslocamento Opcode Especifica o código da instrução a ser executada.
RS1 Informa o registrador que contém o valor a ser deslocado.
RS2 Informa o registrador que conterem o resultado do deslocamento.
RD Não é utilizado nesse formato.
Count É aquele onde está a quantidade de vezes que será realizado um shift (left ou right).
Funct Diferencia as instruções dentro do seu formato (F1).
Instruções de jump register Opcode Especifica o código instrução que será efetuada.
RS1 Informa qual o registrador que contém o valor que será armazenado em PC.
RS2 Informam os dois registradores que devem ser lidos ou sobre os quais uma operação lógica, aritmética ou um SLT será executada.
RD Especifica o registrador de destino, que armazenará o resultado de uma operação realizada.
Count Não é utilizado nesse formato.
Funct Diferencia as instruções dentro do seu formato (F1).
As instruções de multiplicação e divisão possuem o formato F1 e permitem a multiplicação ou divisão dos registradores rs e rt. O resultado é
armazenado em dois registradores internos hi e lo. Para permitir a leitura de tais registradores existem as instruções mfhi e mflo, responsáveis pelo carregamento do registrador hi ou lo no registrador rd, respectivamente.
As instruções mfhi e mflo possuem formato F1. A instrução de divisão realiza a operação entre os valores armazenados em rs e rt e armazena o quociente no registrador interno mflo, o resto da divisão fica armazenado no registrador mfhi..
Formato 2
Instruções de acesso à memória (lw, sw, lb, sb, lh e sh) e as de desvio condicional (beq e bne).
Instruções, addi, andi, xori e slti, as instruções aritméticas, lógicas e a de comparação onde um dos operadores é uma constante.
Instrução lui (load upper immediate), que carrega uma constante em um registrador.
Modelo da instrução F2
Opcode RB RD Deslocamento 6 bits 5 bits 5 bits 16 bits
Representação da instrução F2
RB Especifica o registrador base, que é somado ao deslocamento para o cálculo do endereço onde será lido.
RD Especifica o registrador de destino, que armazenará o conteúdo do endereço de memória fornecido pelo registrador base mais o deslocamento.
Deslocamento Constante que será somada ao registrador base para o cálculo do endereço.
Instruções de Store Opcode Especifica o código da instrução a ser executada.
RB Especifica o registrador base, que é somado ao deslocamento para o cálculo do endereço onde será escrito.
RD Especifica o registrador de destino, que armazenará o conteúdo que será armazenado na memória
Deslocamento Constante que será somada ao registrador base para o cálculo do endereço.
instruções aritméticas, lógicas e a de comparação onde um dos operandos é uma constante Opcode Especifica o código da instrução a ser executada.
RB Registrador que contém um dos valores utilizado na operação que será realizada pela ULA.
RD Indica o registrador no qual será colocado o resultado da operação.
Deslocamento Possui o valor da constante a ser operada.
Instrução lui Opcode Especifica o código da instrução a ser executada.
RB Registrador no qual é carregado o valor da constante.
RD
Não é
utilizadonessa instrução
.Deslocamento Registrador onde será carregado o valor da constante na sua parte mais significativa, sendo os demais bits iguais a zero.
Instruções de desvio condicional Opcode Especifica o código da instrução a ser executada.
RB 1º registrador a ser comparado.
RD 2º registrador a ser comparado.
Deslocamento
No caso da instrução beq, esse vetor de bits indica para qual instrução o PC deve pular. No caso da instrução bne, o mesmo vai ocorrer, de forma que os conteúdos dos registradores são diferentes.
Formato 3
Instruções de jump (j, jal)
Instruções de jump and link Opcode Especifica o código da instrução a ser executada.
Endereço
Contém o valor de memória (endereço é absoluto) para o qual a execução do programa é desviada. O endereço da instrução seguinte é armazenado num registrador para que o programa possa retornar à execução após terminar a rotina especificada no jal sendo o valor do PC guardado no R31.
Dispositivos Internos
Dispositivos Oferecidos
Lista dos componentes oferecidos para o desenvolvimento do projeto que foram utilizados no mesmo.
ULA
A Unidade Aritmética e Lógica (UAL) é um circuito combinacional com:
2 entradas de dados de 32bits
1 entrada de controle F de 3bits
1 saída de dados de 32bits
6 saídas de 1bit (flags)
Flag Função
A B
S
N Z EQ O GT LT
ALU 32 32
32
Z Zero
N Negativo
O Overflow
EQ Equal
LT Less Than
GT Greater Than
Figura 1: ALU.
A UAL permite a operação com números de 32 bits na notação complemento a dois. A funcionalidade é especificada pela entrada F conforme descrito na tabela abaixo.
F Operação Descrição Flags Afetados
000 S = A A Z,N
S = A + B Soma Z,N,O
Banco de Registradores
O banco de registradores é composto por 32 registradores de 32 bits cada. Dois registradores podem ser visíveis simultaneamente e carregados nos registradores A e B. A leitura dos registradores é combinacional, isto é, se os valores nas entradas ReadRegister1 ou ReadRegister 2 forem alteradas, os valores nas saídas ReadData1 ou ReadData2 podem ser alterados. O registrador a ser escrito é selecionado pela entrada WriteRegister e quando a entrada RegWrite é ativada (igual a 1) o registrador selecionado recebe o conteúdo da entrada WriteData. O sinal de reset limpa todos os registradores e é assíncrono. Os registradores A e B também possuem reset. Este componente deve ser descrito no domínio comportamental.
Figura 2: Banco de Registradores.
Registrador de 32 bits
Para armazenar instruções e dados, bem como os endereços das instruções serão utilizados registradores de 32 bits, conforme ilustrado na figura abaixo.
Reg8
load clock
clear
Reg32
load clock
clear
Figura 3: Registrador de 32 bits.
Memória
A memória usada no projeto possuir palavras de 32 bits com endereçamento por byte. Apesar de o endereço possuir 32 bits, a memória só possui 256 bytes.
ram8
add
Data_in
Data_out
clock
wr
Ram32
add
Data_in
Data_out
clock
wr Instruction
Registers Write
register
data 1Read
data 2Read Readregister 1
Readregister 2
Write data
RegWrite Instruction
Registers Write
register
data 1Read
data 2Read Readregister 1
Readregister 2
Write data
RegWrite
Entradas e Saídas da Memória
Memória Entradas
Data_In 32 bits Entrada de Dados da memória.
Add 32 bits O endereço de entrada da memória.
Wr 1 bit Seleciona entre ler (0) ou escrever (1).
Clock 1 bit Comum a todo computador síncrono.
Saída
Data_out 32 bits Saída de dados da memória.
Peculiaridades da Memória
1. Enquanto o bit "wr" estiver com o valor zero (0) ele está lendo, quando estiver com o valor um (1) ele estará escrevendo.
2. A memória está trigada na subida do clock.
3. Ao se fazer uma requisição de leitura, o valor pedido só estará disponível dois ciclos de clock após o clock onde foi feito a requisição.
4. A escrita leva um ciclo.
Dispositivos Adicionais
Lista dos componentes extras que foram adicionados durante o desenvolvimento do projeto e que fazem parte do mesmo.
PC - Program Counter
O PC (Program Counter) é um registrador de 32 bits com:
Program Counter Entradas
PCWriteCond 1 bit Grava PC em condições de jump
PCWrite 1 bit Grava PC
PCReset 1 bit Reseta PC
PC_in 32 bits Novo valor a ser carregado Saída
PC_out 32 bits Endereço da instrução a ser executada.
O PC grava o endereço da próxima instrução a ser executada.
Instruction Register
Registrador de 32 bits que tem a função de armazenar o vetor que contém a palavra oriunda da memória.
Instruction Register Entradas
Clk 1 bit Clock do sistema.
Reset 1 bit Reset.
Load_ir 1 bit Ativa a carga do registrador de instruções.
Entrada 32 bits Instrução a ser carregada.
Saídas
Instr31_26 16 bits Bits 31 a 26 da instrução.
Instr25_21 5 bits Bits 25 a 21 da instrução.
Instr20_16 5 bits Bits 20 a 16 da instrução.
Instr15_0 6 bits Bits 15 a 0 da instrução.
EPC - Exception Program Counter
Registrador de 32 bits que tem a função de armazenar o valor do PC que gerou a exceção.
Veja também o tópico referente a exceções
Entradas
EPCLoad 1 bit Carrega o EPC EPCReset 1 bit Reseta o EPC
EPC_in 32 bits Endereço da instrução que gerou a exceção.
Saída
EPC_out 32 bits Novo endereço da instrução que gerou a exceção
Signal Extend
Elemento lógico que tem a função de estender o vetor de entrada de 16 para 32 bits.
Signal Extend Entradas
entrada 16 bits Vetor de 16 bits Saída
saída 32 bits Vetor de 32 bits estendido
Shift Left 2
Deslocamento lógico à esquerda. Têm por função de deslocar o vetor passado como entrada duas vezes para a esquerda.
Shift Left 2 Entradas
Entrada 32 bits Vetor de 32 bits Saída
saída 32 bits Vetor deslocado 2 vezes para a esquerda
ALU Out
Registrador de deslocamento que tem a função de armazenar o resultado de saída da ULA.
HI Entradas
Sys_clk 1 bit Clock do Sistema rset_HiLo 1 bit Reseta o HI e o LO
ld_HiLo 1 bit Carrega o HI e o LO
HI_in 32 bits Recebe o resultado da multiplicação ou divisão Saída
HI_out 32 bits Fornece o resultado da multiplicação ou divisão
O HI armazena o resto (no caso da divisão) ou os 32 primeiros bits (canônico) do produto (no caso da multiplicação)
LO
O LO é um registrador de 32 bits com:
LO Entradas
Sys_clk 1 bit Clock do Sistema rset_HiLo 1 bit Reseta o HI e o LO
ld_HiLo 1 bit Carrega o HI e o LO
HI_in 32 bits Recebe o resultado da multiplicação ou divisão Saída
HI_out 32 bits Fornece o resultado da multiplicação ou divisão
O LO armazena o quociente (no caso da divisão) ou os 32 últimos bits (canônico) do produto (no caso da multiplicação)
Shift N
Deslocamento lógico ou aritmético à esquerda. Têm por função de deslocar o vetor passado como entrada n vezes para a esquerda.
Shift N Entradas
Seleção 1 bit Seleção
N 5 bits Parâmetro que indica o número de vezes (entre zero e 32.) que a entrada deve ser deslocada.
Entrada 32 bits Vetor de 32 bits Saída
Saída 32 bits Vetor deslocado n vezes para a esquerda
Mult / Div
O Mult/Div é um circuito síncrono com:
clk 1 bit Clock do sistema
start 1 bit Ativa (1) ou Desativa (0) o dispositivo seleção 1 bit Seleciona entre Multiplicar (0) ou Dividir (1) entrada1 32 bits 1ª parcela
entrada2 32 bits 2ª parcela Saídas
HI 32 bits Armazena o resto (no caso da divisão) ou os 32 primeiros bits (canônico) do produto (no caso da multiplicação).
LO 32 bits Armazena o quociente (no caso da divisão) ou os 32 últimos bits (canônico) do produto (no caso da multiplicação).
divZero 1 bit Indica se houve divisão por zero.
terminou 1 bit Indica se a operação foi concluída.
O Mult/Div permite a operação com números de 32 bits na notação complemento a dois.
Para efetuarmos uma multiplicação fazemos à seleção igual à zero (0). O resultado é armazenado em HI (32 primeiros bits) e LO (32 últimos bits) e o flag terminou passa a ser um (1).
Para efetuarmos uma divisão fazemos à seleção igual a um (1). O quociente é armazenado em LO e o resto em HI e o flag terminou passa a ser um (1).
Memory Data Register
Entidade responsável pelo deslocamento de um vetor de 32 bits para a direita estendendo o sinal.
Memory Data Register Entradas
Clk 1 bit Clock do sistema
reset 1 bit Reset
load 1 bit Ativa o carregamento
N 2 bits Código / Deslocamento 00 0 01 8 10 16 11 24
entrada 32 bits Vetor a ser deslocado Saída
saida 32 bits Vetor deslocado
Saída
saida 32 bits Saída para memória
Desloc Const
Recebe uma constante de 16 bits e entrega um vetor de 32 bits com os 16 primeiros bits iguais à zero.
Desloc Const Entradas
entrada 16 bits Constante Saída
saída 32 bits Vetor com 32 bits que possui a constante
Unidade de Controle
Entidade responsável pela interpretação das instruções e pelo comando na execução das mesmas, através do envio de sinais de controle às unidades da central de processamento.
Memory Data Register Entradas
Clock 1 bit O relógio do processador Reset 1 bit Reseta a unidade de controle
Overflow 1 bit Flag da ULA que indica overflow da ULA Negativo 1 bit Sinaliza quando for negativo
Zero 1 bit Sinaliza quando S for zero Igual 1 bit Sinaliza se A = B Maior 1 bit Sinaliza se A > B Menor 1 bit Sinaliza se A < B
MultDivFinished 1 bit Indica o término da operação de multiplicação ou divisão DivByZero 1 bit Indica se exceção divByZero ocorreu
instruction 32 bits A instrução que irá ser analisada pela unidade de controle Saídas
MemoryIO 1 bit Indica se a memória será escrita (1) ou lida (0) IRWrite 1 bit Indica se uma nova instrução será decodificada ou não
reset_Bank 1 bit Indica a operação a ser realizada pelo banco de registradores leitura (0) escrita (1) RegWrite 1 bit Indica a operação a ser realizada pelo banco de registradores leitura (0) escrita (1) MultDivStart 1 bit Inicia a operação
MultDiv 1 bit Seleciona a multiplicação ou divisão
ALUSrcA 1 bit Controlam os Multiplexadores das entradas de ALU PCSource 1 bit Controla o valor a ser carregado no PC
IorD 1 bit Controla o multiplexador que seleciona o endereço de memória a ser lido ou escrito RegDst 1 bit Seleciona o registrador a ser gravado no banco de registradores
EXCode 1 bit Seleciona o multiplexador que possui constantes usadas no SLT, SLTI e Exceções.
LoadA 1 bit Carrega o registrador A ResetA 1 bit Reseta o registrador A
LoadB 1 bit Carrega o registrador B ResetB 1 bit Reseta o registrador B LoadALUOut 1 bit Carrega o registrador ALUOut ResetALUOut 1 bit Reseta o registrador ALUOut
LoadHiLo 1 bit Carrega os registradores HI e LO ResetHiLo 1 bit Reseta os registradores HI e LO PCWriteCond 1 bit Flag de controle de escrita no PC
PCWrite 1 bit Escreve no PC PCReset 1 bit Reseta o PC MdrLoad 1 bit Carrega o MDR MdrReset 1 bit Reseta o MDR
MdrType 1 bit Define a operação (byte, half, word) do MDR de acordo com o valor passado EPCLoad 1 bit Carrega o EPC
EPCReset 1 bit Reseta o EPC
controlWrite 2 bits Indica se o que deve ser guardado na memória é um byte (8 bits) , um half (16 bits) ou uma word (32 bits)
ShiftN 2 bits Indica o tipo do deslocamento
ALUSrcB 2 bits Controlam os Multiplexadores das entradas de ALU ALUOp 2 bits Seleciona a operação que a ALU irá realizar
MemToReg 2 bits Controla o mux que selecionará os dados a serem escritos no banco de registradores
Descrições do Design
Notas de Design
Numa implementação multiciclo, cada passo na execução de uma instrução gasta um único ciclo de
clock. A implementação multiciclo permite que uma unidade funcional seja utilizada mais de uma vez
ReadMemory1 Soma PC + 4
ReadMemory2 Espera que a memória seja lida LoadInstructionRegiste
r
Carrega o Instruction Register
LoadInstruction Aguarda o valor lido na memória ser liberado no instruction register Decoder Envia a instrução pra a unidade de controle e carrega A e B
Break Para execução do programa Mfhi Acesso ao registrador HI Mflo Acesso ao registrador LO
Slt Checa o flag “Menor” da ALU e seleciona o valor entre 0 e 1 LoadALUResult Carrega o resultado da ALU
OverflowHandler Verifica se a exceção de overflow deve ser lançada WaitMultDiv Espera a conclusão da operação de MULT ou DIV
Beq Instrução de pulo condicional Bne Instrução de pulo condicional
LoadPC Estado para escrever PC apos os jumps Jal Pulo não condicional
Jr Pulo não condicional
Load Estado genérico para a respectiva operação Store Estado genérico para a respectiva operação WriteRegister Realiza a escrita em um registrador
Beq2 Instrução de pulo condicional
WriteReg31 Estado para carregar o PC no registrador 31 WriteEPC Estado para carregar o EPC
Load1 Estado genérico para a respectiva operação WriteMemory Realiza escrita na memória
DivByZeroHandler Realiza tratamento de exceção para divisão por ZERO Beq3 Instrução de pulo condicional
LoadEPC Estado para carregar EPC
WaitReadMemory1 Estado genérico para a respectiva operação IdleState Estado de espera
WaitReadMemory2 Estado genérico para a respectiva operação LoadWord Estado de load
LoadHalf Estado de load LoadByte Estado de load
O esquemático da Máquina de Estados encontra-se no apêndice B.
Verificações e Testes
Simulação
O seguinte programa foi usado para similar nosso projeto. Abaixo o código.
lui $2, 172 (decimal) srl $2, $2, 16
lui $7, 0x0032 (hexa-decimal) srl $7, $7, 16
xor $8,$8, $8 lui $8, 0xFFFF srl $8, $8, 16
lh $3,4($2)
sw $2, 0($29) addi $29, $29, -4
lw $5,0($2)
loop: lui $1,0 jal procure bne $1, $0, fim addi $5, $5, 1 addi $2, $2, 2 j loop
fim: addi $5, $5,1 addi $29,$29,4
lw $2, 0($29) mult $5, $2
mfhi $8 mflo $9 div $2, $5 mfhi $10 mflo $11
break
procure: lh $4, 6($2) and $6, $4, $8
End. numérico
End.simbólico Conteúdo memória
67
73 80 0 72
95 32 94
texto count 176
172
177 178 179 180 181 182 183 184 185 186
227
...
Pilha 82
32
69 69 70 83 00
Figura 7: Localização e valores iniciais das variáveis na memória.
O arquivo de simulação mostra os valores dos seguintes sinais: MDR, PC, IR, Regs. $1,$2,$3, $4, $5,
$6, $7, $8, $9, $10, $11, $29 e $31.
Simulação de Exceções
As três situações de exceção foram simuladas e para cada uma delas segue um arquivo de simulação.
Opcode Inexistente
Divisão por Zero
Overflow
Simulação Demais simulações:
Divisão
Multiplicação
Mdr
PreStore
SL
SRA
SRL
Exceções
Tratamento de Exceções
A implementação das exceções leva em consideração três tipos de exceções:
Opcode inexistente
Overflow
Divisão por zero.
Na ocorrência de uma exceção, o endereço da instrução que causou a exceção é salvo no registrador EPC e o PC é carregado, com o valor do endereço da rotina de tratamento, cujo byte menos significativo está armazenado nos seguintes endereços de memória:
253 – Opcode Inexistente
254 – Overflow
255 – Divisão por zero
A rotina de tratamento é armazenada entre os endereços 228 (decimal) até o endereço 251.
No caso de um opcode inexistente, o valor um (1) é armazenado no registrador 30 pela rotina de tratamento e o programa para a execução.
No caso de um overflow, o valor 2 é armazenado no registrador 30 pela rotina de tratamento e a execução do programa continua.
No caso de divisão por zero, o valor três (3) é armazenado no registrador 30 pela rotina de tratamento e o programa parar a execução.
Exceção Valor armazenado
no registrador 30 Execução do programa
Opcode inexistente 1 PARA
Overflow 2 CONTINUA
Divisão por zero 3 PARA
Tabela ??: Exceções.
Referências
Organização e projeto de computadores
HENNESSY, John L.; PATTERSON, David. A.; LARUS, James R.. Organização e projeto de computadores a interface hardware software. 2ª ed. Rio de Janeiro: Livros Técnicos e Científicos, c2000.. 551p. ISBN 8521612125.
Introdução a organização de computadores
MONTEIRO, Mario A. (Mario Antonio).. Introdução a organização de computadores.
2. ed. - Rio de Janeiro: LTC, c1995.. 393 p. ISBN 85-216-1032-7
Introdução à arquitetura e organização de computadores
LORIN, Harold.; REINPRECHT, Ricardo, trad.. Introdução à arquitetura e organização de computadores. Rio de Janeiro: Campus, 1985.. 362p. ISBN 85-7001- 191-1.
A guide to VHDL
MAZOR, Stanley.; LANGSTRAAT, Patricia, colab.. A guide to VHDL. 2. ed. - Bos- ton: Kluwer Academic, 1993.. 1v. (paginação irregular)
MIPS RISc architeture
KANE, Gerry.; HEINRICH, Joe.. MIPS RISc architecture. Upper Saddle River (NJ):
Prentice Hall PTR, c1992.. x-25 p. ISBN 0135904722.
Códigos
controlunit.vhd
entity controlUnit is port (
--- SINAIS ---
-- O relógio do processador.
clock : in bit;
-- Reseta a unidade de controle.
reset : in bit;
-- Flag da ULA que indica overflow da ULA !!
Overflow : in bit;
-- Flag Da Ula
Negativo : in bit;
-- Sinaliza quando S for zero
z : in bit;
-- Sinaliza se A=B
Igual : in bit;
-- Sinaliza se A>B
Maior : in bit;
-- Sinaliza se A<B
Menor : in bit;
-- Indica a operação a ser realizada pelo banco de registradores leitura (0) escrita (1).
reset_Bank : out bit;
RegWrite : out bit;
-- Indica o tipo do deslocamento
ShiftN : out bit_vector(1 downto 0);
-- Controla a caixa MULTDIV
MultDivStart : out bit; -- inicia a operacao
MultDiv : out bit; -- seleciona a mult ou div
DivByZero : in bit; -- indica se exceção divByZero occoreu MultDivFinished : in bit;
--- REGISTRADORES ---
-- Controla o registrador que guarda a primeira saída do banco de registradores.
LoadA : out bit;
ResetA : out bit;
-- Controla o registrador que guarda a segunda saída do banco de registradores.
LoadB : out bit;
ResetB : out bit;
-- Controla o registrador que guarda o resultado da ALU.
LoadALUOut : out bit;
ResetALUOut : out bit;
-- Registradores HI e LO
LoadHiLo : out bit;
ResetHiLo : out bit;
-- Saídas que controlam registrador que guarda PC (Program Counter).
PCWriteCond : out bit;
PCWrite : out bit;
PCReset : out bit;
-- Controla o Memory Data Register com Load, Reset e a operação a ser realizada(MdrType)
MdrLoad : out bit;
MdrReset : out bit;
MdrType : out bit_vector(1 downto 0); -- seta a operação(byte, half, word) do MDR de acordo com o valor passado
-- Registrador EPC que guarda onde houve erro (exceção) EPCLoad : out bit;
EPCReset : out bit;
--- MULTIPLEXADORES
-- Controlam os Multiplexadores das entradas de ALU.
ALUSrcA : out bit;
ALUSrcB : out bit_vector(1 downto 0);
-- Seleciona a operação que a ALU irá realizar.
ALUOp : out bit_vector(2 downto 0);
-- Controla o valor a ser carregado no PC.
PCSource : out bit_vector(2 downto 0);
-- Controla o mux que selecionará os dados a serem escritos no banco de registradores.
MemToReg : out bit_vector(2 downto 0);
-- Controla o mux que seleciona o endereço de memória a ser lido ou escrito.
IorD : out bit_vector(1 downto 0);
-- Seleciona o registrador a ser gravado no banco de registradores RegDst : out bit_vector(1 downto 0);
-- Seleciona o Mux que possui o valor da ULA e do Shift N
MuxOp : out bit;
-- -- Seleciona o Mux que possui constantes usadas no SLT, SLTI e Exceções.
EXCode : out bit_vector(1 downto 0)
);
end controlUnit;
architecture arqControlUnit of controlUnit is
type state is (resetCPU, -- Reseta a unidade de controle
Fetch, -- Carrega o novo valor de PC no seu registrador
ReadMemory1, -- Soma PC + 4
ReadMemory2,-- Espera que a memória seja lida LoadInstruction, -- Aguarda o valor lido na memória ser liberado no instruction register
LoadInstructionRegister, writeRegister, writememory,
-- decoder, -- Decodifica a instrução que será executada
DivByZeroHandler, WaitMultDiv, mult,
div,
shiftRightA, shiftRightL, shiftLeftL, -- Instruções de deslocamento
beq, bne1, bne2, bne3, -- Instruçoes de pulo condicional
slt, slti,
j, jr, jal, -- Pulo não condicional
LoadPC, --estado para escrever pc apos os jumps.
rte, -- Retorno de exceção loadPCEX,
writeReg31, --estado para carregar o pc no reg 31.
writeEPC0, writeEPC,
break -- Pára execução do programa
-- Nop -- Sem operacao
);
signal currentState : state;
signal SP : bit_vector(31 downto 0); -- Stack
point, posição do topo da pilha
signal next_of_next : state; -- State gambieirror pra fazer droga nenhuma e comer tempo !!
begin
process (clock, reset) begin
if (reset = '1') then
currentState <= resetCPU;
elsif (clock'event and clock = '1') then case currentState is
--- -- Idle state
when idleState =>
--IorD <= 0;
--MemWrite <= 0;
currentState <= next_of_next;
--- when resetCPU =>
SP <= "00000000000000000000000011100011";
controlWrite <= "00";
IRWrite <= '0';
MemoryIO <= '0';
RegDst <= "00";
RegWrite <= '0';
MultDivStart <= '0';
MultDiv <= '0';
ResetA <= '1';
ResetB <= '1';
ResetHiLo <= '1';
reset_Bank <= '1';
ALUSrcA <= '0';
ALUSrcB <= "00";
MdrReset <= '1';
EPCLoad <= '0';
EPCReset <= '1';
ALUOp <= "000";
PCSource <= "000";
PCWrite <= '0';
PCWriteCond <= '0';
PCReset <= '1';
ShiftN <= "00";
MemToReg <= "000";
IorD <= "00";
MuxOp <= '0';
loadHiLo <= '0';
mdrLoad <= '0';
MdrType <= "00";
currentState <= Fetch;
--- -- Carrega PC e ativa leitura na memória
when Fetch =>
ResetA <= '0';
ResetB <= '0';
ResetALuOut <= '0';
ResetHilo <= '0';
PCReset <= '0';
MdrReset <= '0';
EPCReset <= '0';
reset_Bank <= '0';
mdrLoad <= '0';
LoadAluOut <= '0'; -- mantém valor no aluOut PCWrite <= '0'; -- mantém o valor de PC PcWriteCond <= '0'; -- mantém o valor de PC MemoryIO <= '0'; -- lê da memória IOrd <= "00"; -- MUX do PC e ALUout regWrite <= '0'; -- pra garantir que o
ALUSrcB <= "01"; -- seleciona 4 para somar com PC
PCSource <= "000"; -- deixa passar pelo multiplexador o valor da soma
PCWrite <= '0'; -- mantém o registrador que contém PC com o seu valor atual.00
currentState <= ReadMemory2;
---
---- Segundo estado de leitura da memória, teoricamente ao término desse o valor lido estará disponível
---- Grava novo valor no PC (PC + 4) when ReadMemory2 =>
IRWrite <= '1'; -- habilita carregamento de valor no IR
PCWrite <= '1';
--mdrLoad <= '1';
--mdrType <= "00";
currentState <= LoadInstructionRegister;
---
---- Aguarda o Intruction Register decompor o valor lido na memória e no próximo clock libera os resultados
when LoadInstructionRegister =>
PCWrite <= '0'; -- hold IRWrite <= '0'; -- hold
--mdrLoad <= '1';
currentState <= LoadInstruction;
--- ---- Envia o valor lido da memória, já decomposto e carrega os valores do Registrador A e B
when LoadInstruction =>
-- Soma o valor do registradores para aumentar a perfomance de algumas intruções
loadA <= '1';
loadB <= '1';
ALUSrcA <= '1'; -- seleciona o
valor do registrador A
ALUSrcB <= "00"; -- seleciona o valor do registrador B
MuxOP <= '0'; -- seleciona o resultado ULA para ALUOut
ALUOP <= "001"; -- seleciona a SOMA na alu
currentState <= decoder;
--- ---- Decodifica a instrução no Instruction Register a ser executada --- Início do Big Ultra Monster CASE plus plus ++ ---
when decoder =>
IRWrite <= '0';
-- Carrega em aluOUt o resultado da soma realizada no ciclo anterior
-- LoadAluOut <= '0';
loadA <= '0';
loadB <= '0';
-- Decodifica a instrução
case instruction(31 downto 26) is -- checa o OP CODE when "000000" =>
case instruction(5 downto 0) is -- function when "000000" =>
if(instruction =
"00000000000000000000000000000000") then -- no operation
currentState <= Fetch;
else
shiftN <= "10";
muxOP <= '1';
memToReg <= "000";
RegDst <= "01";
--MultDiv <=
'1';
currentState <= loadALURe- sult;
end if;
--- ---
-- mfhi
--- ---
when "010000" =>
MemToReg <=
"010";
RegDst <=
"01";
currentState <= WriteReg- ister;
--- ---
-- mflo
--- ---
when "010010" =>
MemToReg <=
if(Overflow = '1') then
--PCSource <=
"101";-- seleciona posicao da memoria pra tratar o overflow
currentState <= Over- flowHandle;
else
LoadALUOut <=
'1';
MemtoReg <=
"000"; --seleciona valor a ser gravado
RegDst <=
"01"; -- registrador destino
currentState <= WriteReg- ister;
end if;
--- -- sub
--- when "100010" =>
-- seleciona a subtração na ALU.
ALUOP <= "010";
MuxOp <= '0'; -- deixa passar o valor da ALU currentState <= OverflowHandle;
--- -- addu
--- when "100001" =>
LoadALUOut <= '1';
MemtoReg <= "000";
RegDst <= "01";
MuxOp <= '0'; -- deixa passar o valor da ALU currentState <= writeRegister;
--- -- subu
--- when "100011" =>
-- seleciona a subtração na ALU.
ALUOP <= "010";
MemtoReg <= "000"; --seleciona valor a ser gravado RegDst <= "01"; -- registrador destino
currentState <= loadALUResult;
--- -- and
--- when "100100" =>
-- seleciona a operação de and na ULA ALUOP <= "011";
MemtoReg <= "000"; --seleciona valor a ser gravado RegDst <= "01"; -- registrador destino
currentState <= loadALUResult;
--- -- xor
---
ALUOP <= "110";
MemtoReg <= "000"; --seleciona valor a ser gravado RegDst <= "01"; -- registrador destino
currentState <= loadALUResult;
--- -- Mult
--- when "011000" =>
LoadA <= '0';
LoadB <= '0';
AlUSrcA <= '1'; -- seleciona o registrador A AlUSrcB <= "00"; --seleciona o registrador B currentState <= mult;
--- -- Div
--- when "011010" =>
LoadA <= '0';
LoadB <= '0';
AlUSrcA <= '1'; -- seleciona o registrador A AlUSrcB <= "00"; --seleciona o registrador B currentState <= div;
--- -- Sra
--- when "000011" =>
MemToReg <= "000";
shiftN <= "01";
RegDst <= "01";
MuxOp <= '1';
currentState <= loadALUResult;
--- -- Srl
--- when "000010" =>
MemToReg <= "000";
RegDst <= "01";
shiftN <= "00";
MuxOp <= '1';
currentState <= loadALUResult;
---
ALUOP <= "000"; --Seleciona carregar na saida da ula O reg. A.
MuxOP <= '0'; --seleciona muxOP para passar a saida da ULA.
currentState <= jr;
--- -- break
--- when "001101" =>
currentState <= break;
when others =>
currentState <= resetCPU;-- ou LANÇAR EXCEÇÃO ??
end case; -- op CODE 000000
--- -- Load Word
--- when "100011" =>
AluSrcA <= '1'; --seleciona a passagem do
Reg. a no mux ALUSrcA.
AluSrcB <= "10"; --seleciona a passagem do mdr no mux ALUSrcB.
ALUOP <= "001"; --seleciona a ula para somar.
next_of_next <= loadword; --estado padrao para os loads.
currentState <= load;
--- -- Load Byte
--- when "100000" =>
ALUSrcA <= '1'; --
seleciona a passagem do Reg. a no mux ALUSrcA.
ALUSrcB <= "10"; --
seleciona a passagem do mdr no mux ALUSrcB.
ALUOP <= "001"; --
seleciona a ula para somar.
next_of_next <= loadbyte; --estado padrao para os loads.
currentState <= load;
--- -- Load Half
--- when "100001" =>
AluSrcA <= '1'; --eleciona a passagem do
Reg. a no mux ALUSrcA.
AluSrcB <= "10"; --
seleciona a passagem do mdr no mux ALUSrcB.
ALUOP <= "001"; --
seleciona a ula para somar.
next_of_next <= loadhalf; --estado padrao para os loads.
currentState <= load;
--- -- Store Word
--- when "101011" =>
AluSrcA <= '1'; -- seleciona valor do registrador A e envia-o pra ULA
MuxOP <= '0'; --seleciona o conteúdo da ULA
controlwrite <= "00"; -- ajusta o preStore pra gravar a palavra inteira(o valor de entrada eh o registrador B)
-- next_of_next <= storeWord;
currentState <= store;
--- -- Store Byte
--- when "101000" =>
AluSrcA <= '1'; -- seleciona valor do registrador A e envia-o pra ULA
AluSrcB <= "10"; -- seleciona o valor do Deslocamento
AluOp <= "001"; -- realiza soma na ULA
MuxOP <= '0'; --seleciona o
conteúdo da ULA
controlwrite <= "10"; -- manipula o byte menos significativo a ser gravado!
-- next_of_next <= storebyte;
currentState <= store;
--- -- Store Half
--- when "101001" =>
AluSrcA <= '1'; -- seleciona valor do registrador A e envia-o pra ULA
AluSrcB <= "10"; -- seleciona o valor do Deslocamento
AluOp <= "001"; -- realiza soma na ULA
MuxOP <= '0'; --seleciona o
conteúdo da ULA
controlWrite <= "01"; -- manipula meia palavra pra ser gravada na memória
-- next_of_next <= storehalf;
currentState <= store;
--- -- Load upper Immediate
--- when "001111" =>
regdst <= "00"; --seleciona o registrador destino memtoreg <= "111";
-- addiu
--- when "001001" =>
ALUSrcB <= "10"; -- seleciona a constante ALUOP <= "001"; -- operação de add na ALU MemtoReg <= "000"; -- seleciona valor a ser gravado RegDst <= "00"; -- registrador destino
currentState <= writeRegister;
--- -- andi
--- when "001101" =>
ALUSrcB <= "10"; -- seleciona a constante
ALUOP <= "011"; -- opreção de and na ALU
MemtoReg <= "000"; -- seleciona valor a ser gravado
RegDst <= "00"; -- registrador destino
currentState <= loadALUResult;
--- -- xori
--- when "001110" =>
ALUSrcB <= "10" ; -- seleciona a constante
ALUOP <= "110" ; -- seleciona operação de xor na ALU
MemtoReg <= "000" ; -- seleciona valor a ser gravado
RegDst <= "00" ; -- registrador destino
currentState <= loadALUResult;
--- --- BEQ --- ---
when "000100" =>
AluSrcB <= "11"; -- seleciona o deslocamento
AluSrcA <= '0'; -- PC
ALUOP <= "001"; -- soma
loadAluOut <= '1'; -- carrega aluOut currentState <= beq;
--- --- BNE --- ---
when "000101" =>
AluSrcB <= "11"; -- seleciona o deslocamento
AluSrcA <= '0'; -- PC
ALUOP <= "001"; -- soma PC + deslocamento currentState <= bne1;
--- --- slti ---
AluSrcA <= '1'; --seleciona o mux do reg. A para passar o valor do reg.
AluSrcB <= "10"; --seleciona o mux do reg. B para passar a constante com sinal extendido.
ALUOP <= "111"; --seleciona a ula para comparar.
currentState <= slti;
--- --- j --- ---
when "000010" =>
PCSource <= "010"; --seleciona pcSource para passar o valor do pc.
currentState <= LoadPC;
--- --- jal --- ---
when "000011" =>
ALUSrcA <= '0'; --seleciona o mux do reg. A para passar o valor do reg.
ALUOP <= "000"; --Seleciona a ULA para carregar A na saida (deixa passa A).
PcSource <= "010"; --seleciona pcSource para passar o valor do pc.
currentState <= jal;
--- --- rte --- ---
when "010000" =>
PCSource <= "011"; -- seleciona valor do EPC pra o PC
PCwrite <= '1'; -- grava novo valor do PC
currentState <= fetch;
--- ---UnKnow OpCode--- ---
when others =>
ALUSrcA <= '0';
ALUSrcB <= "01";
ALUOP <= "010";
-- tratamento de exceção de OverFlow if(Overflow = '1') then
-- seleciona posicao da memoria pra tratar o overflow
ALUSrcA <= '0';
ALUSrcB <= "01";
ALUOP <= "010";
muxOp <= '0'; -- seleciona o resultado da ULA
PCSource <= "100";
IorD <= "10";
MemoryIO <= '0';
EXCode <= "10";
PCSource <= "100";
currentState <= writeEPC0;
else
LoadALUOut <= '1';
MemtoReg <= "000"; --seleciona valor a ser gravado
--RegDst <= "01"; -- registrador destino
currentState <= WriteRegister;
end if;
--- -- Carrega o valor do resultado da ALU no registrador ALUout
--- when loadALUResult =>
loadALUOut <= '1';
currentState <= writeRegister;
--- -- Reliza a gravavação no registrador.
--- when WriteRegister =>
MdrLoad <= '0';
loadALUOut <= '0'; -- desabilita gravação do AluOut
regWrite <= '1';
currentState <= fetch;
--- --- Instruções de LOAD --- ---
when load =>
Iord <= "01";
LoadAluOut <= '1';
currentState <= load1;
when load1 =>
MemoryIO <= '0';
currentState <= WaitReadMemory1;
--- Primeiro dos 2 ciclos de leitura da memória when WaitReadMemory1 =>
currentState <= WaitReadMemory2;
--- Último Ciclo de leitura da memória (ao término o valor da memória
MdrLoad <= '0';
currentState <= next_of_next;
--- --- Load Word --- ---
when LoadWord =>
MdrLoad <= '1';
MdrType <= "00"; -- desabilita deslocamento
RegDst <= "00"; -- seleciona o registrador destino
MemtoReg <= "001"; -- seleciona valor lido da memória
currentState <= writeRegister;
--- --- Load Half --- ---
when LoadHalf =>
MdrLoad <= '1';
MdrType <= "10"; -- Realiza 16 deslocamentos para a direita --OBS:Trocado por anti-patern
RegDst <= "00"; -- seleciona o registrador destino
MemtoReg <= "001"; -- seleciona valor lido da memória
currentState <= writeRegister;
--- --- Load Byte --- ---
when LoadByte =>
MdrLoad <= '1';
MdrType <= "01"; -- Realiza 24 deslocamentos para a direita --OBS:Trocado por anti-patern
RegDst <= "00"; -- seleciona o registrador destino
MemtoReg <= "001"; -- seleciona valor lido da memória
currentState <= writeRegister;
--- --- Instruções de STORE--- ---
when store =>
--- Instruções de MULT/DIV --- ---
when mult =>
MultDivStart <= '1';
MultDiv <= '0';
currentState <= WaitMultDiv;
when div =>
MultDivStart <= '1';
MultDiv <= '1';
currentState <= WaitMultDiv;
--- --- Wait Final Operation --- ---
when WaitMultDiv =>
MultDivStart <= '0';
if(MultDivFinished = '1') then if(DivByZero = '1') then
currentState <= DivByZeroHandler; --trata- mento de exceção
else
LoadHiLo <='1';
currentState <= fetch;
end if;
else
currentState <= WaitMultDiv;
end if;
--- --- ESTADO DE TRATAMENTO DE EXCEÇÂO ---
when DivByZeroHandler =>
-- seleciona posicao da memoria pra tratar a divisão por zero
ALUSrcA <= '0';
ALUSrcB <= "01";
ALUOP <= "010";
muxOp <= '0'; -- seleciona o resultado da ULA PCSource <= "100";
IorD <= "10";
MemoryIO <= '0';
EXCode <= "01";
PCSource <= "100";
currentState <= writeEPC0;
--- --- beq --- ---
when beq =>
AluSrcA <= '1';
AluSrcB <= "00";
AluOp <= "010";
pcSource <= "001";
PcWriteCond <= '1';
currentState<= fetch;
--- when bne1 =>
loadAluout <= '1';
currentState <= bne2;
when bne2 =>
loadAluout <= '0';
AluSrcA <= '1';
AluSrcB <= "00";
AluOp <= "111";
currentState <= bne3;
when bne3 =>
if(igual = '0') then
PCSource <="001";
PCWrite <= '1';
else PCWrite <= '0';
end if;
currentState <= fetch;
--- --- slt --- ---
when slt =>
if(Menor = '1') then
MemToReg <= "101"; -- seleciona a entrada 5 do mux
else
MemToReg <= "100";
end if;
currentState <= writeRegister;
--- --- slti --- ---
when slti =>
regDst <= "00"; --seleciona para passar o endereco do reg. a escrever.
if(Menor = '1') then
MemToReg <= "101"; -- seleciona a entrada 5 do mux
else
when LoadPC =>
LoadALUOut <= '0';
PCWrite <= '1';
currentState <= fetch;
--- --- jal --- ---
when jal =>
LoadALUOut <= '1';
MemToReg <= "000";
RegDst <= "10";
PCWrite <= '1';
PCSource <= "010";
currentState <= writeReg31;
--- --- Write Reg31 --- ---
when writeReg31 =>
PCWrite <= '0';
--PCSource <= "010";
LoadALUOut <= '0';
RegWrite <= '1';
currentState <= fetch;
--- --- break --- ---
when break =>
currentState <= break; -- põe essa droga em Loop ---
--- WriteECP --- ---
when writeEPC0 =>
-- EPCLoad <= '0';
currentState <= writeEPC;
--- --- WriteECP --- ---
when writeEPC =>
EPCLoad <= '1';
currentState <= loadPCEX;
--- --- WriteECP --- ---
when loadPCEX =>
EPCLoad <= '0';
PCWrite <= '1';
currentState <= fetch;
when others =>
currentState <= Fetch;
end case;
end if;
end arqControlUnit;
desloc_const
entity desloc_const is port (
entrada :in bit_vector(15 downto 0);
saida :out bit_vector(31 downto 0)
);
end desloc_const;
architecture behavioral_arc of desloc_const is begin
saida(15 downto 0) <= "0000000000000000";
saida(31 downto 16) <= entrada;
end behavioral_arc;
ex_adr_sel
entity ex_adr_sel is port(
selecao :in bit_vector(1 downto 0);
entradaDataOut :in bit_vector(31 downto 0);
saida :out bit_vector(7 downto 0)
);
end ex_adr_sel;
architecture behavioral_arc of ex_adr_sel is begin
process begin
case selecao is when "00" =>
saida <= entradaDataOut(7 downto 0);
when "01" =>
saida <= entradaDataOut(15 downto 8);
when "10" =>
saida <= entradaDataOut(23 downto 16);
when "11" =>
end case;
end process;
end behavioral_arc;
extensao_sinal.vhd
port(
entrada :in bit_vector(15 downto 0);
saida :out bit_vector(31 downto 0) );
end extensao_sinal;
architecture behavioral_arch of extensao_sinal is begin
saida(15 downto 0) <= entrada;
with entrada(15) select
saida(31 downto 16) <= "0000000000000000" when '0', "1111111111111111" when '1';
end behavioral_arch;
instr_reg.vhd
--- -- Title : Registrador de Intruções
-- Project : CPU multi-ciclo
---
-- File : instr_reg.vhd
-- Author : Marcus Vinicius Lima e Machado ([email protected])
-- Paulo Roberto Santana Oliveira Filho
-- Viviane Cristina Oliveira Aureliano ([email protected]) -- Organization : Universidade Federal de Pernambuco
-- Created : 29/07/2002 -- Last update : 21/11/2002 -- Plataform: Flex10K
-- Simulators : Altera Max+plus II -- Synthesizers :
-- Targets :
-- Dependency :
--- -- Description : Entidade que registra a instrução a ser executada, modulando -- corretamente a saída de acordo com o layout padrão das intruções do Mips.
--- -- Copyright (c) notice
-- Universidade Federal de Pernambuco (UFPE).
-- CIn - Centro de Informatica.
entity Instr_reg is port(
Clk : in bit; -- Clock do sistema
Reset : in bit; -- Reset
Load_ir : in bit; -- Bit para ativar carga do registrador de intruções
Entrada : in bit_vector (31 downto 0); -- Intrução a ser carregada
Instr31_26 : out bit_vector (5 downto 0); -- Bits 31 a 26 da instrução
Instr25_21 : out bit_vector (4 downto 0); -- Bits 25 a 21 da instrução
Instr20_16 : out bit_vector (4 downto 0); -- Bits 20 a 16 da instrução
Instr15_0 : out bit_vector (15 downto 0) -- Bits 15 a 0 da instrução
);
end Instr_reg;
-- Arquitetura que define o comportamento interno do Registrador de Intruções -- Simulation
architecture behavioral_arch of Instr_reg is
signal saida : bit_vector (31 downto 0); -- Sinal interno que guarda a intrução a ser modulada
begin
-- Clocked process process (clk, Reset)
begin
if(reset = '1') then
saida <= "00000000000000000000000000000000";
elsif (clk = '1' and clk'event) then if (load_ir = '1') then
saida (31 downto 0) <= entrada; -- Carrega instrução
end if;
end if;
end process;
Instr31_26 <= saida (31 downto 26); -- Modula instrução (31 a 26) Instr25_21 <= saida (25 downto 21); -- Modula instrução (25 a 21) Instr20_16 <= saida (20 downto 16); -- Modula instrução (20 a 16) Instr15_0 <= saida (15 downto 0); -- Modula instrução (15 a 0) end behavioral_arch;
mdr.vhd
-- Entradas:
-- * reset: bit que reseta o mdr
-- * load: bit que carrega o mdr
-- * N: vetor de 2 bits que indica a quantidade de
-- deslocamentos
-- Abaixo seguem os valores referentes à entrada shift e as
-- respectivas funções do registrador:
--
-- N pode ser deslocamentos de: 00 não desloca --
01 Deslocamento 8 vezes -- 10 Deslocamento 16 vezes -- 11 Deslocamento 24 vezes
--- ENTITY mdr IS
PORT(
Clk : IN bit; -- Clock do sistema
Reset : IN bit; -- Reset load : in bit; -- carrega
N : IN bit_vector (1 downto 0); --
Quantidade de deslocamentos
Entrada : IN bit_vector (31 downto 0); -- Vetor a ser deslocado
Saida : OUT bit_vector (31 downto 0) -- Vetor deslocado );
END mdr;
-- Arquitetura que define o comportamento do registrador de deslocamento -- Simulation
ARCHITECTURE behavioral_arch OF mdr IS
-- signal temp : bit_vector (31 downto 0); -- Vetor temporário begin
-- Clocked process process (Clk, Reset)
begin
if(Reset = '1') then
Saida (18) <= Entrada(15);
Saida (19) <= Entrada(15);
Saida (20) <= Entrada(15);
Saida (21) <= Entrada(15);
Saida (22) <= Entrada(15);
Saida (23) <= Entrada(15);
Saida (24) <= Entrada(15);
Saida (25) <= Entrada(15);
Saida (26) <= Entrada(15);
Saida (27) <= Entrada(15);
Saida (28) <= Entrada(15);
Saida (29) <= Entrada(15);
Saida (30) <= Entrada(15);
Saida (31) <= Entrada(15);
when "10" => --
Deslocamento à direita aritmético 24 vezes
Saida (7 downto 0) <=
Entrada(7 downto 0);
Saida (8) <= Entrada(7);
Saida (9) <= Entrada(7);
Saida (10) <= Entrada(7);
Saida (11) <= Entrada(7);
Saida (12) <= Entrada(7);
Saida (13) <= Entrada(7);
Saida (14) <= Entrada(7);
Saida (15) <= Entrada(7);
Saida (16) <= Entrada(7);
Saida (17) <= Entrada(7);
Saida (18) <= Entrada(7);
Saida (19) <= Entrada(7);
Saida (20) <= Entrada(7);
Saida (21) <= Entrada(7);
Saida (22) <= Entrada(7);
Saida (23) <= Entrada(7);
Saida (24) <= Entrada(7);
Saida (25) <= Entrada(7);
Saida (26) <= Entrada(7);
Saida (27) <= Entrada(7);
Saida (28) <= Entrada(7);
Saida (29) <= Entrada(7);
Saida (30) <= Entrada(7);
Saida (31) <= Entrada(7);
when others =>
end case;
end if;
end if;
--Saida <= temp;
end process;
END behavioral_arch;
multidiv.vhd
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity multiDiv is port(
clk :in bit;
start :in bit;
selecao :in bit;
entrada1 :in bit_vector(31 downto 0);
entrada2 :in bit_vector(31 downto 0);
Hi :out bit_vector(31 downto 0);
Lo :out bit_vector(31 downto 0);
divZero :out bit;
terminou :out bit );
end multiDiv;
architecture behavioral_arc of multiDiv is component ula32
port(
A :in bit_vector(31 downto 0);
B :in bit_vector(31 downto 0);
seletor :in bit_vector(2 downto 0);
S :out bit_vector(31 downto 0) );
end component;
type state is (inicio, --manda o sinal para o bit menos significativo teste, --testa o meio se for necessario, soma e subtrai
shiftR, --shift a direita logico, tb verifica se ja acabou os 32 bits(multiplicacao)
shiftL, --shift a esquerda do remainder todo
subtract, --subtrai o divisor da parte esq. do remainder testRem, --testa se o remainder < 0 e processa as operacoes de acordo com o resultado.
shiftGambiarra, --(vai mudar)
signal divMult : std_logic_vector(31 downto 0); --usado na multiplicacao e na divisao.Funciona como divisor
begin
--ou como multiplicando.
process(clk, start)
variable cont : integer;
begin
if(clk'event and clk = '1') then if (start = '1') then
if(entrada2(31 downto 0) = "00000000000000000000000000000000") then
divZero <= '1';
terminou <= '1';
current <= zerarTerminou;
else current <= inicio;
terminou <= '0';
divZero <= '0';
cont := 0;
end if;
else
case current is
when inicio => --estado inicial sempre
cont := 0;
if (selecao = '0') then prodRem(0) <= '0';
prodRem(64 downto 33) <=
"00000000000000000000000000000000";
prodRem(32 downto 1) <= To_StdLogicVector(en- trada2);
divMult <= To_StdLogicVector(entrada1);
current <= teste;
else
if(entrada1(31) = '1') then --***********verifica os sinais
if(entrada2(31) = '1') then current <= soRem;
else
current <= osDois;
end if;
else
if(entrada2(31) = '1') then current <= soQuo;
else
current <= shiftL;
end if;
end if;
prodRem(64 downto 33) <=
"00000000000000000000000000000000";
divMult <= To_StdLogicVector(entrada2);
end if;
when teste => --testa o meio ***********comeca os estados da multiplicacao
cont := cont + 1;
if (prodRem(1 downto 0) = "00" or prodRem(1 downto 0) = "11") then
current <= shiftR;
elsif (prodRem(1 downto 0) = "01") then
prodRem(64 downto 33) <= divMult + prodRem(64 downto 33);
current <= shiftR;
else
prodRem(64 downto 33) <= prodRem(64 downto 33) - divMult;
current <= shiftR;
end if;
when shiftR =>
prodRem(63 downto 0) <= prodRem(64 downto 1);
prodRem(64) <= prodRem(64);
if(cont = 32) then current <= fim;
else
current <= teste;
end if;
--********acaba os estados da multiplicacao
when shiftL => --
********comeca os estados da divisao
prodRem(64 downto 2) <= prodRem(63 downto 1);
prodRem(1) <= '0';
current <= subtract;
when subtract =>
cont := cont + 1;
prodRem(64 downto 33) <= prodRem(64 downto 33) - divMult;
current <= testRem;
when testRem =>
if(prodRem(64) = '0') then