Restructuring tb, more ready for UVM port

This commit is contained in:
Florian Zaruba 2017-04-12 17:38:23 +02:00
parent 7ee4add5b6
commit f3f136a382
2 changed files with 199 additions and 120 deletions

56
tb/models/scoreboard.sv Executable file
View file

@ -0,0 +1,56 @@
class Scoreboard;
scoreboard_entry decoded_instructions[$];
scoreboard_entry issued_instructions[$];
static integer unsigned pc = 0;
// utility function to get randomized input data
static function automatic scoreboard_entry randomize_scoreboard();
exception exception = { 64'h55, 63'h0, 1'b0};
scoreboard_entry entry = {
pc, ALU, ADD, 5'h5, 5'h5, 5'h5, 64'h0, 1'b0, 1'b0, exception
};
pc++;
return entry;
endfunction : randomize_scoreboard
// just allow one operation
function void submit_instruction(scoreboard_entry entry);
decoded_instructions.push_back(entry);
endfunction : submit_instruction
// get the current issue instruction
function scoreboard_entry get_issue();
scoreboard_entry issue = decoded_instructions.pop_front();
issued_instructions.push_back(issue);
return issue;
endfunction : get_issue
// write back to scoreboard
function void write_back(logic [63:0] pc, logic [63:0] value);
for (int i = 0; i < $size(issued_instructions); i++) begin
if (issued_instructions[i].pc == pc) begin
issued_instructions[i].valid = 1'b1;
issued_instructions[i].result = value;
end
end
endfunction : write_back
// // commit the instruction, e.g.: delete it from the entries
function scoreboard_entry commit();
return issued_instructions.pop_front();
endfunction : commit
// return the clobbered registers
function logic [31:0][$bits(fu_t)-1:0] get_clobber();
logic [31:0][$bits(fu_t)-1:0] result;
for (int i = 0; i < $size(issued_instructions); i++) begin
if (issued_instructions[i].rd != 5'h0) begin
result[issued_instructions[i].rd] = issued_instructions[i].fu;
end
end
return result;
endfunction : get_clobber
endclass : Scoreboard

View file

@ -7,58 +7,40 @@
// All rights reserved.
//
// TODO, test register read and clobber interface, make a proper TB out of it
module scoreboard_tb;
import uvm_pkg::*;
import ariane_pkg::*;
logic rst_ni, clk;
scoreboard_entry scoreboard_queue[$];
scoreboard_entry temp_scoreboard_entry;
scoreboard_entry comp;
semaphore wb_lock = new(1);
module scoreboard_tb;
integer unsigned pc = 0;
`include "models/scoreboard.sv"
scoreboard_if scoreboard_if (clk);
logic rst_ni, clk;
scoreboard_if scoreboard_if (clk);
scoreboard dut (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.full_o ( scoreboard_if.full ),
.flush_i ( scoreboard_if.flush ),
.rd_clobber_o ( scoreboard_if.rd_clobber ),
.rs1_i ( scoreboard_if.rs1_address ),
.rs1_o ( scoreboard_if.rs1 ),
.rs1_valid_o ( scoreboard_if.rs1_valid ),
.rs2_i ( scoreboard_if.rs2_address ),
.rs2_o ( scoreboard_if.rs2 ),
.rs2_valid_o ( scoreboard_if.rs2_valid ),
.commit_instr_o ( scoreboard_if.commit_instr ),
.commit_ack_i ( scoreboard_if.commit_ack ),
.decoded_instr_i ( scoreboard_if.decoded_instr ),
.decoded_instr_valid_i( scoreboard_if.decoded_instr_valid ),
.issue_instr_o ( scoreboard_if.issue_instr ),
.issue_instr_valid_o ( scoreboard_if.issue_instr_valid ),
.issue_ack_i ( scoreboard_if.issue_ack ),
.pc_i ( scoreboard_if.pc ),
.wdata_i ( scoreboard_if.wdata ),
.wb_valid_i ( scoreboard_if.wb_valid )
);
function automatic scoreboard_entry randomize_scoreboard();
exception exception = { 64'h55, 63'h0, 1'b0};
scoreboard_entry entry = {
pc, ALU, ADD, 5'h5, 5'h5, 5'h5, 64'h0, 1'b0, 1'b0, exception
};
pc++;
return entry;
endfunction : randomize_scoreboard
initial begin
// register the scoreboard interface
// uvm_config_db #(virtual scoreboard_if)::set(null, "uvm_test_top", "scoreboard_vif", scoreboard_if);
end
scoreboard dut (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.full_o ( scoreboard_if.full ),
.flush_i ( scoreboard_if.flush ),
.rd_clobber_o ( scoreboard_if.rd_clobber ),
.rs1_i ( scoreboard_if.rs1_address ),
.rs1_o ( scoreboard_if.rs1 ),
.rs1_valid_o ( scoreboard_if.rs1_valid ),
.rs2_i ( scoreboard_if.rs2_address ),
.rs2_o ( scoreboard_if.rs2 ),
.rs2_valid_o ( scoreboard_if.rs2_valid ),
.commit_instr_o ( scoreboard_if.commit_instr ),
.commit_ack_i ( scoreboard_if.commit_ack ),
.decoded_instr_i ( scoreboard_if.decoded_instr ),
.decoded_instr_valid_i( scoreboard_if.decoded_instr_valid ),
.issue_instr_o ( scoreboard_if.issue_instr ),
.issue_instr_valid_o ( scoreboard_if.issue_instr_valid ),
.issue_ack_i ( scoreboard_if.issue_ack ),
.pc_i ( scoreboard_if.pc ),
.wdata_i ( scoreboard_if.wdata ),
.wb_valid_i ( scoreboard_if.wb_valid )
);
initial begin
clk = 1'b0;
@ -71,88 +53,129 @@ scoreboard dut (
#10ns clk = ~clk;
end
// push new decoded instructions
initial begin
wait(rst_ni == 1'b1);
// load the scoreboard until it is full
forever begin
program testbench (scoreboard_if scoreboard_if);
// variable declarations
Scoreboard sb = new;
semaphore wb_lock = new(1);
@(scoreboard_if.mck);
// if we are not full load another instruction
if (scoreboard_if.full == 1'b0) begin
temp_scoreboard_entry = randomize_scoreboard();
scoreboard_queue.push_back(temp_scoreboard_entry);
scoreboard_if.mck.decoded_instr <= temp_scoreboard_entry;
scoreboard_if.mck.decoded_instr_valid <= 1'b1;
end else begin
scoreboard_if.mck.decoded_instr_valid <= 1'b0;
end
assign scoreboard_if.flush = 1'b0;
initial begin
// register the scoreboard interface
// uvm_config_db #(virtual scoreboard_if)::set(null, "uvm_test_top", "scoreboard_vif", scoreboard_if);
end
end
scoreboard_entry issue_instruction;
// pull e.g. issue instructions
initial begin
wait(rst_ni == 1'b1);
forever begin
@(scoreboard_if.mck);
// push new decoded instructions
initial begin
scoreboard_if.mck.decoded_instr_valid <= 1'b0;
wait(rst_ni == 1'b1);
// load the scoreboard until it is full
forever begin
// if we are not full then load another instruction
if (scoreboard_if.issue_instr_valid == 1'b1) begin
scoreboard_if.mck.issue_ack <= 1'b1;
issue_instruction <= scoreboard_if.mck.issue_instr;
$display("Time: %t, Issuing: %0h, Valid: %h", $time, scoreboard_if.mck.issue_instr.pc, scoreboard_if.issue_instr_valid);
@(scoreboard_if.mck)
scoreboard_if.mck.issue_ack <= 1'b0;
// generate a delay between 0 and 3 cycles for WB, write-back out of order
fork
write_back: begin
automatic scoreboard_entry thread_copy = issue_instruction;
repeat ($urandom_range(0,20)) @(scoreboard_if.mck);
wb_lock.get(1);
$display("Time: %t, Writing Back: %0h", $time, thread_copy.pc);
scoreboard_if.mck.pc <= thread_copy.pc;
scoreboard_if.mck.wdata <= 64'h7777;
scoreboard_if.mck.wb_valid <= 1'b1;
@(scoreboard_if.mck);
scoreboard_if.mck.wb_valid <= 1'b0;
wb_lock.put(1);
end
join_none
end else begin
scoreboard_if.mck.issue_ack <= 1'b0;
end
end
end
// commit instructions
initial begin
wait(rst_ni == 1'b1);
forever begin
repeat ($urandom_range(1,3)) @(scoreboard_if.mck);
if (scoreboard_if.mck.commit_instr.valid == 1'b1) begin
$display("Time: %t, Commiting: %0h", $time, scoreboard_if.mck.commit_instr.pc);
scoreboard_if.mck.commit_ack <= 1'b1;
@(scoreboard_if.mck);
scoreboard_if.mck.commit_ack <= 1'b0;
repeat ($urandom_range(0,3)) @(scoreboard_if.mck);
end else
scoreboard_if.mck.commit_ack <= 1'b0;
end
end
// commit checker e.g.: monitor
initial begin
wait(rst_ni == 1'b1);
// if we are not full load another instruction
if (scoreboard_if.full == 1'b0) begin
scoreboard_if.mck.decoded_instr <= Scoreboard::randomize_scoreboard();
scoreboard_if.mck.decoded_instr_valid <= 1'b1;
end else begin
scoreboard_if.mck.decoded_instr_valid <= 1'b0;
end
forever begin
@(scoreboard_if.pck);
if (scoreboard_if.pck.commit_ack == 1'b1) begin
comp = scoreboard_queue.pop_front();
assert (comp.pc === scoreboard_if.pck.commit_instr.pc) else $error($sformatf("Mismatch: Expected: %0h Got: %0h", comp.pc, scoreboard_if.pck.commit_instr.pc));
end
end
end
scoreboard_entry issue_instruction;
// pull e.g. issue instructions
initial begin
wait(rst_ni == 1'b1);
forever begin
@(scoreboard_if.mck);
// if we are not full then load another instruction
if (scoreboard_if.issue_instr_valid == 1'b1) begin
scoreboard_if.mck.issue_ack <= 1'b1;
issue_instruction <= scoreboard_if.mck.issue_instr;
// $display("Time: %t, Issuing: %0h, Valid: %h", $time, scoreboard_if.mck.issue_instr.pc, scoreboard_if.issue_instr_valid);
@(scoreboard_if.mck)
scoreboard_if.mck.issue_ack <= 1'b0;
// generate a delay between 0 and 3 cycles for WB, write-back out of order
fork
write_back: begin
automatic scoreboard_entry thread_copy = issue_instruction;
automatic logic [63:0] rand_data = $urandom_range(0, 2**31);
repeat ($urandom_range(1,20)) @(scoreboard_if.mck);
wb_lock.get(1);
// $display("Time: %t, Writing Back: %0h", $time, thread_copy.pc);
scoreboard_if.mck.pc <= thread_copy.pc;
scoreboard_if.mck.wdata <= rand_data;
scoreboard_if.mck.wb_valid <= 1'b1;
sb.write_back(thread_copy.pc, rand_data);
@(scoreboard_if.mck);
scoreboard_if.mck.wb_valid <= 1'b0;
wb_lock.put(1);
end
join_none
end else begin
scoreboard_if.mck.issue_ack <= 1'b0;
end
end
end
// commit instructions
initial begin
wait(rst_ni == 1'b1);
forever begin
repeat ($urandom_range(1,3)) @(scoreboard_if.mck);
if (scoreboard_if.mck.commit_instr.valid == 1'b1) begin
// $display("Time: %t, Commiting: %0h", $time, scoreboard_if.mck.commit_instr.pc);
scoreboard_if.mck.commit_ack <= 1'b1;
@(scoreboard_if.mck);
scoreboard_if.mck.commit_ack <= 1'b0;
repeat ($urandom_range(0,3)) @(scoreboard_if.mck);
end else
scoreboard_if.mck.commit_ack <= 1'b0;
end
end
// ------------------
// Monitor + Checker
// ------------------
initial begin
wait(rst_ni == 1'b1);
forever begin
@(scoreboard_if.pck);
if (scoreboard_if.pck.decoded_instr_valid == 1'b1) begin
sb.submit_instruction(scoreboard_if.pck.decoded_instr);
end
end
end
scoreboard_entry tmp_sbe;
initial begin
wait(rst_ni == 1'b1);
forever begin
@(scoreboard_if.pck);
if (scoreboard_if.pck.issue_instr_valid == 1'b1 && scoreboard_if.pck.issue_ack) begin
tmp_sbe = sb.get_issue();
assert (tmp_sbe.pc == issue_instruction.pc) else $error("Issue instruction mismatch. Expected: %0h Got: %0h", tmp_sbe, issue_instruction);
end
end
end
// commit checker
scoreboard_entry comp;
initial begin
wait(rst_ni == 1'b1);
forever begin
@(scoreboard_if.pck);
if (scoreboard_if.pck.commit_ack == 1'b1) begin
comp = sb.commit();
assert (comp === scoreboard_if.pck.commit_instr) else $error($sformatf("Mismatch: Expected: %0h Got: %0h", comp, scoreboard_if.pck.commit_instr));
end
end
end
endprogram
testbench tb(scoreboard_if);
endmodule