mirror of
https://github.com/openhwgroup/cva5.git
synced 2025-04-20 12:07:53 -04:00
branch unit bug fix, inuse adjustments, csr fix
This commit is contained in:
parent
4e35ee52f6
commit
bf5c12af25
9 changed files with 61 additions and 56 deletions
|
@ -38,7 +38,7 @@ module branch_predictor_ram
|
|||
output logic [C_DATA_WIDTH-1:0] read_data
|
||||
);
|
||||
|
||||
logic [C_DATA_WIDTH-1:0] branch_ram [C_DEPTH-1:0];
|
||||
(* ram_style = "block" *)logic [C_DATA_WIDTH-1:0] branch_ram [C_DEPTH-1:0];
|
||||
//implementation
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -118,20 +118,24 @@ module branch_unit(
|
|||
assign jump_pc_dec = jump_base + pc_offset;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
fn3_ex <= branch_inputs.fn3;
|
||||
result_ex <= result;
|
||||
jump_ex <= (branch_inputs.jal | branch_inputs.jalr);
|
||||
if (branch_ex.new_request_dec) begin
|
||||
fn3_ex <= branch_inputs.fn3;
|
||||
result_ex <= result;
|
||||
jump_ex <= (branch_inputs.jal | branch_inputs.jalr);
|
||||
end
|
||||
end
|
||||
|
||||
//Predictor support
|
||||
////////////////////////////////////////////////////
|
||||
always_ff @(posedge clk) begin
|
||||
pc_ex <= branch_inputs.dec_pc;
|
||||
jump_pc <= {jump_pc_dec[31:1], 1'b0};
|
||||
njump_pc <= branch_inputs.dec_pc + 4;
|
||||
branch_metadata <= branch_inputs.branch_metadata;
|
||||
branch_prediction_used <= branch_inputs.branch_prediction_used;
|
||||
bp_update_way <= branch_inputs.bp_update_way;
|
||||
if (branch_ex.new_request_dec) begin
|
||||
pc_ex <= branch_inputs.dec_pc;
|
||||
jump_pc <= {jump_pc_dec[31:1], 1'b0};
|
||||
njump_pc <= branch_inputs.dec_pc + 4;
|
||||
branch_metadata <= branch_inputs.branch_metadata;
|
||||
branch_prediction_used <= branch_inputs.branch_prediction_used;
|
||||
bp_update_way <= branch_inputs.bp_update_way;
|
||||
end
|
||||
end
|
||||
|
||||
assign br_results.pc_ex = pc_ex;
|
||||
|
@ -140,7 +144,7 @@ module branch_unit(
|
|||
assign br_results.branch_ex_metadata = branch_metadata;
|
||||
|
||||
assign br_results.branch_taken = branch_taken;
|
||||
assign br_results.branch_ex = branch_ex.new_request;
|
||||
assign br_results.branch_ex = branch_ex.new_request & branch_inputs.dec_pc_valid;
|
||||
assign br_results.is_return_ex = is_return;
|
||||
assign br_results.branch_prediction_used = branch_prediction_used;
|
||||
assign br_results.bp_update_way = bp_update_way;
|
||||
|
@ -148,9 +152,9 @@ module branch_unit(
|
|||
|
||||
assign branch_correctly_taken = {br_results.branch_taken, branch_inputs.dec_pc[31:1]} == {1'b1, br_results.jump_pc[31:1]};
|
||||
assign branch_correclty_not_taken = {br_results.branch_taken, branch_inputs.dec_pc[31:1]} == {1'b0, br_results.njump_pc[31:1]};
|
||||
assign miss_predict = branch_ex.new_request && ~(branch_correctly_taken || branch_correclty_not_taken);
|
||||
assign miss_predict = branch_ex.new_request && branch_inputs.dec_pc_valid && ~(branch_correctly_taken || branch_correclty_not_taken);
|
||||
|
||||
assign branch_flush = USE_BRANCH_PREDICTOR ? miss_predict : branch_ex.new_request & branch_taken;
|
||||
assign branch_flush = USE_BRANCH_PREDICTOR ? miss_predict : branch_ex.new_request & branch_taken & branch_inputs.dec_pc_valid;
|
||||
|
||||
//RAS support
|
||||
////////////////////////////////////////////////////
|
||||
|
|
|
@ -331,15 +331,15 @@ module decode(
|
|||
assign environment_op = (opcode_trim == SYSTEM_T) && (fn3 == 0);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (issue_ready[GC_UNIT_ID]) begin
|
||||
if (issue[GC_UNIT_ID]) begin
|
||||
gc_inputs.pc <= fb.pc;
|
||||
gc_inputs.instruction <= fb.instruction;
|
||||
gc_inputs.rs1 <= rf_decode.rs1_data;
|
||||
gc_inputs.rs2 <= rf_decode.rs2_data;
|
||||
gc_inputs.rd_is_zero <= rd_zero;
|
||||
gc_inputs.is_fence <= (opcode_trim == FENCE_T) && ~fn3[0];
|
||||
gc_inputs.is_csr <= (opcode_trim == SYSTEM_T) && (fn3 != 0);
|
||||
end
|
||||
gc_inputs.is_csr <= (opcode_trim == SYSTEM_T) && (fn3 != 0);
|
||||
gc_inputs.is_ecall <= issue[GC_UNIT_ID] && environment_op && (fb.instruction[21:20] == 0);
|
||||
gc_inputs.is_ebreak <= issue[GC_UNIT_ID] && environment_op && (fb.instruction[21:20] == 2'b01);
|
||||
gc_inputs.is_ret <= issue[GC_UNIT_ID] && environment_op && (fb.instruction[21:20] == 2'b10);
|
||||
|
@ -417,10 +417,19 @@ module decode(
|
|||
always_ff @(posedge clk) begin
|
||||
alu_ex.new_request <= issue[ALU_UNIT_WB_ID];
|
||||
ls_ex.new_request <= issue[LS_UNIT_WB_ID];
|
||||
branch_ex.new_request <= issue[BRANCH_UNIT_ID];
|
||||
gc_ex.new_request <= issue[GC_UNIT_ID];
|
||||
end
|
||||
|
||||
//Branch new request is held if
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst)
|
||||
branch_ex.new_request <= 0;
|
||||
else if (issue[BRANCH_UNIT_ID])
|
||||
branch_ex.new_request <= 1;
|
||||
else if (fb_valid)
|
||||
branch_ex.new_request <= 0;
|
||||
end
|
||||
|
||||
assign branch_ex.instruction_id_one_hot = ti.issue_id_one_hot;
|
||||
assign branch_ex.instruction_id = ti.issue_id;
|
||||
assign alu_ex.instruction_id_one_hot = ti.issue_id_one_hot;
|
||||
|
|
|
@ -291,6 +291,7 @@ module gc_unit(
|
|||
//Decode / Write-back Handshaking
|
||||
logic csr_ready_to_complete;
|
||||
logic csr_ready_to_complete_r;
|
||||
instruction_id_t instruction_id;
|
||||
//CSR reads are passed through the Load-Store unit
|
||||
//A CSR write is only committed once it is the oldest instruction in the pipeline
|
||||
//while processing a csr operation, gc_issue_hold prevents further instructions from being issued
|
||||
|
@ -309,9 +310,10 @@ module gc_unit(
|
|||
always_ff @(posedge clk) begin
|
||||
csr_ready_to_complete_r <= csr_ready_to_complete;
|
||||
csr_id_done <= id & {MAX_INFLIGHT_COUNT{csr_ready_to_complete}};
|
||||
csr_id <= instruction_id;
|
||||
if (gc_ex.new_request_dec) begin
|
||||
id <= gc_ex.instruction_id_one_hot;
|
||||
csr_id <= gc_ex.instruction_id;
|
||||
instruction_id <= gc_ex.instruction_id;
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ endinterface
|
|||
|
||||
interface register_file_writeback_interface;
|
||||
logic[4:0] rd_addr;
|
||||
logic valid_write;
|
||||
logic commit;
|
||||
logic rd_nzero;
|
||||
|
||||
logic[XLEN-1:0] rd_data;
|
||||
|
@ -143,8 +143,8 @@ interface register_file_writeback_interface;
|
|||
logic forward_rs1;
|
||||
logic forward_rs2;
|
||||
|
||||
modport writeback (output rd_addr, valid_write, rd_nzero, rd_data, id, input forward_rs1, forward_rs2);
|
||||
modport unit (input rd_addr, valid_write, rd_nzero, rd_data, id, output forward_rs1, forward_rs2);
|
||||
modport writeback (output rd_addr, commit, rd_nzero, rd_data, id, input forward_rs1, forward_rs2);
|
||||
modport unit (input rd_addr, commit, rd_nzero, rd_data, id, output forward_rs1, forward_rs2);
|
||||
|
||||
endinterface
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2018 Eric Matthews, Lesley Shannon
|
||||
* Copyright © 2018-2019 Eric Matthews, Lesley Shannon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,24 +23,6 @@
|
|||
import taiga_config::*;
|
||||
import taiga_types::*;
|
||||
|
||||
/*Overview:
|
||||
* Inuse tracking logic. Tracks whether there is an outstanding write to any given register.
|
||||
* Inuse tracking has two write-ports. One port, (issue), always sets bits, and (completed) always clears bits.
|
||||
*/
|
||||
|
||||
/* Constraints
|
||||
* + Issue has precedence over completed. Addresses may/will overlap.
|
||||
*/
|
||||
|
||||
/*Implementation:
|
||||
* If the addresses overlap, then issue has precedence over completed. After a reset, all memory bits are zero.
|
||||
* Seperate memories are used for each write port (issue and completed). Whenever a write occurs to either block,
|
||||
* the bit is toggled. If the xor of the two memories is one, then the register is inuse. Issues and completed occur
|
||||
* in pairs so after an instruction completes the two memories will have the same value (0 or 1).
|
||||
* If a new issue to the same address as a completing instruction occurs the memories will continue to have different values,
|
||||
* satisfing the requirement that issue has precedence over completion.
|
||||
*/
|
||||
|
||||
module inuse (
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
@ -61,8 +43,10 @@ module inuse (
|
|||
|
||||
logic [4:0] w_clear;
|
||||
logic [4:0] wb_rd_addr_muxed;
|
||||
logic [4:0] decode_rd_addr_muxed;
|
||||
|
||||
logic wb_collision;
|
||||
logic rd_inuse;
|
||||
//////////////////////////////////////////
|
||||
//Initialize to all inuse (0,1) for simulation,
|
||||
//will be cleared by GC after reset in hardware
|
||||
|
@ -77,26 +61,29 @@ module inuse (
|
|||
|
||||
//After reset, clear is held for at least 32 cycles to reset memory block
|
||||
assign wb_rd_addr_muxed = clr ? w_clear : wb_rd_addr;
|
||||
|
||||
assign decode_rd_addr_muxed = clr ? w_clear : decode_rd_addr;
|
||||
|
||||
//reset is for simulation purposes only, not needed for actual design
|
||||
always_ff @ (posedge clk) begin
|
||||
if (rst)
|
||||
w_clear <= 0;
|
||||
else
|
||||
w_clear <= w_clear + {4'b0, clr};
|
||||
w_clear <= w_clear + 5'(clr);
|
||||
end
|
||||
|
||||
assign wb_collision = completed && (decode_rd_addr == wb_rd_addr);
|
||||
//Toggle issue (bankA) and write-back (bankB) values for inuse tracking
|
||||
//Special cases are when multiple instructions are in flight that write to the same address
|
||||
//Only the newest write will toggle BankB
|
||||
//When issueing multiple times, don't toggle for subsequent issues unless the previous write is completing on this cycle
|
||||
assign wb_collision = completed && (decode_rd_addr == wb_rd_addr);
|
||||
assign rd_inuse = ~wb_collision & (bankA[decode_rd_addr_muxed] ^ bankB[decode_rd_addr_muxed]);
|
||||
|
||||
always_ff @ (posedge clk) begin
|
||||
if (issued)
|
||||
bankA[decode_rd_addr] <= wb_collision ? ~bankA[wb_rd_addr_muxed] : ~bankB[decode_rd_addr];
|
||||
bankA[decode_rd_addr_muxed] <= clr | ((~rd_inuse & issued) ^ bankA[decode_rd_addr_muxed]);
|
||||
end
|
||||
|
||||
always_ff @ (posedge clk) begin
|
||||
if (completed | clr)
|
||||
bankB[wb_rd_addr_muxed] <= bankA[wb_rd_addr_muxed];
|
||||
bankB[wb_rd_addr_muxed] <= clr | (completed ^ bankB[wb_rd_addr_muxed]);
|
||||
end
|
||||
|
||||
assign rs1_inuse = bankA[rs1_addr] ^ bankB[rs1_addr];
|
||||
|
@ -119,3 +106,4 @@ module inuse (
|
|||
endmodule
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ module register_file(
|
|||
logic rs1_feedforward;
|
||||
logic rs2_feedforward;
|
||||
|
||||
logic valid_write;
|
||||
logic in_use_match;
|
||||
instruction_id_t in_use_by_id;
|
||||
instruction_id_t rs1_id;
|
||||
|
@ -55,9 +56,9 @@ module register_file(
|
|||
end
|
||||
end
|
||||
|
||||
//Writeback unit does not assert rf_wb.valid_write when the target register is r0
|
||||
//Writeback unit does not assert rf_wb.commit when the target register is r0
|
||||
always_ff @ (posedge clk) begin
|
||||
if (~gc_supress_writeback & rf_wb.rd_nzero & rf_wb.valid_write & (in_use_match | inorder)) //inorder needed for case when multiple outstanding writes to this register (common pattern: load, store, load) where the first load hasn't completed by the second causes an exception. Without inorder we wouldn't commit the first load
|
||||
if (~gc_supress_writeback & valid_write & (in_use_match | inorder)) //inorder needed for when a L/S exception occurs
|
||||
register[rf_wb.rd_addr] <= rf_wb.rd_data;
|
||||
end
|
||||
|
||||
|
@ -66,7 +67,7 @@ module register_file(
|
|||
.rs1_addr(rf_decode.rs1_addr),.rs2_addr(rf_decode.rs2_addr), .decode_rd_addr(rf_decode.future_rd_addr),
|
||||
.wb_rd_addr(rf_wb.rd_addr),
|
||||
.issued(rf_decode.instruction_issued),
|
||||
.completed(in_use_match),
|
||||
.completed(valid_write & in_use_match),
|
||||
.rs1_inuse(rs1_inuse),
|
||||
.rs2_inuse(rs2_inuse)
|
||||
);
|
||||
|
@ -80,10 +81,11 @@ module register_file(
|
|||
assign rs1_id = in_use_by[rf_decode.rs1_addr];
|
||||
assign rs2_id = in_use_by[rf_decode.rs2_addr];
|
||||
|
||||
assign in_use_match = ~gc_supress_writeback && rf_wb.rd_nzero && rf_wb.valid_write && (rf_wb.id == in_use_by_id);
|
||||
assign valid_write = rf_wb.rd_nzero && rf_wb.commit;
|
||||
assign in_use_match = (rf_wb.id == in_use_by_id);
|
||||
|
||||
assign rs1_feedforward = rs1_inuse && (rs1_id == rf_wb.id) && rf_wb.valid_write;
|
||||
assign rs2_feedforward = rs2_inuse && (rs2_id == rf_wb.id) && rf_wb.valid_write;
|
||||
assign rs1_feedforward = rs1_inuse && (rs1_id == rf_wb.id) && rf_wb.commit;
|
||||
assign rs2_feedforward = rs2_inuse && (rs2_id == rf_wb.id) && rf_wb.commit;
|
||||
|
||||
assign rf_decode.rs1_data = rs1_feedforward ? rf_wb.rd_data : register[rf_decode.rs1_addr];
|
||||
assign rf_decode.rs2_data = rs2_feedforward ? rf_wb.rd_data : register[rf_decode.rs2_addr];
|
||||
|
|
|
@ -171,7 +171,7 @@ module write_back(
|
|||
//Register file interaction
|
||||
assign rf_wb.rd_addr = retired_instruction_packet.rd_addr;
|
||||
assign rf_wb.id = retired_id_r;
|
||||
assign rf_wb.valid_write = retired_r;
|
||||
assign rf_wb.commit = retired_r;
|
||||
assign rf_wb.rd_nzero = retired_instruction_packet.rd_addr_nzero;
|
||||
assign rf_wb.rd_data = unit_rd[retired_instruction_packet.unit_id];
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ export RANLIB
|
|||
|
||||
#Compiance parameters
|
||||
###############################################################
|
||||
COMPLIANCE_DIR=/home/ematthew/Research/RISCV/software/riscv-compliance/
|
||||
COMPLIANCE_DIR=/home/ematthew/Research/RISCV/sfu-rcl/taiga-riscv-compliance/
|
||||
COMPLIANCE_TARGET=rv32im
|
||||
###############################################################
|
||||
|
||||
|
@ -49,7 +49,7 @@ BENCHMARKS = \
|
|||
#Benchmark parameters
|
||||
#Assumes binaries are in the BENCHMARK_DIR
|
||||
###############################################################
|
||||
EMBENCH_DIR=/home/ematthew/Research/RISCV/software/embench/build/src
|
||||
EMBENCH_DIR=/home/ematthew/Research/RISCV/sfu-rcl/taiga-embench/build/src
|
||||
EMBENCH_BENCHMARKS = \
|
||||
aha-mont64 \
|
||||
crc32 \
|
||||
|
@ -126,7 +126,7 @@ verilator_taiga_compliance_unit_test:
|
|||
.PHONY: verilator_taiga_compliance_tests
|
||||
verilator_taiga_compliance_tests:
|
||||
$(MAKE) -C $(COMPLIANCE_DIR) clean
|
||||
$(MAKE) -C $(COMPLIANCE_DIR) RISCV_TARGET=taiga RISCV_DEVICE=$(COMPLIANCE_TARGET) RISCV_PREFIX=$(RISCV_PREFIX)
|
||||
$(MAKE) -C $(COMPLIANCE_DIR) RISCV_TARGET=taiga RISCV_DEVICE=$(COMPLIANCE_TARGET) RISCV_PREFIX=$(RISCV_PREFIX) TAIGA_ROOT=$(TAIGA_DIR)/tools
|
||||
|
||||
.PHONY: verilator_taiga_coremark
|
||||
verilator_taiga_coremark:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue