IF Sync, problems in RVC

This commit is contained in:
Sven Stucki 2015-08-26 19:13:09 +02:00
parent 685b6dbabb
commit d324cfc01f

View file

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