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:
drv2scbvemon2scbmailbox'ları beklenen ve gerçek transaction'ları taşır.pass_count,fail_count,total_countistatistikleri tutar.covise coverage nesnesidir ve yapıcıdanew()ile oluşturulur. run(): Sonsuz döngüdedrv2scb.get(expected)vemon2scb.get(actual)ile bir beklenen ve bir gerçek transaction'ı eşleştirir,total_count++yapar.- Referans hesabı:
compute_reference(...)ile beklenenref_resultveref_flagshesaplanır. - Karşılaştırma:
if (actual.result === ref_result)ile sonuç kontrol edilir.===operatörüx/zdurumları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 vefail_count++yapılır. cov.sample(actual): Gerçek değerler her çevrimde kapsam toplamaya gönderilir.compute_reference(...):OP_ADD/OP_SUBiçin17-bit tempile carry ve overflow bayraklarını hesaplar; mantıksal ve kaydırma işlemlerini ayrıcasedallarında modeller. Zero bayrağı aritmetik işlemlerdetemp[7:0], diğerlerinderesultü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/zdurumları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_referenceDUT bayrak sözleşmesini bilmelidir; örneğin carry yalnızca aritmetik işlemlerde anlamlıdır ve model bunu yansıtır.