EDA Playground'da Dene

Scoreboard

Gün 7: Bitirme Projesi - Bölüm 2 | Referans model ile DUT çıkışını karşılaştırma

Scoreboard (puan tablosu), doğrulamanın "hakem"idir. ALU mimarimizde driver'ın gönderdiği beklenen işlemle, monitor'ün gözlediği gerçek DUT çıkışını karşılaştırır ve bir bağımsız referans modeliyle DUT'un doğru çalışıp çalışmadığına karar verir.

Scoreboard ve Mimarideki Yeri

Scoreboard iki mailbox'tan beslenir:

  • drv2scb: Driver'dan gelen beklenen (uygulanan) transaction.
  • mon2scb: Monitor'den gelen gerçek (gözlenen) DUT çıkışı.

Her iki kaynaktan birer transaction alıp eşleştirir. Beklenen değer DUT'tan değil, scoreboard'un kendi içindeki referans modelinden (compute_reference) hesaplanır. Bu sayede DUT'un çıkışı bağımsız bir "altın model"e (golden model) karşı sınanır.

Referans Model (Golden Model)

compute_reference, ALU davranışını saf yazılımda yeniden modeller. Donanımdan tamamen bağımsız bu hesap, "doğru cevabın" ne olması gerektiğini söyler. DUT'un sonucu bu beklenen değerle uyuşmazsa hata raporlanır.

Kapsamla (Coverage) İşbirliği

Scoreboard, gözlenen her transaction'ı (actual) cov.sample(actual) ile coverage bileşenine de iletir. Böylece hangi senaryoların gerçekten test edildiği ölçülür. Scoreboard, cov nesnesini yapıcısında kendisi oluşturur.

Kaynak Kod

// =============================================================================
// GUN 7 - Konu 2: Scoreboard - Referans Model ile DUT Karsilastirmasi
// =============================================================================
class ALU_Scoreboard;
  mailbox #(ALU_Transaction) drv2scb;  // Driver'dan beklenen
  mailbox #(ALU_Transaction) mon2scb;  // Monitor'den gercek

  int pass_count = 0;
  int fail_count = 0;
  int total_count = 0;

  ALU_Coverage cov;

  function new(mailbox #(ALU_Transaction) drv_mbx, mailbox #(ALU_Transaction) mon_mbx);
    this.drv2scb = drv_mbx;
    this.mon2scb = mon_mbx;
    this.cov = new(); 
  endfunction

  task run();
    ALU_Transaction expected, actual;
    logic [15:0] ref_result;
    logic [3:0]  ref_flags;

    $display("[Scoreboard] Baslatildi");

    forever begin
      drv2scb.get(expected);
      mon2scb.get(actual);
      total_count++;

      // Referans model hesaplama
      compute_reference(expected.opcode, expected.operand_a, expected.operand_b,
                        ref_result, ref_flags);

      // Karsilastirma
      if (actual.result === ref_result) begin
        pass_count++;
      end else begin
        fail_count++;
        $display("[Scoreboard] HATA #%0d!", total_count);
        $display("  Islem    : %s", expected.opcode.name());
        $display("  A=0x%02h, B=0x%02h", expected.operand_a, expected.operand_b);
        $display("  Beklenen : result=0x%04h, flags=%04b", ref_result, ref_flags);
        $display("  Gercek   : result=0x%04h, flags=%04b", actual.result, actual.flags);
      end

	  // Actual degerler Coverage'a gönderilir
      cov.sample(actual); 

    end
  endtask

  // Referans model: ALU davranisini yazilimda modelle
  function void compute_reference(
    ALU_Transaction::opcode_e opcode,
    logic [7:0] a, logic [7:0] b,
    output logic [15:0] result,
    output logic [3:0] flags
  );
    logic [16:0] temp;
    flags = 0;

    case (opcode)
      ALU_Transaction::OP_ADD: begin
        temp = {1'b0, a} + {1'b0, b};
        result = temp[15:0];
        flags[2] = temp[8];  // carry
        flags[3] = (a[7] == b[7]) && (temp[7] != a[7]);  // overflow
      end
      ALU_Transaction::OP_SUB: begin
        temp = {1'b0, a} - {1'b0, b};
        result = temp[15:0];
        flags[2] = temp[8];  // borrow
        flags[3] = (a[7] != b[7]) && (temp[7] != a[7]);  // overflow
      end
      ALU_Transaction::OP_AND: result = {8'h00, a & b};
      ALU_Transaction::OP_OR:  result = {8'h00, a | b};
      ALU_Transaction::OP_XOR: result = {8'h00, a ^ b};
      ALU_Transaction::OP_NOT: result = {8'h00, ~a};
      ALU_Transaction::OP_SHL: result = a << b[2:0];
      ALU_Transaction::OP_SHR: result = a >> b[2:0];
    endcase

    // Zero & Negative
    if (opcode inside {ALU_Transaction::OP_ADD, ALU_Transaction::OP_SUB})
      flags[0] = (temp[7:0] == 0);
    else
      flags[0] = (result == 0);
    flags[1] = result[15] | result[7];
  endfunction

  function void report();
    $display("\n  ========== SCOREBOARD RAPORU ==========");
    $display("  Toplam  : %0d", total_count);
    $display("  Basarili: %0d", pass_count);
    $display("  Basarisiz: %0d", fail_count);
    if (fail_count == 0)
      $display("  *** TUM TESTLER BASARILI! ***");
    else
      $display("  !!! %0d HATA TESPIT EDILDI !!!", fail_count);
    $display("  ========================================");
    
  endfunction
endclass

Kodun Açıklaması

  • Üyeler: drv2scb ve mon2scb mailbox'ları beklenen ve gerçek transaction'ları taşır. pass_count, fail_count, total_count istatistikleri tutar. cov ise coverage nesnesidir ve yapıcıda new() ile oluşturulur.
  • run(): Sonsuz döngüde drv2scb.get(expected) ve mon2scb.get(actual) ile bir beklenen ve bir gerçek transaction'ı eşleştirir, total_count++ yapar.
  • Referans hesabı: compute_reference(...) ile beklenen ref_result ve ref_flags hesaplanır.
  • Karşılaştırma: if (actual.result === ref_result) ile sonuç kontrol edilir. === operatörü x/z durumlarını da kesin karşılaştırır. Eşleşmezse hata detayları (opcode.name(), operandlar, beklenen ve gerçek değerler) basılır ve fail_count++ yapılır.
  • cov.sample(actual): Gerçek değerler her çevrimde kapsam toplamaya gönderilir.
  • compute_reference(...): OP_ADD/OP_SUB için 17-bit temp ile carry ve overflow bayraklarını hesaplar; mantıksal ve kaydırma işlemlerini ayrı case dallarında modeller. Zero bayrağı aritmetik işlemlerde temp[7:0], diğerlerinde result üzerinden belirlenir; negatif bayrağı result[15] | result[7] ile hesaplanır.
  • report(): Toplam/başarılı/başarısız sayıları ve geçti/kaldı özetini ekrana basar.

Önemli Noktalar

  • Referans modelin DUT'tan bağımsız olması esastır; aksi halde aynı hatayı iki yerde yapıp hatayı göremezsiniz.
  • Karşılaştırmada === kullanımı, sonuçtaki olası x/z durumlarını da yakalar; == bu durumlarda yanıltıcı olabilir.
  • Bu scoreboard yalnızca result'ı karşılaştırır (actual.result === ref_result); bayraklar hesaplanıp raporlansa da pass/fail kararına dahil edilmemiştir. Bu, bilinçli bir kapsam sınırı olarak akılda tutulmalıdır.
  • Driver ve monitor akışlarının hizalı kalması kritiktir; her beklenen transaction tam bir gözlemle eşleşmelidir, yoksa get çağrıları kayar.
  • compute_reference DUT bayrak sözleşmesini bilmelidir; örneğin carry yalnızca aritmetik işlemlerde anlamlıdır ve model bunu yansıtır.