-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changed logic for sequence progress detection #638
Changes from all commits
aefdf1e
d47b51d
7723120
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,7 +48,6 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
|
||
// From IF stage | ||
input logic [31:0] pc_if_i, | ||
input logic first_op_if_i, // IF stage is handling the first operation of a sequence. | ||
input logic last_op_if_i, // IF stage is handling the last operation of a sequence. | ||
|
||
// From ID stage | ||
|
@@ -58,12 +57,12 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
input logic alu_en_id_i, // alu_en qualifier for jumps | ||
input logic sys_en_id_i, // sys_en qualifier for mret | ||
input logic first_op_id_i, // ID stage is handling the first operation of a sequence | ||
input logic last_op_id_i, // ID stage is handling the last operation of a sequence | ||
|
||
// From EX stage | ||
input id_ex_pipe_t id_ex_pipe_i, | ||
input logic branch_decision_ex_i, // branch decision signal from EX ALU | ||
input logic last_op_ex_i, // EX stage contains the last operation of an instruction | ||
input logic first_op_ex_i, // EX stage is handling the first operation of a sequence | ||
|
||
// From WB stage | ||
input ex_wb_pipe_t ex_wb_pipe_i, | ||
|
@@ -218,12 +217,18 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
logic csr_flush_ack_q; | ||
|
||
// Flag for checking if multi op instructions are in an interruptible state | ||
logic sequence_in_progress_wb; | ||
logic sequence_interruptible; | ||
|
||
// Flag for checking if ID stage can be halted | ||
// Used to not halt sequences in the middle, potentially causing deadlocks | ||
logic sequence_in_progress_id; | ||
logic id_stage_haltable; | ||
|
||
assign sequence_interruptible = !sequence_in_progress_wb; | ||
|
||
assign id_stage_haltable = !sequence_in_progress_id; | ||
|
||
assign fencei_ready = !lsu_busy_i; | ||
|
||
// Once the fencei handshake is initiated, it must complete and the instruction must retire. | ||
|
@@ -463,36 +468,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
assign ctrl_fsm_o.mhpmevent.id_ld_stall = ctrl_byp_i.load_stall && !id_valid_i && ex_ready_i; | ||
assign ctrl_fsm_o.mhpmevent.wb_data_stall = data_stall_wb_i; | ||
|
||
// Detect if we are in the middle of a multi operation sequence | ||
// Basically check if the oldest instruction in the pipeline is a 'first_op' | ||
// - if not, we have an unfinished sequence and cannot interrupt it. | ||
// Used to determine if we are allowed to take debug or interrupts | ||
always_comb begin | ||
if (ex_wb_pipe_i.instr_valid) begin | ||
sequence_interruptible = ex_wb_pipe_i.first_op; | ||
end else if (id_ex_pipe_i.instr_valid) begin | ||
sequence_interruptible = first_op_ex_i; | ||
end else if (if_id_pipe_i.instr_valid) begin | ||
sequence_interruptible = first_op_id_i; | ||
end else begin | ||
sequence_interruptible = first_op_if_i; // todo: first/last op should always be classified with instr_vali; if not it needs proper explanation. | ||
end | ||
end | ||
|
||
// Check if we are allowed to halt the ID stage. | ||
// If ID stage contains a non-first operation, we cannot halt ID as that | ||
// could cause a deadlock because a sequence cannot finish through ID. | ||
// If ID stage does not contain a valid instruction, the same check is performed | ||
// for the IF stage (although this is likely not needed). | ||
always_comb begin | ||
if (if_id_pipe_i.instr_valid) begin | ||
id_stage_haltable = first_op_id_i; | ||
end else begin | ||
// IF stage first_op defaults to 1'b1 if the stage does not hold a valid instruction or | ||
// table jump pointer. Table jump pointers will have first_op set to 0. | ||
id_stage_haltable = first_op_if_i; // todo: first/last op should always be classified with instr_valid; if not it needs proper explanation (and I would prefer if we get rid of this special reliance on the 1'b1 default) | ||
end | ||
end | ||
|
||
// Mux used to select PC from the different pipeline stages | ||
always_comb begin | ||
|
@@ -1082,6 +1058,53 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
end | ||
end | ||
|
||
// Instruction sequences may not be interrupted/killed if the first operation has already been retired. | ||
// Flop set when first_op is done in WB, and cleared when last_op is done, or WB is killed | ||
always_ff @(posedge clk, negedge rst_n) begin | ||
if (rst_n == 1'b0) begin | ||
sequence_in_progress_wb <= 1'b0; | ||
end else begin | ||
if (!sequence_in_progress_wb) begin | ||
if (wb_valid_i && ex_wb_pipe_i.first_op && !last_op_wb_i) begin // wb_valid implies ex_wb_pipe.instr_valid | ||
sequence_in_progress_wb <= 1'b1; | ||
end | ||
end else begin | ||
// sequence_in_progress_wb is set, clear when last_op retires | ||
if (wb_valid_i && last_op_wb_i) begin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reply as above |
||
sequence_in_progress_wb <= 1'b0; | ||
end | ||
// Needed in the future, but commented out to make a SEC clean PR. | ||
//if (ctrl_fsm_o.kill_wb) begin | ||
// sequence_in_progress_wb <= 1'b0; | ||
//end | ||
end | ||
end | ||
end | ||
|
||
// Logic to track first_op and last_op through the ID stage to detect unhaltable sequences | ||
// Flop set when first_op is done in ID, and cleared when last_op is done, or ID is killed | ||
always_ff @(posedge clk, negedge rst_n) begin | ||
if (rst_n == 1'b0) begin | ||
sequence_in_progress_id <= 1'b0; | ||
end else begin | ||
if (!sequence_in_progress_id) begin | ||
if (id_valid_i && ex_ready_i && first_op_id_i && !last_op_id_i) begin // id_valid implies if_id_pipe.instr.valid | ||
sequence_in_progress_id <= 1'b1; | ||
end | ||
end else begin | ||
// sequence_in_progress_id is set, clear when last_op retires | ||
if (id_valid_i && ex_ready_i && last_op_id_i) begin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same remarks as above related to usage of isntr_valid. Is adding the instr_valid signals a SEC clean change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would likely be SEC clean, but as for the others the instr_valid is baked into the valid |
||
sequence_in_progress_id <= 1'b0; | ||
end | ||
end | ||
|
||
// Reset flag if ID stage is killed | ||
if (ctrl_fsm_o.kill_id) begin | ||
sequence_in_progress_id <= 1'b0; | ||
end | ||
end | ||
end | ||
|
||
|
||
///////////////////// | ||
// Debug state FSM // | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!