0% acharam este documento útil (0 voto)
7 visualizações17 páginas

Implementação de CPU RISC-V Uniciclo

OAC___Lab2
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
7 visualizações17 páginas

Implementação de CPU RISC-V Uniciclo

OAC___Lab2
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Universidade de Brası́lia (UnB)

Departamento de Ciência da Computação (CIC)

Organização e Arquitetura de
Computadores
Laboratório 2 - CPU RISC-V UNICICLO

Professor:
Prof. Carla Maria Chagas e Cavalcante Koike

Autores:
Felipe de Moraes Vilhena 211066042
Isabela de Souza Climaco 190088931
João Marcos Melo Monteiro 130143031
Luis Felipe Hilario Carmona 212007153
Luis Fernando Gomes Alvim 211066285

Brası́lia-DF
10 de novembro de 2025
Conteúdo
1 Questão 1 1
1.0.1 b) Levante os requisitos fı́sicos e temporais do seu processador com-
pleto. Verifique se os slacks de setup e hold estão sendo cumpridos. 11
[12pt]article [utf8]inputenc [T1]fontenc lmodern geometry a4paper, margin=2cm array
booktabs graphicx

1 Questão 1

Figura 1: Implemente o processador Uniciclo com ISA Reduzida com as instruções: add,
sub, and, or, slt, lw, sw, beq, jal, e ainda as instruções jalr, addi e lui.

O projeto [Link] possui o arcabouço para o desenvolvimento e teste do seu pro-


cessador.

1.1 – Análise do Programa de Teste (de1.s)


Objetivo
Validar a implementação das instruções da ISA RV32I reduzida por meio da execução
do programa de1.s no simulador RARS. O programa foi projetado para exercitar todas
as instruções requeridas (9 + 3) e utiliza o registrador t0 (x5) como referência para
observação dos resultados.

Especificação funcional
• Entradas: Código em Assembly RISC-V (de1.s) contendo instruções nos formatos
R, I, S, B, U e J.

• Saı́das: Valores esperados no registrador t0 após cada instrução, confirmando a


corretude da execução.

1
Resumo das instruções testadas
• R-type: add, sub, and, or, slt

• I-type: addi, jalr (via ret), lw

• S-type: sw

• B-type: beq

• U/J-type: lui (comentada), jal

Análise do código
O programa inicia carregando o ponteiro gp para a área de dados (0x10010000) e
executa operações aritméticas, lógicas, comparação, desvio condicional, salto e acesso à
memória. O fluxo principal é:

1. Carregar t1 com a palavra 0xFFFFFF0F da memória.

2. Inicializar t2 com 0x00000777.

3. Executar operações sobre t0: and, or, add, sub, slt (duas vezes).

4. Testar desvio com beq.

5. Chamar procedimento via jal e retornar com ret.

6. Realizar operações de carga e armazenamento (lw, sw).

7. Finalizar com um loop infinito (FIM: j FIM), mantendo o último valor de t0.

Resultados esperados em t0
Etapa Instrução Valor esperado
1 and t0,t1,t2 0x00000707
2 or t0,t1,t2 0xFFFFFF7F
3 add t0,t2,t1 0x00000686
4 sub t0,t2,t1 0x00000868
5 slt t0,t1,t2 0x00000001
6 slt t0,t2,t1 0x00000000
7 Após PROC 0x0000007F, 0xFFFFFF0F, 0x0000007F
Final addi t0,zero,0xFFFFFCCC 0xFFFFFCCC

Conclusão
O programa de1.s cobre todas as instruções exigidas e permite validar a CPU uni-
ciclo. A sequência de valores em t0 confirma a execução correta das operações lógicas,
aritméticas, de desvio e acesso à memória. O valor final (0xFFFFFCCC) serve como re-
ferência para testes no hardware.

2
1.2 - Banco de Registradores (3 leituras simultâneas)
Objetivo
Implementar o Banco de Registradores RV32I com 32 registradores de 32 bits (x0..x31),
com: (i) três leituras assı́ncronas simultâneas (rs1, rs2 e disp para debug/visua-
lização), (ii) uma escrita sı́ncrona em rd, (iii) x0 sempre zero (escrita ignorada), e
(iv) sp (x2) inicializado em 0x1001 03FC no reset, conforme enunciado.

Especificação funcional
• Entradas

– clk: clock (borda de subida).


– rst: reset (sı́ncrono ativo em 1).
– we: habilita escrita.
– wa[4:0]: endereço de escrita (write address, registrador rd).
– wd[31:0]: dado de escrita (write data).
– ra1[4:0], ra2[4:0], ra3[4:0]: endereços de leitura (rs1/rs2/disp).

• Saı́das

– rd1[31:0], rd2[31:0], rd3[31:0]: dados lidos de ra1, ra2, ra3.

Implementação em Verilog
‘timescale 1ns/1ps

module regfile #(
parameter XLEN = 32
)(
input wire clk,
input wire rst,
input wire we,
input wire [4:0] wa,
input wire [XLEN-1:0] wd,
input wire [4:0] ra1,
input wire [4:0] ra2,
input wire [4:0] ra3,
output wire [XLEN-1:0] rd1,
output wire [XLEN-1:0] rd2,
output wire [XLEN-1:0] rd3
);

reg [XLEN-1:0] regs 0:31[1]();


integer i;

3
always @(posedge clk) begin
if (rst) begin
for (i = 0; i < 32; i = i + 1)
regs[i] <= {XLEN{1’b0}};
regs[2] <= 32’h1001_03FC;
end else begin
if (we && (wa != 5’d0)) begin
regs[wa] <= wd;
end
end
end

wire bypass_ra1 = we && (wa == ra1) && (wa != 5’d0);


wire bypass_ra2 = we && (wa == ra2) && (wa != 5’d0);
wire bypass_ra3 = we && (wa == ra3) && (wa != 5’d0);

assign rd1 = (ra1 == 5’d0) ? {XLEN{1’b0}} :


(bypass_ra1) ? wd : regs[ra1];

assign rd2 = (ra2 == 5’d0) ? {XLEN{1’b0}} :


(bypass_ra2) ? wd : regs[ra2];

assign rd3 = (ra3 == 5’d0) ? {XLEN{1’b0}} :


(bypass_ra3) ? wd : regs[ra3];

endmoduleule

Testbench e verificação
• Abordagem: Estı́mulos cobrem (i) reset e sp, (ii) escrita/leitura, (iii) tentativa de
escrita em x0, (iv) bypass de leitura durante escrita.

• Critérios de aceitação:

– Após o reset, x0 = 0 e x2 = 0x1001 03FC.


– Escrita em x5 persiste após a borda de clock.
– Escrita em x0 é ignorada.
– Durante escrita em wa == ra*, as leituras rd* devolvem wd (bypass).

Integração com o datapath


• Conectar rd1 e rd2 como operandos A/B da ULA; ra1 = rs1, ra2 = rs2.

• ra3 recebe o ı́ndice do registrador que será observado (por exemplo, via switches);
rd3 segue para o bloco de display/debug (ex.: mostrar t0 = x5).

• A escrita (we, wa, wd) vem do write-back (ALU/Memória/PC+4) controlado pelo


bloco de controle.

4
• O reset deve estar sincronizado com o restante do sistema; sp (x2) inicia em
0x1001 03FC.

Observações importantes
• x0 imutável: toda tentativa de escrita em x0 é ignorada (hardware força zero).

• Leituras assı́ncronas: necessárias no uniciclo para ter operandos disponı́veis no


mesmo ciclo em que a instrução é decodificada.

• Bypass de leitura: resolve dependência no mesmo ciclo entre a porta de escrita e


qualquer porta de leitura (ra1/ra2/ra3).

• Inicialização do sp: x2 recebe 0x1001 03FC no reset, conforme enunciado.

1.3 - (Gerador de Imediatos)


Objetivo
Descrever a implementação do gerador de imediatos (Immediate Generator) requerido
pela ISA RV32I reduzida. O módulo deve extrair e estender corretamente os campos de
imediato das instruções RISC-V nos formatos: I, S, B, U e J, produzindo sinais de 32 bits
com sinal estendido quando aplicável.

Especificação funcional
• Entradas:

– instr[31:0]: palavra de instrução (32 bits).


– imm sel[2:0]: seletor de tipo de imediato (codificação local: I=000, S=001,
B=010, U=011, J=100).

• Saı́das:

– imm out[31:0]: imediato resultante, sinal estendido quando necessário.

Tabelas de formatos (resumo)


I-type imm[11:0] = instr31:20[1]() (sign-extend)

S-type imm[11:0] = instr31:25[2]() &lt;&lt;5, — instr[11:7] (sign-extend)

B-type imm[12:1] = instr[31], instr[7], instr30:25[3](), instr[11:8] &lt;&lt;1 (sign-extend


com LSB zero)

U-type imm31:12[4]() = instr31:12[5]() (upper 20 bits; sem extensão de sinal para des-
locamento de 20 bits)

J-type imm[20:1] = instr[31], instr19:12[6](), instr[20], instr30:21[7]() &lt;&lt;1 (sign-


extend)

5
Implementação em Verilog
Inclua o seguinte módulo no seu projeto (exemplo claro e compacto):

// immediate_generator.v module immediate_generator ( input wire [31:0] instr,


input wire [2:0] imm_sel,
// 000=I,001=S,010=B,011=U,100=J output reg [31:0] imm_out );

wire [31:0] imm_i, imm_s, imm_b, imm_u, imm_j;

assign imm_i = {{20{instr[31]}}, instr31:20[8]()};


assign imm_s = {{20{instr[31]}}, instr31:25[9](), instr[11:7]};
assign imm_b = {{19{instr[31]}}, instr[31], instr[7], instr30:25[10](), instr[11:8], 1
assign imm_u = {instr31:12[11](), 12’b0};
assign imm_j = {{11{instr[31]}}, instr[31], instr19:12[12](), instr[20], instr30:21[13

always @(*) begin


case (imm_sel)
3’b000: imm_out = imm_i; // I
3’b001: imm_out = imm_s; // S
3’b010: imm_out = imm_b; // B
3’b011: imm_out = imm_u; // U
3’b100: imm_out = imm_j; // J
default: imm_out = 32’b0;
endcase
end

endmodule

Testbench e verificação
• Escreva um testbench simples que injete instruções exemplo cobrindo cada formato
e compare imm out com valores esperados.

• Gere formas de onda (ModelSim/Quartus) e inclua trechos no relatório: cada teste


deve mostrar a instrução de entrada, o seletor imm sel e a saı́da imm out com a
extensão correta.

• Exemplo de vetores de teste (valores em hex):

– I-type: instr = 0xFFF70713 (addi x14,x14,-1) -> imm = 0xFFFFFFFF


– S-type: instr = 0x00F78223 (sw x15,4(x15)) -> imm = 0x00000004
– B-type: instr = 0xFE079AE3 (beq x15,x0,-24) -> imm = 0xFFFFFFE8
– U-type: instr = 0x000FF037 (lui x0,0x000FF) -> imm = 0x000FF000
– J-type: instr = 0x004000EF (jal x1,4) -> imm = 0x00000004

6
Integração com o datapath
Explique sucintamente como conectar o imm out ao somador da ULA (para cálculos
I-type, load/store), ao gerador do endereço de desvio (B e J) e ao sinal de escrita do
registrador de destino (para JAL/JALR). Indique também o sinal de controle imm sel
vindo do Bloco Controlador.

Observações importantes
• Tenha atenção especial às rotações de bits e ordenação correta ao concatenar os
campos (indices no Verilog).

• Valide casos de sinal negativo (bit 31 = 1) para todos os formatos que exigem
extensão de sinal.

1.4 - Dump de memória (.mif ) e integração no projeto)


Objetivo
Descrever os passos para gerar os arquivos MIF (Memory Initialization File) a partir
do Rars16 Custom2 e integrar os arquivos de1 [Link] e de1 [Link] nas memórias
do seu projeto Quartus/TopDE.

Passos no Rars16 Custom2


1. Abra o RARS16 Custom2 e carregue o seu arquivo de texto (.s) com o programa de
teste (por exemplo, de1.s ou de1 text).

2. Na barra de menu, vá em File → Dump Memory.

3. Escolha o formato MIF 32 Format e defina o endereço de inı́cio do segmento de


texto como 0x00400000 (conforme enunciado).

4. Salve o arquivo sem extensão (nome sugerido: de1) — o RARS criará automatica-
mente de1 [Link] e de1 [Link].

Formato MIF (exemplo)


Abaixo um exemplo reduzido do conteúdo de um arquivo MIF com palavras de 32 bits
(endereços em hexadecimal):

-- de1_text.mif DEPTH = 1024; WIDTH = 32; ADDRESS_RADIX = HEX; DATA_RADIX = HEX; CONT

Explique que o endereço 0x000 no MIF corresponde à primeira palavra do bloco de


memória que o Quartus irá mapear no endereço base definido no seu sistema (no enunci-
ado: .text começa em 0x0040 0000 e .data em 0x1001 0000).

7
Integração no Quartus / TopDE
• Copie os arquivos de1 [Link] e de1 [Link] para a pasta do projeto (por exem-
plo, project/memory/).

• Na criação das memórias (IP Blocks ou blocos RTL já providos no TopDE), configure
o arquivo de inicialização (MIF) para cada memória:

– Memória de instruções (ROM/ROM-like): inicializar com de1 [Link].


– Memória de dados (RAM): inicializar com de1 [Link] (se desejar dados
pré-carregados).

• Verifique os parâmetros: WIDTH = 32, DEPTH = 1024; caso use blocos de memória
do FPGA, certifique-se do endianness e da correspondência de palavra.

Ajuste de clock e latência de memória


Como citado no enunciado: as memórias FPGA quantizadas costumam ter latência
de 2 ciclos para operação de leitura/escrita. Logo:
• Ajuste o clock da CPU para metade da frequência da memória, ou implemente um
estágio extra de latch para acomodar a latência (solução recomendada: dividir o
clock com um flop/contador quando fizer simulação temporal no .vwf).

• Documente no relatório experimental como você tratou a latência: alteração de


CLOCK no arquivo .vwf, inserção de registradores pipeline (se aplicável) ou uso de
controle de enable para memória.

Geração dos arquivos finais


Na entrega, inclua no ZIP:
• [Link] (ou diretório do projeto Quartus completo);

• de1 [Link] e de1 [Link];

• Fontes Verilog (.v) incluindo immediate generator.v;

• Arquivos .vwf usados nas simulações (formas de onda), e screenshots das simulações
e do RTL netlist.

Exemplo: verificação prática


Descreva brevemente (e inclua em relatório):
1. Abra o .vwf no ModelSim/Quartus e rode a simulação funcional com o programa
de1.s carregado.

2. Capture a forma de onda que mostra o fetch das instruções no endereço inicial
(0x0040 0000) e o carregamento de um valor do .data em 0x1001 0000.

3. Mostre que, quando a memória exige 2 ciclos para ler, o valor aparece no ciclo
esperado (documente os ı́ndices de tempo nas imagens).

8
Observações finais
• Sempre verifique o mapeamento de endereços entre o MIF e os módulos de memória
do Quartus;

• Inclua prints do RARS mostrando o dump e os nomes gerados dos arquivos para
evidência;

• Em caso de divergência entre simulação e sı́ntese (comportamento diferente no


FPGA), investigue sinais de inicialização e ’reset’ das memórias.

1.5)
Na questão 1.5 é pedido a implementação da ULA mı́nima necessária, com add,sub,and,
or, slt, zero. Para o controle da ULA foi considerado que a ógica das linhas de controle
descritas na imagem da figura 2. O zero foi definido como a excessão pelo default. Desse
modo foi implementado o código que pode ser visto nas figuras 3 e 4.

Figura 2: Tabela de linhas de comando para o controlador da ULA retirado dos slides da
disciplina.

Figura 3: Primeira parte do código em verilog para a implementação da ULA.

9
Figura 4: Segunda parte do código em verilog para a implementação da ULA.

1.6)
Na questão 1.6 do relatório é pedido a implementação do controlador da ULA e do
banco de controle do processador. Os mesmos podem ser vizualizados nas figuras 3 a 10.

Figura 5: Primeira parte do código em verilog para implementação do controlador da


ULA.

10
Figura 6: Segunda parte do código em verilog para implementação do controlador da
ULA.

1.7)Implemente o Processador Uniciclo Completo


a)Visualize o netlist RTL view.
A figura 11 mostra a visão RTL do módulo TopDE, que representa o sistema completo
incluindo a CPU Uniciclo, memória de instruções e memória de dados.
A figura 12 apresenta a visão expandida do módulo Uniciclo, onde é possı́vel observar
todos os componentes internos do processador e suas interconexões.
A figuras 13 mostram os módulos individuais que compõem o processador:

1.0.1 b) Levante os requisitos fı́sicos e temporais do seu processador com-


pleto. Verifique se os slacks de setup e hold estão sendo cumpridos.
Os requisitos fı́sicos do processador foram obtidos através do relatório de compilação
do Quartus II e são apresentados na Tabela 1.

Recurso Quantidade Utilização


Total logic elements [32 / 114,480] [ ¡1%]
Total registers [31]
Total memory bits [0 / 3,981,312] [0%]
Total pins [108 / 529] [20%]

Tabela 1: Recursos fı́sicos utilizados pela implementação do processador RISC-V uniciclo.

A análise temporal foi realizada utilizando o TimeQuest Timing Analyzer, com os


resultados apresentados na Tabela 2.
Análise dos Resultados:

• Setup Slack: O valor positivo de [VALOR] ns indica que o tempo de estabilização


dos sinais antes da borda de clock é satisfeito, garantindo operação confiável.

11
Figura 7: Terceira parte do código em verilog para implementação do controlador da
ULA.

Parâmetro Valor CLOCK


Setup Slack [-2.155] ns [-0.040]
Hold Slack [-0,427] ns [0.063]
Fmax Máxima [316.96] MHz

Tabela 2: Análise temporal do processador - Slack de setup e hold.

• Hold Slack: O valor positivo de [VALOR] ns assegura que os sinais permanecem


estáveis após a borda de clock, prevenindo metaestabilidade.

• Frequência Máxima: A frequência de [VALOR] MHz representa o limite opera-


cional do processador dentro das restrições de timing.

Conclusão: Os resultados demonstram que o processador implementado atende a


todos os requisitos de timing, com ambos os slacks de setup e hold sendo cumpridos.
A arquitetura desenvolvida é capaz de operar na frequência máxima especificada sem
violações temporais, validando o correto funcionamento do projeto.

b)
c)
d)

12
Figura 8: Primeira parte do código em verilog para implementação do bloco de controle.

Figura 9: Segunda parte do código em verilog para implementação do bloco de controle.

13
Figura 10: Terceira parte do código em verilog para implementação bloco de controle.

Figura 11: Visão RTL do módulo TopDE mostrando a hierarquia completa do sistema.

14
Figura 12: Visão RTL detalhada do módulo Uniciclo com todos os submodules.

Figura 13: Módulos

15

Você também pode gostar