O processador dentro do seu Verilog

Até aqui os dois mundos andaram separados: Verilog escrito à mão na Parte II, processador gerado na Parte III. Este capítulo os junta: o processador vira um componente dentro de um circuito seu.

É o arranjo típico de um projeto real: o processador cuida do algoritmo, e a lógica em volta cuida do resto, como interfaces, sincronização e pré-processamento.

As portas do processador gerado

Abra Hardware/media_movel.v e olhe o cabeçalho do módulo. As portas que ele expõe:

Porta

Direção

Largura

Papel

clk

entrada

1

clock

rst

entrada

1

reset síncrono

in

entrada

NUBITS

dado de entrada

out

saída

NUBITS

dado de saída

req_in

saída

depende das portas

qual porta de entrada o programa está lendo agora

out_en

saída

depende das portas

qual porta de saída o programa está escrevendo agora

O aperto de mão é simples: quando o programa executa in(k), o processador expõe k em req_in e espera o dado presente em in; quando executa out(k, v), expõe k em out_en e v em out por um ciclo. Com uma porta só, req_in e out_en funcionam como sinais de “lendo agora” e “válido agora”.

Dica

O melhor guia de fiação é o testbench gerado, Simulation/media_movel_tb.v: ele mostra exatamente como alimentar in em função de req_in e quando capturar out. Copiar a fiação dele para o seu top-level é o caminho seguro.

Um top-level de exemplo

Um gerador de estímulo em Verilog alimentando o filtro do tutorial: um contador produz uma rampa, e o processador devolve a média móvel dela.

Listagem 7 top_filtro.v
 1module top_filtro (
 2    input  wire        clk,
 3    input  wire        rst,
 4    output wire [15:0] media,
 5    output wire        media_valida
 6);
 7
 8    // gerador de estimulo: uma rampa que sobe de 8 em 8
 9    reg [15:0] rampa;
10    wire       lendo;
11
12    always @(posedge clk) begin
13        if (rst)
14            rampa <= 16'd0;
15        else if (lendo)
16            rampa <= rampa + 16'd8;
17    end
18
19    // o processador gerado pela Parte III
20    media_movel u_filtro (
21        .clk    (clk),
22        .rst    (rst),
23        .in     (rampa),
24        .out    (media),
25        .req_in (lendo),
26        .out_en (media_valida)
27    );
28
29endmodule

Passos na AURORA:

  1. Crie top_filtro.v no projeto MeuFiltro (a classificação o marcará como sintetizável).

  2. Botão direito, Definir como Top Level. O processador deixa de ser o topo e vira um componente.

  3. Clique em Sintetizar Verilog. A elaboração resolve o módulo media_movel sozinha, porque o .v gerado está no projeto.

  4. Escreva um testbench para o top_filtro (clock, reset, $dumpvars, $finish), marque como Testbench Top e clique em Analisar Verilog.

Na onda, você verá a rampa entrando, o aperto de mão pulsando e a média saindo suavizada: dois mundos no mesmo diagrama de tempo.

Aviso

O processador carrega as memórias por $readmemb com os arquivos .mif. Recompile o C± antes de simular o conjunto, para as imagens de memória estarem atualizadas com o programa.

Hierarquia e PRISM

Com o top-level seu, a visão Hierarquia mostra o processador como uma instância entre as outras, e o PRISM desenha o conjunto: sua lógica e o processador no mesmo diagrama, cada um navegável.

Vários processadores no mesmo projeto seguem a mesma receita: crie cada um no Hub, compile cada um, e instancie todos no seu top-level. Um estudo de caso completo com dois processadores sincronizados está em Interrupção, marcador de fim e multiprocessador.

Exercícios

  1. Troque a rampa por um gerador pseudoaleatório (um LFSR de 16 bits) e observe o filtro suavizando o ruído.

  2. Insira um decimador entre o gerador e o processador: só uma a cada duas amostras chega ao filtro.

  3. Coloque dois processadores em cascata: a saída do filtro de média alimenta um segundo processador que detecta quando o valor cruza um limiar e publica 0 ou 1.

Falta só um passo para o hardware de verdade: Levar ao FPGA.