diff --git a/src/ariane.sv b/src/ariane.sv index 67b0f0720..39de653ad 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -118,8 +118,17 @@ module ariane logic fetch_valid_if_id; logic decode_ack_id_if; exception exception_if_id; + // -------------- - // ID <-> EX + // ID <-> ISSUE + // -------------- + scoreboard_entry issue_entry_id_issue; + logic issue_entry_valid_id_issue; + logic is_ctrl_fow_id_issue; + logic issue_instr_issue_id; + + // -------------- + // ISSUE <-> EX // -------------- logic [63:0] imm_id_ex; logic [TRANS_ID_BITS-1:0] trans_id_id_ex; @@ -266,22 +275,42 @@ module ariane // --------- // ID // --------- - id_stage + id_stage id_stage_i ( + .flush_i ( flush_ctrl_id ), + .fetch_entry_i ( fetch_entry_if_id ), + .fetch_entry_valid_i ( fetch_valid_if_id ), + .decoded_instr_ack_o ( decode_ack_id_if ), + + .issue_entry_o ( issue_entry_id_issue ), + .issue_entry_valid_o ( issue_entry_valid_id_issue ), + .is_ctrl_flow_o ( is_ctrl_fow_id_issue ), + .issue_instr_ack_i ( issue_instr_issue_id ), + + .priv_lvl_i ( priv_lvl ), + .tvm_i ( tvm_csr_id ), + .tw_i ( tw_csr_id ), + .tsr_i ( tsr_csr_id ), + + .* + ); + + // --------- + // Issue + // --------- + issue_stage #( - .NR_ENTRIES ( NR_SB_ENTRIES ), - .NR_WB_PORTS ( NR_WB_PORTS ) + .NR_ENTRIES ( NR_SB_ENTRIES ), + .NR_WB_PORTS ( NR_WB_PORTS ) ) - id_stage_i ( - .test_en_i ( test_en_i ), + issue_stage_i ( + .flush_unissued_instr_i ( flush_unissued_instr_i ), .flush_i ( flush_ctrl_id ), - .flush_unissued_instr_i ( flush_unissued_instr_ctrl_id ), - .fetch_entry_i ( fetch_entry_if_id ), - .fetch_entry_valid_i ( fetch_valid_if_id ), - .decoded_instr_ack_o ( decode_ack_id_if ), - .priv_lvl_i ( priv_lvl ), - .tvm_i ( tvm_csr_id ), - .tw_i ( tw_csr_id ), - .tsr_i ( tsr_csr_id ), + + .decoded_instr_i ( issue_entry_id_issue ), + .decoded_instr_valid_i ( issue_entry_valid_id_issue ), + .is_ctrl_flow_i ( is_ctrl_fow_id_issue ), + .decoded_instr_ack_o ( issue_instr_issue_id ), + // Functional Units .fu_o ( fu_id_ex ), .operator_o ( operator_id_ex ), @@ -485,8 +514,8 @@ module ariane assign tracer_if.fetch_valid = fetch_valid_if_id; assign tracer_if.fetch_ack = decode_ack_id_if; // Issue - assign tracer_if.issue_ack = id_stage_i.scoreboard_i.issue_ack_i; - assign tracer_if.issue_sbe = id_stage_i.scoreboard_i.issue_instr_o; + assign tracer_if.issue_ack = issue_stage_i.scoreboard_i.issue_ack_i; + assign tracer_if.issue_sbe = issue_stage_i.scoreboard_i.issue_instr_o; // write-back assign tracer_if.waddr = waddr_a_commit_id; assign tracer_if.wdata = wdata_a_commit_id; diff --git a/src/id_stage.sv b/src/id_stage.sv index abcaaeddf..3426d76f7 100644 --- a/src/id_stage.sv +++ b/src/id_stage.sv @@ -19,121 +19,37 @@ // import ariane_pkg::*; -module id_stage #( - parameter int NR_ENTRIES = 4, - parameter int NR_WB_PORTS = 4 - )( +module id_stage ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_en_i, // Test Enable input logic flush_i, - input logic flush_unissued_instr_i, // from IF input fetch_entry fetch_entry_i, input logic fetch_entry_valid_i, - output logic decoded_instr_ack_o, + output logic decoded_instr_ack_o, // acknowledge the instruction (fetch entry) + + // to ID + output scoreboard_entry issue_entry_o, // a decoded instruction + output logic issue_entry_valid_o, // issue entry is valid + output logic is_ctrl_flow_o, // the instruction we issue is a ctrl flow instructions + input logic issue_instr_ack_i, // issue stage acknowledged sampling of instructions // from CSR file - input priv_lvl_t priv_lvl_i, // current privilege level + input priv_lvl_t priv_lvl_i, // current privilege level input logic tvm_i, input logic tw_i, - input logic tsr_i, - - output fu_t fu_o, - output fu_op operator_o, - output logic [63:0] operand_a_o, - output logic [63:0] operand_b_o, - output logic [63:0] imm_o, - output logic [TRANS_ID_BITS-1:0] trans_id_o, - output logic [63:0] pc_o, - output logic is_compressed_instr_o, - - input logic alu_ready_i, - output logic alu_valid_o, - // ex just resolved our predicted branch, we are ready to accept new requests - input logic resolve_branch_i, - - input logic lsu_ready_i, - output logic lsu_valid_o, - // branch prediction - input logic branch_ready_i, - output logic branch_valid_o, // use branch prediction unit - output branchpredict_sbe branch_predict_o, - - input logic mult_ready_i, - output logic mult_valid_o, // Branch predict Out - - input logic csr_ready_i, - output logic csr_valid_o, - - // write back port - input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i, - input logic [NR_WB_PORTS-1:0][63:0] wdata_i, - input exception [NR_WB_PORTS-1:0] ex_ex_i, // exception from execute stage - input logic [NR_WB_PORTS-1:0] wb_valid_i, - // commit port - input logic[4:0] waddr_a_i, - input logic[63:0] wdata_a_i, - input logic we_a_i, - - output scoreboard_entry commit_instr_o, - input logic commit_ack_i + input logic tsr_i ); - // --------------------------------------------------- - // Global signals - // --------------------------------------------------- - logic full; - logic decode_instr_ack; - // --------------------------------------------------- - // Scoreboard (SB) <-> Issue and Read Operands (iro) - // --------------------------------------------------- - fu_t [31:0] rd_clobber_sb_iro; - logic [4:0] rs1_iro_sb; - logic [63:0] rs1_sb_iro; - logic rs1_valid_sb_iro; - logic [4:0] rs2_iro_sb; - logic [63:0] rs2_sb_iro; - logic rs2_valid_iro_sb; - scoreboard_entry issue_instr_sb_iro; - logic issue_instr_valid_sb_iro; - logic issue_ack_iro_sb; - // --------------------------------------------------- - // Decoder (DC) <-> Scoreboard (SB) - // --------------------------------------------------- - scoreboard_entry decoded_instr_dc_sb; - // --------------------------------------------------- - // Decoder (DC) <-> Branch Logic - // --------------------------------------------------- + // register stage + struct packed { + logic valid; + scoreboard_entry sbe; + logic is_ctrl_flow; + + } issue_n, issue_q; + logic is_control_flow_instr; - - // --------------------------------------------------- - // Branch (resolve) logic - // --------------------------------------------------- - // This should basically prevent the scoreboard from accepting - // instructions past a branch. We need to resolve the branch beforehand. - // This limitation is in place to ease the backtracking of mis-predicted branches as they - // can simply be in the front-end of the processor. - logic unresolved_branch_n, unresolved_branch_q; - - always_comb begin : unresolved_branch - unresolved_branch_n = unresolved_branch_q; - // we just resolved the branch - if (resolve_branch_i) begin - unresolved_branch_n = 1'b0; - end - // if the instruction is valid and it is a control flow instruction - if (fetch_entry_valid_i && is_control_flow_instr) begin - unresolved_branch_n = 1'b1; - end - // if we are requested to flush also flush the unresolved branch flag because either the flush - // was requested by a branch or an exception. In any case: any unresolved branch will get evicted - if (flush_unissued_instr_i || flush_i) begin - unresolved_branch_n = 1'b0; - end - end - // we are ready if we are not full and don't have any unresolved branches, but it can be - // the case that we have an unresolved branch which is cleared in that cycle (resolved_branch_i.valid == 1) - assign decoded_instr_ack_o = decode_instr_ack && !unresolved_branch_q; + scoreboard_entry decoded_instruction; decoder decoder_i ( .pc_i ( fetch_entry_i.address ), @@ -142,59 +58,47 @@ module id_stage #( .branch_predict_i ( fetch_entry_i.branch_predict ), .is_illegal_i ( fetch_entry_i.is_illegal ), .ex_i ( fetch_entry_i.ex ), - .instruction_o ( decoded_instr_dc_sb ), + .instruction_o ( decoded_instruction ), .is_control_flow_instr_o ( is_control_flow_instr ), .* ); - scoreboard #( - .NR_ENTRIES ( NR_ENTRIES ), - .NR_WB_PORTS ( NR_WB_PORTS ) - ) - scoreboard_i - ( - .full_o ( full ), - .rd_clobber_o ( rd_clobber_sb_iro ), - .rs1_i ( rs1_iro_sb ), - .rs1_o ( rs1_sb_iro ), - .rs1_valid_o ( rs1_valid_sb_iro ), - .rs2_i ( rs2_iro_sb ), - .rs2_o ( rs2_sb_iro ), - .rs2_valid_o ( rs2_valid_iro_sb ), - .commit_instr_o ( commit_instr_o ), - .commit_ack_i ( commit_ack_i ), - .decoded_instr_ack_o ( decode_instr_ack ), - .decoded_instr_i ( decoded_instr_dc_sb ), - .decoded_instr_valid_i ( fetch_entry_valid_i ), - .issue_instr_o ( issue_instr_sb_iro ), - .issue_instr_valid_o ( issue_instr_valid_sb_iro ), - .issue_ack_i ( issue_ack_iro_sb ), - .trans_id_i ( trans_id_i ), - .wdata_i ( wdata_i ), - .ex_i ( ex_ex_i ), - .* - ); + // ------------------ + // Output Registers + // ------------------ + assign issue_entry_o = issue_q.sbe; + assign issue_entry_valid_o = issue_q.valid; + assign is_ctrl_flow_o = issue_q.is_ctrl_flow; + always_comb begin + issue_n = issue_q; + decoded_instr_ack_o = 1'b0; - issue_read_operands issue_read_operands_i ( - .issue_instr_i ( issue_instr_sb_iro ), - .issue_instr_valid_i ( issue_instr_valid_sb_iro ), - .issue_ack_o ( issue_ack_iro_sb ), - .rs1_o ( rs1_iro_sb ), - .rs1_i ( rs1_sb_iro ), - .rs1_valid_i ( rs1_valid_sb_iro ), - .rs2_o ( rs2_iro_sb ), - .rs2_i ( rs2_sb_iro ), - .rs2_valid_i ( rs2_valid_iro_sb ), - .rd_clobber_i ( rd_clobber_sb_iro ), - .* - ); + // if we have a space in the register and the fetch is valid, go get it + if (!issue_q.valid && fetch_entry_valid_i) begin + decoded_instr_ack_o = 1'b1; + issue_n = { 1'b1, decoded_instruction, is_control_flow_instr}; + issue_n.valid = 1'b1; + end + // we have something in the register but issue stage already acknowledged + if (issue_q.valid && issue_instr_ack_i) begin + decoded_instr_ack_o = 1'b1; + issue_n = { 1'b1, decoded_instruction, is_control_flow_instr}; + end + + // invalidate on a flush + if (flush_i) + issue_n.valid = 1'b0; + end + // ------------------------- + // Registers (ID <-> Issue) + // ------------------------- always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - unresolved_branch_q <= 1'b0; + if(~rst_ni) begin + issue_q <= '0; end else begin - unresolved_branch_q <= unresolved_branch_n; + issue_q <= issue_n; end end diff --git a/src/issue_stage.sv b/src/issue_stage.sv new file mode 100755 index 000000000..70a600ffb --- /dev/null +++ b/src/issue_stage.sv @@ -0,0 +1,180 @@ +// Author: Florian Zaruba, ETH Zurich +// Date: 21.05.2017 +// Description: Issue stage dispatches instructions to the FUs +// +// +// Copyright (C) 2017 ETH Zurich, University of Bologna +// All rights reserved. +// +// This code is under development and not yet released to the public. +// Until it is released, the code is under the copyright of ETH Zurich and +// the University of Bologna, and may contain confidential and/or unpublished +// work. Any reuse/redistribution is strictly forbidden without written +// permission from ETH Zurich. +// +// Bug fixes and contributions will eventually be released under the +// SolderPad open hardware license in the context of the PULP platform +// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the +// University of Bologna. +// + +import ariane_pkg::*; + +module issue_stage #( + parameter int NR_ENTRIES = 4, + parameter int NR_WB_PORTS = 4 + )( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic test_en_i, // Test Enable + + input logic flush_unissued_instr_i, + input logic flush_i, + // from ID + input scoreboard_entry decoded_instr_i, + input logic decoded_instr_valid_i, + input logic is_ctrl_flow_i, + output logic decoded_instr_ack_o, + // to EX + output fu_t fu_o, + output fu_op operator_o, + output logic [63:0] operand_a_o, + output logic [63:0] operand_b_o, + output logic [63:0] imm_o, + output logic [TRANS_ID_BITS-1:0] trans_id_o, + output logic [63:0] pc_o, + output logic is_compressed_instr_o, + + input logic alu_ready_i, + output logic alu_valid_o, + // ex just resolved our predicted branch, we are ready to accept new requests + input logic resolve_branch_i, + + input logic lsu_ready_i, + output logic lsu_valid_o, + // branch prediction + input logic branch_ready_i, + output logic branch_valid_o, // use branch prediction unit + output branchpredict_sbe branch_predict_o, + + input logic mult_ready_i, + output logic mult_valid_o, // Branch predict Out + + input logic csr_ready_i, + output logic csr_valid_o, + + // write back port + input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i, + input logic [NR_WB_PORTS-1:0][63:0] wdata_i, + input exception [NR_WB_PORTS-1:0] ex_ex_i, // exception from execute stage + input logic [NR_WB_PORTS-1:0] wb_valid_i, + + // commit port + input logic[4:0] waddr_a_i, + input logic[63:0] wdata_a_i, + input logic we_a_i, + + output scoreboard_entry commit_instr_o, + input logic commit_ack_i +); + + // --------------------------------------------------- + // Global signals + // --------------------------------------------------- + logic full; + logic decoded_instr_ack; + // --------------------------------------------------- + // Scoreboard (SB) <-> Issue and Read Operands (IRO) + // --------------------------------------------------- + fu_t [31:0] rd_clobber_sb_iro; + logic [4:0] rs1_iro_sb; + logic [63:0] rs1_sb_iro; + logic rs1_valid_sb_iro; + logic [4:0] rs2_iro_sb; + logic [63:0] rs2_sb_iro; + logic rs2_valid_iro_sb; + scoreboard_entry issue_instr_sb_iro; + logic issue_instr_valid_sb_iro; + logic issue_ack_iro_sb; + + + // --------------------------------------------------- + // Branch (resolve) logic + // --------------------------------------------------- + // This should basically prevent the scoreboard from accepting + // instructions past a branch. We need to resolve the branch beforehand. + // This limitation is in place to ease the backtracking of mis-predicted branches as they + // can simply be in the front-end of the processor. + logic unresolved_branch_n, unresolved_branch_q; + + always_comb begin : unresolved_branch + unresolved_branch_n = unresolved_branch_q; + // we just resolved the branch + if (resolve_branch_i) begin + unresolved_branch_n = 1'b0; + end + // if the instruction is valid and it is a control flow instruction + if (decoded_instr_valid_i && is_ctrl_flow_i) begin + unresolved_branch_n = 1'b1; + end + // if we are requested to flush also flush the unresolved branch flag because either the flush + // was requested by a branch or an exception. In any case: any unresolved branch will get evicted + if (flush_unissued_instr_i || flush_i) begin + unresolved_branch_n = 1'b0; + end + end + // we are ready if we are not full and don't have any unresolved branches, but it can be + // the case that we have an unresolved branch which is cleared in that cycle (resolved_branch_i == 1) + assign decoded_instr_ack_o = ~full && (~unresolved_branch_q) && decoded_instr_ack; + + issue_read_operands issue_read_operands_i ( + .flush_i ( flush_unissued_instr_i ), + .issue_instr_i ( issue_instr_sb_iro ), + .issue_instr_valid_i ( issue_instr_valid_sb_iro ), + .issue_ack_o ( issue_ack_iro_sb ), + .rs1_o ( rs1_iro_sb ), + .rs1_i ( rs1_sb_iro ), + .rs1_valid_i ( rs1_valid_sb_iro ), + .rs2_o ( rs2_iro_sb ), + .rs2_i ( rs2_sb_iro ), + .rs2_valid_i ( rs2_valid_iro_sb ), + .rd_clobber_i ( rd_clobber_sb_iro ), + .* + ); + + scoreboard #( + .NR_ENTRIES ( NR_ENTRIES ), + .NR_WB_PORTS ( NR_WB_PORTS ) + ) + scoreboard_i + ( + .full_o ( full ), + .rd_clobber_o ( rd_clobber_sb_iro ), + .rs1_i ( rs1_iro_sb ), + .rs1_o ( rs1_sb_iro ), + .rs1_valid_o ( rs1_valid_sb_iro ), + .rs2_i ( rs2_iro_sb ), + .rs2_o ( rs2_sb_iro ), + .rs2_valid_o ( rs2_valid_iro_sb ), + + .decoded_instr_ack_o ( decoded_instr_ack ), + + .issue_instr_o ( issue_instr_sb_iro ), + .issue_instr_valid_o ( issue_instr_valid_sb_iro ), + .issue_ack_i ( issue_ack_iro_sb ), + + .trans_id_i ( trans_id_i ), + .wdata_i ( wdata_i ), + .ex_i ( ex_ex_i ), + .* + ); + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + unresolved_branch_q <= 1'b0; + end else begin + unresolved_branch_q <= unresolved_branch_n; + end + end + +endmodule diff --git a/src/scoreboard.sv b/src/scoreboard.sv index 70e18f3f8..cc226feba 100644 --- a/src/scoreboard.sv +++ b/src/scoreboard.sv @@ -76,13 +76,6 @@ module scoreboard #( logic [$clog2(NR_ENTRIES)-1:0] commit_pointer_n, commit_pointer_q; logic issue_full; - struct packed { - logic valid; - scoreboard_entry sbe; - } decoded_instr_n, decoded_instr_q; - - logic decoded_instr_ack; - // the issue queue is full don't issue any new instructions assign issue_full = (issue_cnt_q == NR_ENTRIES-1); assign full_o = issue_full; @@ -91,29 +84,13 @@ module scoreboard #( // an instruction is ready for issue if we have place in the issue FIFO and it the decoder says it is valid always_comb begin - issue_instr_o = decoded_instr_q; + issue_instr_o = decoded_instr_i; // make sure we assign the correct trans ID issue_instr_o.trans_id = issue_pointer_q; - issue_instr_valid_o = decoded_instr_q.valid; - decoded_instr_ack_o = decoded_instr_ack; + issue_instr_valid_o = decoded_instr_valid_i; + decoded_instr_ack_o = issue_ack_i; end - always_comb begin : decode_if - decoded_instr_ack = 1'b0; - decoded_instr_n = decoded_instr_q; - if (issue_ack_i) - decoded_instr_n.valid = 1'b0; - - if (!decoded_instr_q.valid && decoded_instr_valid_i) begin - decoded_instr_ack = 1'b1; - decoded_instr_n = {1'b1, decoded_instr_i}; - end - - if (decoded_instr_q.valid && !issue_full && issue_ack_i) begin - decoded_instr_ack = 1'b1; - decoded_instr_n = {1'b1, decoded_instr_i}; - end - end // maintain a FIFO with issued instructions // keep track of all issued instructions always_comb begin : issue_fifo @@ -254,13 +231,11 @@ module scoreboard #( issue_cnt_q <= '0; commit_pointer_q <= '0; issue_pointer_q <= '0; - decoded_instr_q <= '0; end else begin mem_q <= mem_n; issue_cnt_q <= issue_cnt_n; commit_pointer_q <= commit_pointer_n; issue_pointer_q <= issue_pointer_n; - decoded_instr_q <= decoded_instr_n; end end `ifndef SYNTHESIS diff --git a/tb/wave/wave_core.do b/tb/wave/wave_core.do index 4289d8933..83a3c0354 100644 --- a/tb/wave/wave_core.do +++ b/tb/wave/wave_core.do @@ -3,9 +3,9 @@ add wave -noupdate -group pcgen_stage -group btb /core_tb/dut/pcgen_i/btb_i/* add wave -noupdate -group pcgen_stage /core_tb/dut/pcgen_i/* add wave -noupdate -group if_stage -group fetch_fifo /core_tb/dut/if_stage_i/fetch_fifo_i/* add wave -noupdate -group if_stage /core_tb/dut/if_stage_i/* -add wave -noupdate -group id_stage -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/* add wave -noupdate -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/* -add wave -noupdate -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/* +add wave -noupdate -group issue_stage -group scoreboard /core_tb/dut/issue_stage_i/scoreboard_i/* +add wave -noupdate -group issue_stage -group issue_read_operands /core_tb/dut/issue_stage_i/issue_read_operands_i/* add wave -noupdate -group id_stage /core_tb/dut/id_stage_i/* add wave -noupdate -group ex_stage -group alu /core_tb/dut/ex_stage_i/alu_i/* add wave -noupdate -group ex_stage -group lsu -group mmu /core_tb/dut/ex_stage_i/lsu_i/mmu_i/*