branch unit bug fix, inuse adjustments, csr fix

This commit is contained in:
Eric Matthews 2019-08-29 11:17:58 -07:00
parent 4e35ee52f6
commit bf5c12af25
9 changed files with 61 additions and 56 deletions

View file

@ -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
////////////////////////////////////////////////////

View file

@ -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
////////////////////////////////////////////////////

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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];

View file

@ -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];

View file

@ -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: