From f3f136a382f589322cd14893fe63e112612e1620 Mon Sep 17 00:00:00 2001 From: Florian Zaruba Date: Wed, 12 Apr 2017 17:38:23 +0200 Subject: [PATCH] Restructuring tb, more ready for UVM port --- tb/models/scoreboard.sv | 56 +++++++++ tb/scoreboard_tb.sv | 263 ++++++++++++++++++++++------------------ 2 files changed, 199 insertions(+), 120 deletions(-) create mode 100755 tb/models/scoreboard.sv diff --git a/tb/models/scoreboard.sv b/tb/models/scoreboard.sv new file mode 100755 index 000000000..e1352ae1f --- /dev/null +++ b/tb/models/scoreboard.sv @@ -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 \ No newline at end of file diff --git a/tb/scoreboard_tb.sv b/tb/scoreboard_tb.sv index 7bdb228ee..609321f8c 100755 --- a/tb/scoreboard_tb.sv +++ b/tb/scoreboard_tb.sv @@ -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 \ No newline at end of file