mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 06:07:19 -04:00
Issuing write back out of order, fixed bug in comb
This commit is contained in:
parent
e66a683e8d
commit
7ee4add5b6
3 changed files with 51 additions and 33 deletions
|
@ -49,9 +49,9 @@ module scoreboard #(
|
|||
);
|
||||
localparam BITS_ENTRIES = $clog2(NR_ENTRIES);
|
||||
|
||||
dtype [NR_ENTRIES-1:0] mem;
|
||||
dtype [NR_ENTRIES-1:0] mem_q, mem_n;
|
||||
logic [BITS_ENTRIES-1:0] issue_pointer_n, issue_pointer_q, // points to the instruction currently in issue
|
||||
commit_pointer_n, commit_pointer_q, commit_pointer_qq, // points to the instruction currently in commit
|
||||
commit_pointer_n, commit_pointer_q, // points to the instruction currently in commit
|
||||
top_pointer_n, top_pointer_q, top_pointer_qq; // points to the top of the scoreboard, an empty slot, top pointer two cycles ago
|
||||
|
||||
logic pointer_overflow;
|
||||
|
@ -84,12 +84,12 @@ always_comb begin : clobber_output
|
|||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
// non overflowed case, depicted on the left
|
||||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q && i[BITS_ENTRIES-1:0] < issue_pointer_q)
|
||||
rd_clobber_o[mem[i].rd] = mem[i].fu;
|
||||
rd_clobber_o[mem_q[i].rd] = mem_q[i].fu;
|
||||
end
|
||||
end else begin // the issue pointer has overflowed, invert logic, depicted on the right
|
||||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q || i[BITS_ENTRIES-1:0] < issue_pointer_q)
|
||||
rd_clobber_o[mem[i].rd] = mem[i].fu;
|
||||
rd_clobber_o[mem_q[i].rd] = mem_q[i].fu;
|
||||
end
|
||||
end
|
||||
// the zero register is always free
|
||||
|
@ -108,13 +108,13 @@ always_comb begin : read_operands
|
|||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q && i[BITS_ENTRIES-1:0] < issue_pointer_q) begin
|
||||
// look at the appropriate fields and look whether there was an
|
||||
// instruction that wrote the rd field before, first for RS1 and then for RS2
|
||||
if (mem[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_o = mem[i].result;
|
||||
rs1_valid_o = mem[i].valid;
|
||||
if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_o = mem_q[i].result;
|
||||
rs1_valid_o = mem_q[i].valid;
|
||||
// do the same for rs2
|
||||
end else if (mem[i].rd == rs2_i) begin
|
||||
rs2_o = mem[i].result;
|
||||
rs2_valid_o = mem[i].valid;
|
||||
end else if (mem_q[i].rd == rs2_i) begin
|
||||
rs2_o = mem_q[i].result;
|
||||
rs2_valid_o = mem_q[i].valid;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -122,13 +122,13 @@ always_comb begin : read_operands
|
|||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q || i[BITS_ENTRIES-1:0] < issue_pointer_q) begin
|
||||
// same as above but for the overflowed pointer case
|
||||
if (mem[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_o = mem[i].result;
|
||||
rs1_valid_o = mem[i].valid;
|
||||
if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs1_i) begin
|
||||
rs1_o = mem_q[i].result;
|
||||
rs1_valid_o = mem_q[i].valid;
|
||||
// do the same for rs2
|
||||
end else if (mem[i[BITS_ENTRIES-1:0]].rd == rs2_i) begin
|
||||
rs2_o = mem[i].result;
|
||||
rs2_valid_o = mem[i].valid;
|
||||
end else if (mem_q[i[BITS_ENTRIES-1:0]].rd == rs2_i) begin
|
||||
rs2_o = mem_q[i].result;
|
||||
rs2_valid_o = mem_q[i].valid;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -144,9 +144,10 @@ end
|
|||
always_latch begin : push_instruction_and_wb
|
||||
// default assignment
|
||||
top_pointer_n = top_pointer_q;
|
||||
mem_n = mem_q;
|
||||
// if we are not full we can push a new instruction
|
||||
if (~full_o && decoded_instr_valid_i) begin
|
||||
mem[$unsigned(top_pointer_q)] = decoded_instr_i;
|
||||
mem_n[$unsigned(top_pointer_q)] = decoded_instr_i;
|
||||
top_pointer_n = top_pointer_q + 1;
|
||||
end
|
||||
|
||||
|
@ -155,16 +156,16 @@ always_latch begin : push_instruction_and_wb
|
|||
// also set the valid bit
|
||||
if (wb_valid_i) begin
|
||||
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
|
||||
if (mem[i].pc == pc_i) begin
|
||||
mem[i].valid = 1'b1;
|
||||
mem[i].result = wdata_i;
|
||||
if (mem_q[i].pc == pc_i) begin
|
||||
mem_n[i].valid = 1'b1;
|
||||
mem_n[i].result = wdata_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// flush signal
|
||||
if (flush_i)
|
||||
mem = '{default: 0};
|
||||
mem_n = '{default: 0};
|
||||
|
||||
end
|
||||
|
||||
|
@ -173,16 +174,16 @@ always_comb begin : issue_instruction
|
|||
|
||||
|
||||
// provide a combinatorial path in case the scoreboard is empty
|
||||
if (empty) begin
|
||||
if (top_pointer_q == issue_pointer_q) begin
|
||||
issue_instr_o = decoded_instr_i;
|
||||
issue_instr_valid_o = decoded_instr_valid_i;
|
||||
// if not empty go to scoreboard and get the instruction at the issue pointer
|
||||
end else begin
|
||||
issue_instr_o = mem[$unsigned(issue_pointer_q)];
|
||||
issue_instr_o = mem_q[$unsigned(issue_pointer_q)];
|
||||
// we have not reached the top of the buffer
|
||||
// issue pointer has overflowed
|
||||
if (issue_pointer_q < commit_pointer_q) begin
|
||||
if (issue_pointer_q <= top_pointer_q)
|
||||
if (issue_pointer_q <= commit_pointer_q) begin
|
||||
if (issue_pointer_q < top_pointer_q)
|
||||
issue_instr_valid_o = 1'b1;
|
||||
else
|
||||
issue_instr_valid_o = 1'b0;
|
||||
|
@ -210,7 +211,7 @@ always_comb begin: commit_instruction
|
|||
commit_pointer_n = commit_pointer_q;
|
||||
// we can always safely output the instruction at which the commit pointer points
|
||||
// since the scoreboard entry has a valid bit which the commit stage needs to check anyway
|
||||
commit_instr_o = mem[commit_pointer_q];
|
||||
commit_instr_o = mem_q[commit_pointer_q];
|
||||
if (commit_ack_i) begin
|
||||
commit_pointer_n = commit_pointer_q + 1;
|
||||
end
|
||||
|
@ -223,15 +224,18 @@ always_ff @(posedge clk_i or negedge rst_ni) begin : sequential
|
|||
commit_pointer_q <= '{default: 0};
|
||||
top_pointer_q <= '{default: 0};
|
||||
top_pointer_qq <= '{default: 0};
|
||||
mem_q <= '{default: 0};
|
||||
end else if (flush_i) begin // reset pointers on flush
|
||||
issue_pointer_q <= '{default: 0};
|
||||
commit_pointer_q <= '{default: 0};
|
||||
top_pointer_q <= '{default: 0};
|
||||
top_pointer_qq <= '{default: 0};
|
||||
mem_q <= '{default: 0};
|
||||
end else begin
|
||||
issue_pointer_q <= issue_pointer_n;
|
||||
commit_pointer_q <= commit_pointer_n;
|
||||
top_pointer_q <= top_pointer_n;
|
||||
mem_q <= mem_n;
|
||||
if (decoded_instr_valid_i) // only advance if we decoded instruction
|
||||
top_pointer_qq <= top_pointer_q;
|
||||
end
|
||||
|
|
|
@ -35,6 +35,7 @@ interface scoreboard_if (input clk);
|
|||
|
||||
// Scoreboard interface configured as master
|
||||
clocking mck @(posedge clk);
|
||||
default input #1 output #5; // save timing
|
||||
output flush, rs1_address, rs2_address, commit_ack, decoded_instr, decoded_instr_valid, issue_ack, pc, wdata, wb_valid;
|
||||
input full, rd_clobber, rs1, rs1_valid, rs2, rs2_valid, commit_instr, issue_instr, issue_instr_valid;
|
||||
endclocking
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright (C) 2017 ETH Zurich, University of Bologna
|
||||
// All rights reserved.
|
||||
//
|
||||
// TODO, test register read and clobber interface
|
||||
// TODO, test register read and clobber interface, make a proper TB out of it
|
||||
module scoreboard_tb;
|
||||
|
||||
import uvm_pkg::*;
|
||||
|
@ -16,6 +16,7 @@ logic rst_ni, clk;
|
|||
scoreboard_entry scoreboard_queue[$];
|
||||
scoreboard_entry temp_scoreboard_entry;
|
||||
scoreboard_entry comp;
|
||||
semaphore wb_lock = new(1);
|
||||
|
||||
integer unsigned pc = 0;
|
||||
|
||||
|
@ -97,19 +98,30 @@ scoreboard dut (
|
|||
forever begin
|
||||
|
||||
@(scoreboard_if.mck);
|
||||
scoreboard_if.mck.wb_valid <= 1'b0;
|
||||
|
||||
// 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 1 and 3 cycles for WB
|
||||
repeat ($urandom_range(0,3)) @(scoreboard_if.mck);
|
||||
scoreboard_if.mck.pc <= issue_instruction.pc;
|
||||
scoreboard_if.mck.wdata <= 64'h7777;
|
||||
scoreboard_if.mck.wb_valid <= 1'b1;
|
||||
// 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
|
||||
|
@ -122,6 +134,7 @@ scoreboard dut (
|
|||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue