mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
IF Sync, problems in RVC
This commit is contained in:
parent
685b6dbabb
commit
d324cfc01f
1 changed files with 144 additions and 90 deletions
234
if_stage.sv
234
if_stage.sv
|
@ -80,17 +80,17 @@ module if_stage
|
|||
input logic stall_id_i
|
||||
);
|
||||
|
||||
|
||||
logic [31:0] exc_pc;
|
||||
// offset FSM
|
||||
enum logic[3:0] {IDLE, WAIT_ALIGNED, WAIT_UNALIGNED, VALID_ALIGNED, VALID_UNALIGNED,
|
||||
HANDLE_BRANCH, FETCH_UNALIGNED} offset_fsm_cs, offset_fsm_ns, offset_fsm_stored;
|
||||
|
||||
logic [1:0] is_compressed;
|
||||
logic crossword_n, crossword_Q;
|
||||
logic unaligned, unaligned_Q;
|
||||
logic unaligned_jump;
|
||||
logic branch_taken;
|
||||
|
||||
logic handle_branch;
|
||||
logic force_nop_int;
|
||||
logic [31:0] instr_rdata_int;
|
||||
logic [31:0] current_pc_id_int;
|
||||
|
||||
// instr_core_interface
|
||||
logic fetch_req;
|
||||
|
@ -99,40 +99,32 @@ module if_stage
|
|||
logic [31:0] fetch_addr, fetch_addr_n;
|
||||
logic [31:0] fetch_addr_Q;
|
||||
|
||||
logic [31:0] instr_rdata_int;
|
||||
|
||||
logic [31:0] exc_pc;
|
||||
|
||||
// local cache
|
||||
logic [15:0] data_arr;
|
||||
|
||||
|
||||
// store instr_core_if data in local cache
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (rst_n == 1'b0) begin
|
||||
data_arr <= 16'b0;
|
||||
end else begin
|
||||
if (fetch_valid) begin
|
||||
data_arr <= fetch_rdata[31:16];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// output data and PC mux
|
||||
always_comb
|
||||
begin
|
||||
// default values for regular aligned access
|
||||
instr_rdata_int = fetch_rdata;
|
||||
current_pc_id_int = {fetch_addr[31:2], 2'b00};
|
||||
current_pc_if_o = {fetch_addr[31:2], 2'b00};
|
||||
|
||||
if (unaligned) begin
|
||||
if (unaligned_Q) begin
|
||||
// cross-word access
|
||||
if (crossword_Q) begin
|
||||
// cross-word access, regular instruction
|
||||
instr_rdata_int = {fetch_rdata[15:0], data_arr};
|
||||
current_pc_id_int = {fetch_addr_Q[31:2], 2'b10};
|
||||
current_pc_if_o = {fetch_addr_Q[31:2], 2'b10};
|
||||
end else begin
|
||||
// unaligned compressed instruction
|
||||
// don't care about upper half-word, insert good value for
|
||||
// optimization
|
||||
instr_rdata_int = {fetch_rdata[31:16], fetch_rdata[31:16]};
|
||||
current_pc_id_int = {fetch_addr[31:2], 2'b10};
|
||||
current_pc_if_o = {fetch_addr[31:2], 2'b10};
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -141,8 +133,6 @@ module if_stage
|
|||
instr_rdata_int = {25'b0, `OPCODE_OPIMM};
|
||||
end
|
||||
|
||||
assign current_pc_if_o = current_pc_id_int;
|
||||
|
||||
|
||||
// compressed instruction detection
|
||||
assign is_compressed[0] = fetch_rdata[1:0] != 2'b11;
|
||||
|
@ -153,13 +143,14 @@ module if_stage
|
|||
always_comb
|
||||
begin : EXC_PC_MUX
|
||||
unique case (exc_pc_mux_i)
|
||||
`EXC_PC_ILLINSN: begin exc_pc = {boot_addr_i[31:5], `EXC_OFF_ILLINSN }; end
|
||||
`EXC_PC_IRQ: begin exc_pc = {boot_addr_i[31:5], `EXC_OFF_IRQ }; end
|
||||
`EXC_PC_IRQ_NM: begin exc_pc = {boot_addr_i[31:5], `EXC_OFF_IRQ_NM }; end
|
||||
`EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:5], `EXC_OFF_ILLINSN };
|
||||
`EXC_PC_IRQ: exc_pc = { boot_addr_i[31:5], `EXC_OFF_IRQ };
|
||||
`EXC_PC_IRQ_NM: exc_pc = { boot_addr_i[31:5], `EXC_OFF_IRQ_NM };
|
||||
default: exc_pc = { boot_addr_i[31:5], `EXC_OFF_RST };
|
||||
endcase
|
||||
end
|
||||
|
||||
// next PC selection
|
||||
// fetch address selection
|
||||
always_comb
|
||||
begin
|
||||
unique case (pc_mux_sel_i)
|
||||
|
@ -203,30 +194,35 @@ module if_stage
|
|||
);
|
||||
|
||||
|
||||
// offset FSM
|
||||
enum logic[3:0] {IDLE, WAIT_ALIGNED, WAIT_UNALIGNED, VALID_ALIGNED, VALID_UNALIGNED,
|
||||
HANDLE_BRANCH, FETCH_UNALIGNED} offset_fsm_cs, offset_fsm_ns;
|
||||
|
||||
// offset FSM state
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (rst_n == 1'b0) begin
|
||||
offset_fsm_cs <= IDLE;
|
||||
offset_fsm_cs <= IDLE;
|
||||
offset_fsm_stored <= IDLE;
|
||||
end else begin
|
||||
offset_fsm_cs <= offset_fsm_ns;
|
||||
if (handle_branch) begin
|
||||
offset_fsm_cs <= HANDLE_BRANCH;
|
||||
offset_fsm_stored <= offset_fsm_ns;
|
||||
end
|
||||
else
|
||||
offset_fsm_cs <= offset_fsm_ns;
|
||||
end
|
||||
end
|
||||
|
||||
// offset FSM state logic
|
||||
// offset FSM state transition logic
|
||||
always_comb
|
||||
begin
|
||||
offset_fsm_ns = offset_fsm_cs;
|
||||
|
||||
fetch_req = 1'b0;
|
||||
valid_o = 1'b0;
|
||||
handle_branch = 1'b0;
|
||||
|
||||
unaligned = 1'b0;
|
||||
fetch_req = 1'b0;
|
||||
valid_o = 1'b0;
|
||||
|
||||
unaligned = unaligned_Q;
|
||||
crossword_n = crossword_Q;
|
||||
force_nop_int = 1'b0;
|
||||
branch_taken = 1'b0;
|
||||
|
||||
unique case (offset_fsm_cs)
|
||||
// no valid instruction data for ID stage
|
||||
|
@ -238,70 +234,87 @@ module if_stage
|
|||
end
|
||||
end
|
||||
|
||||
// We are currently in an ALIGNED state, serving PC[1] == 1'b0
|
||||
VALID_ALIGNED,
|
||||
WAIT_ALIGNED: begin
|
||||
unaligned = 1'b0;
|
||||
|
||||
if (fetch_valid || offset_fsm_cs == VALID_ALIGNED) begin
|
||||
valid_o = 1'b1;
|
||||
offset_fsm_ns = VALID_ALIGNED;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
if (jump_in_id_i == `BRANCH_NONE) begin
|
||||
// ----------------------------------------------------------------------
|
||||
// no branch in ID, do regular fetch
|
||||
// ----------------------------------------------------------------------
|
||||
if (is_compressed[0]) begin
|
||||
// compressed instruction
|
||||
if (is_compressed[1]) begin
|
||||
// upper half contains compressed instruction and is available
|
||||
// from register
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
end else begin
|
||||
// cross-word access, upper half is regular instruction
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end else begin
|
||||
// regular instruction
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
crossword_n = 1'b0;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// no branch in ID, do regular fetch
|
||||
// ----------------------------------------------------------------------
|
||||
if (is_compressed[0]) begin
|
||||
// compressed instruction
|
||||
if (is_compressed[1]) begin
|
||||
// upper half contains compressed instruction and is available
|
||||
// from register, don't start fetch now
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
end else begin
|
||||
// cross-word access, upper half is beginning of 32 bit instruction
|
||||
crossword_n = 1'b1;
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end else begin
|
||||
// regular instruction
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
|
||||
if (jump_in_id_i != `BRANCH_NONE) begin
|
||||
// ----------------------------------------------------------------------
|
||||
// need to handle branch
|
||||
// ----------------------------------------------------------------------
|
||||
offset_fsm_ns = HANDLE_BRANCH;
|
||||
handle_branch = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// We are currently in an unaligned state, serving PC[1] == 1'b1
|
||||
WAIT_UNALIGNED,
|
||||
VALID_UNALIGNED: begin
|
||||
unaligned = 1'b1;
|
||||
|
||||
if (fetch_valid || offset_fsm_cs == VALID_UNALIGNED) begin
|
||||
valid_o = 1'b1;
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
if (jump_in_id_i == `BRANCH_NONE) begin
|
||||
// ----------------------------------------------------------------------
|
||||
// no branch in ID, do regular fetch
|
||||
// ----------------------------------------------------------------------
|
||||
fetch_req = 1'b1;
|
||||
crossword_n = 1'b0;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// no branch in ID, do regular fetch
|
||||
// ----------------------------------------------------------------------
|
||||
if (crossword_Q) begin
|
||||
// last instruction was 32 bit crossword, unaligned
|
||||
if (is_compressed[1]) begin
|
||||
// compressed instruction, next instruction will be aligned
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
// compressed instruction, next instruction will be
|
||||
// unaligned
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
end else begin
|
||||
// regular instruction, fetch following instruction
|
||||
fetch_req = 1'b1;
|
||||
crossword_n = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end else begin
|
||||
// ----------------------------------------------------------------------
|
||||
// need to handle branch
|
||||
// ----------------------------------------------------------------------
|
||||
offset_fsm_ns = HANDLE_BRANCH;
|
||||
// compressed instruction because no cross-word access done,
|
||||
// next instruction will be aligned
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
|
||||
assert(is_compressed[1]) else $error("Not compressed, but compressed expected");
|
||||
end
|
||||
|
||||
if (jump_in_id_i != `BRANCH_NONE) begin
|
||||
handle_branch = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -310,17 +323,34 @@ module if_stage
|
|||
HANDLE_BRANCH: begin
|
||||
// assume jump/branch instruction is in EX stage
|
||||
if (jump_in_ex_i == `BRANCH_COND && ~branch_decision_i) begin
|
||||
// TODO: Optimize this, already send request & valid
|
||||
if (unaligned_Q)
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
else
|
||||
offset_fsm_ns = VALID_ALIGNED;
|
||||
// branch not taken
|
||||
|
||||
// let's go to one instruction after the one we already put into the
|
||||
// pipeline
|
||||
if (unaligned_Q) begin
|
||||
// last state was unaligned, go back
|
||||
if (crossword_Q) begin
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end else begin
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
end else begin
|
||||
crossword_n = 1'b0;
|
||||
|
||||
if (is_compressed[0]) begin
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
end else begin
|
||||
offset_fsm_ns = VALID_ALIGNED;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
// branch/jump taken
|
||||
branch_taken = 1'b1;
|
||||
fetch_req = 1'b1;
|
||||
// branch taken or jump
|
||||
fetch_req = 1'b1;
|
||||
crossword_n = 1'b0;
|
||||
if (unaligned_jump) begin
|
||||
unaligned = 1'b1;
|
||||
// if the target address is unaligned, we need to fetch the lower
|
||||
// word first
|
||||
offset_fsm_ns = FETCH_UNALIGNED;
|
||||
|
@ -330,22 +360,33 @@ module if_stage
|
|||
end
|
||||
end
|
||||
|
||||
// can be cross-word or compressed
|
||||
FETCH_UNALIGNED: begin
|
||||
unaligned = 1'b1;
|
||||
|
||||
if (fetch_valid) begin
|
||||
if (is_compressed[1]) begin
|
||||
// no cross-word access
|
||||
valid_o = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
crossword_n = 1'b0;
|
||||
valid_o = 1'b1;
|
||||
if (req_i && ~stall_if_i) begin
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end else begin
|
||||
offset_fsm_ns = VALID_UNALIGNED;
|
||||
end
|
||||
end else begin
|
||||
// cross-word access, fetch next word
|
||||
fetch_req = 1'b1;
|
||||
fetch_req = 1'b1;
|
||||
crossword_n = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
offset_fsm_ns = IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -362,20 +403,33 @@ module if_stage
|
|||
end
|
||||
|
||||
|
||||
// store instr_core_if data in local cache
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (rst_n == 1'b0) begin
|
||||
data_arr <= 16'b0;
|
||||
fetch_addr_Q <= 32'b0;
|
||||
end else begin
|
||||
if (~stall_if_i) begin
|
||||
data_arr <= fetch_rdata[31:16];
|
||||
fetch_addr_Q <= fetch_addr;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// IF PC register
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin : IF_PIPELINE
|
||||
if (rst_n == 1'b0)
|
||||
begin
|
||||
crossword_Q <= 1'b0;
|
||||
unaligned_Q <= 1'b0;
|
||||
fetch_addr_Q <= 32'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (fetch_valid) begin
|
||||
unaligned_Q <= unaligned;
|
||||
fetch_addr_Q <= fetch_addr;
|
||||
end
|
||||
crossword_Q <= crossword_n;
|
||||
unaligned_Q <= unaligned;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -392,7 +446,7 @@ module if_stage
|
|||
if (stall_id_i == 1'b0)
|
||||
begin : ENABLED_PIPE
|
||||
instr_rdata_id_o <= instr_rdata_int;
|
||||
current_pc_id_o <= current_pc_id_int;
|
||||
current_pc_id_o <= current_pc_if_o;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue