Altifigence Academy

58 / 63 · Conceito

Plano de verificação de FIFO e memória com scoreboard independente

Use uma fila de referência independente dos ponteiros e planeje a verificação de fronteiras, reset, valid e leituras de posições não inicializadas.

Usar um modelo de referência diferente do DUT

Copiar rptr e wptr para o testbench pode reproduzir o mesmo erro de ponteiros. Um scoreboardScoreboard Estado de referência do ambiente de verificação que compara, em ordem, os dados esperados com as saídas reais. É calculado de forma independente, sem copiar o estado interno da implementação. independente usa uma fila de SystemVerilog para manter a ordem lógica: um push aceito insere no final e um pop aceito retira a cabeça.

O plano de cobertura cruza vazio/intermediário/cheio com nenhuma solicitação/somente push/somente pop/ambas. Inclua várias voltas dos ponteiros, retiradas contínuas e reset com dados pendentes. Registre cobertura, semente e condições de qualquer falha.

Calcule a aceitação a partir do tamanho anterior N do modelo, sem depender de full nem da ocupação informada pelo DUT:

q=pop∧(N>0)q=pop\land(N>0)
p=push∧((N<4)∨q)p=push\land\big((N<4)\lor q\big)
N+=N+p−qN^+=N+p-q

Retire e guarde a cabeça anterior antes de inserir o dado novo. Isso representa corretamente a substituição com a FIFO cheia. Compare dout quando o q esperado for 1.

Testbench completo

Compile este testbench junto com o fifo4 da unidade anterior. A fila e os atrasos pertencem ao ambiente de verificação. As entradas são aplicadas na borda de descida; as verificações ocorrem 1 ps após a borda de subida, depois do processamento das atribuições não bloqueantesAtribuição não bloqueante Atribuição escrita com <= em RTL sequencial. Avalia o lado direito e agenda a atualização, permitindo que os registradores da mesma borda calculem a partir do estado anterior. Saiba mais.

SystemVerilog
module tb_fifo4;
  timeunit 1ns;
  timeprecision 1ps;
  typedef logic [7:0] word_t;
  logic clk=0, rst=1, push=0, pop=0;
  word_t din=0, dout;
  logic dout_valid, full, empty;
  logic [2:0] occupancy;
  word_t model[$], expected;
  bit expect_pop, expect_push;
  fifo4 dut (.*);
  always #5ns clk = ~clk;

  always @(posedge clk) begin
    if (rst) begin
      model.delete();
      expect_pop = 0;
    end else begin
      expect_pop = pop && (model.size() != 0);
      expect_push = push && ((model.size() < 4) || expect_pop);
      if (expect_pop) expected = model.pop_front();
      if (expect_push) model.push_back(din);
    end
    #1ps;
    assert (dout_valid === expect_pop)
      else $fatal(1, "valid mismatch");
    if (expect_pop)
      assert (dout === expected)
        else $fatal(1, "data mismatch");
    assert (int'(occupancy) === model.size())
      else $fatal(1, "count mismatch");
    assert (empty === (model.size() == 0))
      else $fatal(1, "empty mismatch");
    assert (full === (model.size() == 4))
      else $fatal(1, "full mismatch");
  end

  task automatic step(input bit r, p, o, input word_t d);
    @(negedge clk);
    rst=r; push=p; pop=o; din=d;
  endtask

  initial begin
    step(0,0,1,0);
    step(0,1,1,8'hA0);
    for (int i=1; i<4; i++)
      step(0,1,0,word_t'(160+i));
    step(0,1,0,8'hEE);
    step(0,1,1,8'hB0);
    repeat (5) step(0,0,1,0);
    repeat (3) begin
      for (int i=0; i<4; i++) step(0,1,0,word_t'(i));
      repeat (4) step(0,0,1,0);
    end
    step(0,1,0,8'h5A);
    step(1,1,1,8'hFF);
    step(0,0,1,0);
    repeat (100)
      step(0,bit'($urandom_range(1,0)),bit'($urandom_range(1,0)),
           word_t'($urandom));
    repeat (4) step(0,0,1,0);
    @(negedge clk);
    $display("PASS");
    $finish;
  end
endmodule

A primeira borda de subida com rst=1 esvazia tanto o DUT quanto o modelo. === compara estritamente, incluindo valores X. Não se compara dout quando inválido, mas um valid desconhecido provoca falha. Os quatro pops finais verificam os elementos restantes. PASS só é impresso se a execução real superar todas as asserções; apresentar este exemplo não equivale a tê-lo executado.

Antes de inserir B0, guarda-se A0, a cabeça anterior, como dado esperado. O modelo representa a ordem lógica da fila, sem reproduzir suas posições físicas nem seus ponteiros.

Ordem do scoreboard nas solicitações simultâneas com FIFO cheia
  1. Fila anterior: [A0, A1, A2, A3]
  2. Valor esperado do pop: Guarde a cabeça anterior A0
  3. Aplique push: [A1, A2, A3, B0]
  4. Compare a resposta: Com valid=1, dout=A0

Conferir manualmente as fronteiras do scoreboard

Com a fila [A0,A1,A2,A3], um push de EE sem pop é rejeitado. Em um push de B0 e pop simultâneos, espera-se A0 e a fila passa a [A1,A2,A3,B0]. Se o DUT retornar o novo B0, a asserção de dados falha. Com a fila vazia e ambas as solicitações, espera-se pop=0, push=1: a saída não é comparada e um elemento fica armazenado. O reset ignora as duas solicitações, esvazia a fila e exige valid=0.

Para uma memória endereçada, use um array de referência e indicadores de inicialização. Com read-first, determine a leitura esperada antes de escrever no array de referência. Em um banco de registradoresRegistrador Circuito que armazena vários bits de estado. Os registradores síncronos deste curso capturam a entrada especificada na borda de clock. Saiba mais com bypass, escolha wr_data quando houver coincidência e depois atualize o array. A precondição deve proibir leituras não inicializadas ou permitir resultado indefinido; não invente um valor esperado igual a 0. A memória endereçada precisa de seu próprio verificador.

Introduza falhas deliberadas: retornar o dado novo ao retirar de uma FIFO cheia, incrementar a ocupação com as duas operações ou ativar valid ao fazer pop de uma FIFO vazia. Cada falha deve ser detectada pela verificação correspondente. Essas mutações e a cobertura das fronteiras revelam lacunas nos testes. O mapeamento para RAM física e o cumprimento temporal exigem verificações separadas de síntese e temporização.

Experimente

Um scoreboard incorreto primeiro insere o dado de push e depois decide se aceita pop usando o tamanho já atualizado. O que ele espera incorretamente quando a FIFO vazia recebe push e pop simultâneos? Com a FIFO cheia, em que momento deve guardar o dado esperado? Avalie também uma verificação que sempre exige dout=0 após o reset.

Ler a explicação

Quando a FIFO está vazia, o scoreboard incorreto supõe que pode retirar imediatamente o dado recém-inserido e espera expect_pop=1. O contrato usa o tamanho anterior e aceita somente push, portanto valid=0. Quando a FIFO está cheia, ele deve guardar e retirar a cabeça anterior antes de inserir o dado novo. O reset não apaga dout: verificam-se valid=0, a fila vazia e a ocupação, não um dado igual a 0. O dado só é comparado quando expect_pop=1, mas valid do DUT também deve ser verificado separadamente; caso contrário, um DUT que mantém valid sempre em 0 poderia passar despercebido.

Sua escolha vale neste navegador. Altere-a a qualquer momento no rodapé.