mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
Prefetcher basically done, works in pulpino without rvc
This commit is contained in:
parent
79bce5b31b
commit
e0ea57968b
3 changed files with 398 additions and 229 deletions
|
@ -264,7 +264,8 @@ module compressed_decoder
|
|||
endcase
|
||||
end
|
||||
|
||||
2'b11: begin
|
||||
// 2'b11:
|
||||
default: begin
|
||||
// 32 bit (or more) instruction
|
||||
instr_o = instr_i;
|
||||
end
|
||||
|
|
256
if_stage.sv
256
if_stage.sv
|
@ -89,51 +89,41 @@ module if_stage
|
|||
);
|
||||
|
||||
// offset FSM
|
||||
enum logic[3:0] {WAIT_ALIGNED, VALID_ALIGNED,
|
||||
UNALIGNED_16,
|
||||
WAIT_UNALIGNED_32, VALID_UNALIGNED_32,
|
||||
WAIT_JUMPED_ALIGNED, VALID_JUMPED_ALIGNED,
|
||||
WAIT_JUMPED_UNALIGNED, VALID_JUMPED_UNALIGNED,
|
||||
enum logic[3:0] {WAIT_ALIGNED, WAIT_UNALIGNED,
|
||||
IDLE } offset_fsm_cs, offset_fsm_ns;
|
||||
|
||||
logic [1:0] is_compressed;
|
||||
logic crossword;
|
||||
logic unaligned;
|
||||
logic unaligned_jump;
|
||||
|
||||
// instr_core_interface
|
||||
logic fetch_req;
|
||||
logic [31:0] fetch_rdata;
|
||||
logic branch_req;
|
||||
logic [31:0] fetch_addr_n;
|
||||
|
||||
logic fetch_valid;
|
||||
logic [31:0] fetch_addr_n, fetch_addr_Q, fetch_addr_QQ;
|
||||
logic fetch_ready;
|
||||
logic [31:0] fetch_rdata;
|
||||
logic [31:0] fetch_addr;
|
||||
|
||||
logic fetch_unaligned_valid;
|
||||
logic [31:0] fetch_unaligned_rdata;
|
||||
|
||||
|
||||
logic [31:0] instr_rdata_int;
|
||||
|
||||
logic [31:0] exc_pc;
|
||||
|
||||
// local cache
|
||||
logic [15:0] data_arr;
|
||||
|
||||
|
||||
// output data and PC mux
|
||||
always_comb
|
||||
begin
|
||||
// default values for regular aligned access
|
||||
instr_rdata_int = fetch_rdata;
|
||||
current_pc_if_o = {fetch_addr_Q[31:2], 2'b00};
|
||||
current_pc_if_o = {fetch_addr[31:2], 2'b00};
|
||||
|
||||
if (unaligned) begin
|
||||
if (crossword) begin
|
||||
// cross-word access, regular instruction
|
||||
instr_rdata_int = {fetch_rdata[15:0], data_arr};
|
||||
current_pc_if_o = {fetch_addr_QQ[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[15:0], fetch_rdata[31:16]};
|
||||
current_pc_if_o = {fetch_addr_Q[31:2], 2'b10};
|
||||
end
|
||||
current_pc_if_o = {fetch_addr[31:2], 2'b10};
|
||||
instr_rdata_int = fetch_unaligned_rdata;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -161,7 +151,8 @@ module if_stage
|
|||
`PC_BOOT: fetch_addr_n = {boot_addr_i[31:5], `EXC_OFF_RST};
|
||||
`PC_JUMP: fetch_addr_n = {jump_target_id_i[31:2], 2'b0};
|
||||
`PC_BRANCH: fetch_addr_n = {jump_target_ex_i[31:2], 2'b0};
|
||||
`PC_INCR: fetch_addr_n = fetch_addr_Q + 32'd4; // incremented PC
|
||||
// TODO: remove the next entry
|
||||
`PC_INCR: fetch_addr_n = 'X; // no longer needed, remove!
|
||||
`PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler
|
||||
`PC_ERET: fetch_addr_n = exception_pc_reg_i; // PC is restored when returning from IRQ/exception
|
||||
`PC_HWLOOP: fetch_addr_n = hwloop_target_i; // PC is taken from hwloop start addr
|
||||
|
@ -193,20 +184,26 @@ module if_stage
|
|||
// cache fetch interface
|
||||
instr_core_interface instr_core_if_i
|
||||
(
|
||||
.clk ( clk ),
|
||||
.rst_n ( rst_n ),
|
||||
.clk ( clk ),
|
||||
.rst_n ( rst_n ),
|
||||
|
||||
.req_i ( fetch_req ),
|
||||
.addr_i ( fetch_addr_n ),
|
||||
.valid_o ( fetch_valid ),
|
||||
.rdata_o ( fetch_rdata ),
|
||||
.last_addr_o ( fetch_addr_Q ),
|
||||
.req_i ( 1'b1 ),
|
||||
.clear_i ( branch_req ),
|
||||
.addr_i ( fetch_addr_n ),
|
||||
|
||||
.instr_req_o ( instr_req_o ),
|
||||
.instr_addr_o ( instr_addr_o ),
|
||||
.instr_gnt_i ( instr_gnt_i ),
|
||||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i )
|
||||
.ready_i ( fetch_ready ),
|
||||
.valid_o ( fetch_valid ),
|
||||
.rdata_o ( fetch_rdata ),
|
||||
.addr_o ( fetch_addr ),
|
||||
|
||||
.unaligned_valid_o ( fetch_unaligned_valid ),
|
||||
.unaligned_rdata_o ( fetch_unaligned_rdata ),
|
||||
|
||||
.instr_req_o ( instr_req_o ),
|
||||
.instr_addr_o ( instr_addr_o ),
|
||||
.instr_gnt_i ( instr_gnt_i ),
|
||||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i )
|
||||
);
|
||||
|
||||
|
||||
|
@ -225,162 +222,69 @@ module if_stage
|
|||
begin
|
||||
offset_fsm_ns = offset_fsm_cs;
|
||||
|
||||
fetch_req = 1'b0;
|
||||
valid_o = 1'b0;
|
||||
fetch_ready = 1'b0;
|
||||
branch_req = 1'b0;
|
||||
valid_o = 1'b0;
|
||||
|
||||
unaligned = 1'b0;
|
||||
crossword = 1'b0;
|
||||
|
||||
unique case (offset_fsm_cs)
|
||||
// no valid instruction data for ID stage
|
||||
// assume aligned
|
||||
IDLE: begin
|
||||
if (req_i) begin
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_JUMPED_ALIGNED;
|
||||
branch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
end
|
||||
|
||||
// serving aligned 32 bit or 16 bit instruction, we don't know yet
|
||||
WAIT_ALIGNED,
|
||||
VALID_ALIGNED: begin
|
||||
if (fetch_valid || offset_fsm_cs == VALID_ALIGNED) begin
|
||||
WAIT_ALIGNED: begin
|
||||
if (fetch_valid) begin
|
||||
valid_o = 1'b1; // an instruction is ready for ID stage
|
||||
offset_fsm_ns = VALID_ALIGNED;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
|
||||
if (~is_compressed[0]) begin
|
||||
// 32 bit aligned instruction found
|
||||
fetch_req = 1'b1;
|
||||
fetch_ready = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end else begin
|
||||
// 16 bit aligned instruction found
|
||||
if (is_compressed[1]) begin
|
||||
// next is 16 bit unaligned instruction
|
||||
// we already have that data, no need to fetch anything
|
||||
offset_fsm_ns = UNALIGNED_16;
|
||||
end else begin
|
||||
// next is 32 bit unaligned instruction
|
||||
// the upper half of this instruction is missing, start
|
||||
// fetching it
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED_32;
|
||||
end
|
||||
// next instruction will be unaligned
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// serving unaligned 16 bit instruction
|
||||
// next instruction will be aligned, either 16 bit or 32 bit
|
||||
UNALIGNED_16: begin
|
||||
unaligned = 1'b1;
|
||||
|
||||
// we don't need to wait for a fetch_valid as we already have the data
|
||||
valid_o = 1'b1;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
// next instruction will be aligned
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
end
|
||||
|
||||
// serving unaligned 32 bit instruction
|
||||
// next instruction might be 16 bit unaligned (no need to fetch)
|
||||
// or 32 bit unaligned (need to fetch another word from cache)
|
||||
WAIT_UNALIGNED_32,
|
||||
VALID_UNALIGNED_32: begin
|
||||
unaligned = 1'b1;
|
||||
crossword = 1'b1;
|
||||
|
||||
if (fetch_valid || offset_fsm_cs == VALID_UNALIGNED_32) begin
|
||||
valid_o = 1'b1;
|
||||
offset_fsm_ns = VALID_UNALIGNED_32;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
|
||||
if (is_compressed[1]) begin
|
||||
// next is 16 bit unaligned instruction
|
||||
// we already have that data, no need to fetch anything
|
||||
offset_fsm_ns = UNALIGNED_16;
|
||||
end else begin
|
||||
// next is 32 bit unaligned instruction
|
||||
// the upper half of this instruction is missing, start
|
||||
// fetching it
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED_32;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// we did an aligned jump
|
||||
// current instruction is either 16 bit aligned or 32 bit aligned
|
||||
// so next instruction can be one of the following:
|
||||
// - 32 bit aligned (if 32 bit aligned now)
|
||||
// - 16 bit unaligned (if 16 bit aligned now)
|
||||
// - 32 bit unaligned (if 16 bit aligned now)
|
||||
WAIT_JUMPED_ALIGNED,
|
||||
VALID_JUMPED_ALIGNED: begin
|
||||
|
||||
if (fetch_valid || offset_fsm_cs == VALID_JUMPED_ALIGNED) begin
|
||||
valid_o = 1'b1;
|
||||
offset_fsm_ns = VALID_JUMPED_ALIGNED;
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
|
||||
if (is_compressed[0]) begin
|
||||
// this instruction is 16 bit
|
||||
|
||||
if (is_compressed[1]) begin
|
||||
// next instruction is also 16 bit
|
||||
offset_fsm_ns = UNALIGNED_16;
|
||||
end else begin
|
||||
// next is 32 bit unaligned instruction
|
||||
// the upper half of this instruction is missing, start
|
||||
// fetching it
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED_32;
|
||||
end
|
||||
end else begin
|
||||
// this instruction is 32 bit, so next one will be aligned
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// we did an unaligned jump
|
||||
// current instruction is either 16 bit unaligned (ready to serve) or 32
|
||||
// bit unaligned (still need to get data)
|
||||
WAIT_JUMPED_UNALIGNED,
|
||||
VALID_JUMPED_UNALIGNED: begin
|
||||
WAIT_UNALIGNED: begin
|
||||
unaligned = 1'b1;
|
||||
|
||||
if (fetch_valid || offset_fsm_cs == VALID_JUMPED_UNALIGNED) begin
|
||||
// here we might not yet have the data, if the instruction is 32 bit
|
||||
// unaligned
|
||||
offset_fsm_ns = VALID_JUMPED_UNALIGNED;
|
||||
|
||||
if (fetch_valid) begin
|
||||
if (is_compressed[1]) begin
|
||||
// Puh, lucky, we got a 16 bit instruction
|
||||
valid_o = 1'b1;
|
||||
valid_o = 1'b1; // an instruction is ready for ID stage
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
// next instruction will be aligned
|
||||
fetch_req = 1'b1;
|
||||
fetch_ready = 1'b1;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
|
||||
end else begin
|
||||
// a 32 bit unaligned instruction, let's fetch the upper half
|
||||
// we don't wait for stalls here as we still need data to get
|
||||
// unstalled
|
||||
fetch_req = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED_32;
|
||||
// not compressed, we are looking at a 32 bit instruction
|
||||
|
||||
if (fetch_unaligned_valid) begin
|
||||
valid_o = 1'b1; // an instruction is ready for ID stage
|
||||
|
||||
if (req_i && ~stall_if_i) begin
|
||||
// next instruction will be unaligned
|
||||
fetch_ready = 1'b1;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -396,50 +300,34 @@ module if_stage
|
|||
if (jump_in_ex_i == `BRANCH_COND) begin
|
||||
if (branch_decision_i) begin
|
||||
// branch taken
|
||||
fetch_req = 1'b1;
|
||||
branch_req = 1'b1;
|
||||
if (unaligned_jump)
|
||||
offset_fsm_ns = WAIT_JUMPED_UNALIGNED;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
else
|
||||
offset_fsm_ns = WAIT_JUMPED_ALIGNED;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
|
||||
end else if (jump_in_id_i == `BRANCH_JAL || jump_in_id_i == `BRANCH_JALR
|
||||
|| dbg_set_npc_i
|
||||
|| hwloop_jump_i) begin
|
||||
// switch to new PC from ID stage
|
||||
fetch_req = 1'b1;
|
||||
branch_req = 1'b1;
|
||||
if (unaligned_jump)
|
||||
offset_fsm_ns = WAIT_JUMPED_UNALIGNED;
|
||||
offset_fsm_ns = WAIT_UNALIGNED;
|
||||
else
|
||||
offset_fsm_ns = WAIT_JUMPED_ALIGNED;
|
||||
offset_fsm_ns = WAIT_ALIGNED;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// store instr_core_if data in local cache
|
||||
// store last address used to fetch an instruction
|
||||
// we also store the address we used before, so
|
||||
// fetch_addr_n -> fetch_addr_Q -> fetch_addr_QQ
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (rst_n == 1'b0) begin
|
||||
data_arr <= 16'b0;
|
||||
fetch_addr_QQ <= 32'b0;
|
||||
end else begin
|
||||
if (fetch_req) begin
|
||||
data_arr <= fetch_rdata[31:16];
|
||||
fetch_addr_QQ <= fetch_addr_Q;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign if_busy_o = ~(offset_fsm_cs == IDLE ||
|
||||
offset_fsm_cs == VALID_JUMPED_ALIGNED ||
|
||||
offset_fsm_cs == VALID_JUMPED_UNALIGNED ||
|
||||
offset_fsm_cs == VALID_ALIGNED ||
|
||||
offset_fsm_cs == VALID_UNALIGNED_32 ||
|
||||
offset_fsm_cs == UNALIGNED_16) || instr_req_o;
|
||||
assign if_busy_o = 1'b1; // TODO
|
||||
// assign if_busy_o = ~(offset_fsm_cs == IDLE ||
|
||||
// offset_fsm_cs == VALID_JUMPED_ALIGNED ||
|
||||
// offset_fsm_cs == VALID_JUMPED_UNALIGNED ||
|
||||
// offset_fsm_cs == VALID_ALIGNED ||
|
||||
// offset_fsm_cs == VALID_UNALIGNED_32 ||
|
||||
// offset_fsm_cs == UNALIGNED_16) || instr_req_o;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -23,18 +23,194 @@
|
|||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// input port: send address one cycle before the data
|
||||
// clear_i clears the FIFO for the following cycle. in_addr_i can be sent in
|
||||
// this cycle already
|
||||
module fetch_fifo
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
|
||||
// control signals
|
||||
input logic clear_i, // clears the contents of the fifo
|
||||
|
||||
// input port
|
||||
input logic in_addr_valid_i,
|
||||
output logic in_addr_ready_o,
|
||||
input logic [31:0] in_addr_i,
|
||||
output logic [31:0] in_last_addr_o,
|
||||
|
||||
input logic in_rdata_valid_i,
|
||||
output logic in_rdata_ready_o,
|
||||
input logic [31:0] in_rdata_i,
|
||||
|
||||
// output port
|
||||
output logic out_valid_o,
|
||||
input logic out_ready_i,
|
||||
output logic [31:0] out_rdata_o,
|
||||
output logic [31:0] out_addr_o,
|
||||
|
||||
output logic out_unaligned_valid_o,
|
||||
output logic [31:0] out_unaligned_rdata_o
|
||||
);
|
||||
|
||||
localparam DEPTH = 2; // must be 2 or greater
|
||||
|
||||
// index 0 is used for output
|
||||
logic [0:DEPTH-1] [31:0] addr_n, addr_int, addr_Q;
|
||||
logic [0:DEPTH-1] addr_valid_n, addr_valid_int, addr_valid_Q;
|
||||
logic [0:DEPTH-1] [31:0] rdata_n, rdata_int, rdata_Q;
|
||||
logic [0:DEPTH-1] rdata_valid_n, rdata_valid_int, rdata_valid_Q;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// output port
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// output assignments
|
||||
assign out_rdata_o = (rdata_valid_Q[0]) ? rdata_Q[0] : in_rdata_i;
|
||||
assign out_addr_o = addr_Q[0]; // always output addr directly since we sent it one cycle earlier to the FIFO
|
||||
|
||||
assign out_valid_o = (rdata_valid_Q[0] || (addr_valid_Q[0] && in_rdata_valid_i));
|
||||
|
||||
assign out_unaligned_rdata_o = (rdata_valid_Q[1]) ? {rdata_Q[1][15:0], rdata_Q[0][31:16]} : {in_rdata_i[15:0], rdata_Q[0][31:16]};
|
||||
// it is implied that rdata_valid_Q[0] is set
|
||||
assign out_unaligned_valid_o = (rdata_valid_Q[1] || (addr_valid_Q[1] && in_rdata_valid_i));
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// input port
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// we accept addresses as long as our fifo is not full or we are cleared
|
||||
assign in_addr_ready_o = clear_i || (~addr_valid_Q[DEPTH-1]);
|
||||
|
||||
// we accept data as long as our fifo is not full
|
||||
// we don't care about clear here as the data will be received one cycle
|
||||
// later anyway
|
||||
assign in_rdata_ready_o = ~rdata_valid_Q[DEPTH-1];
|
||||
|
||||
|
||||
// output the latest valid address we got
|
||||
int i;
|
||||
always_comb
|
||||
begin
|
||||
in_last_addr_o = addr_Q[0];
|
||||
|
||||
for(i = 1; i < DEPTH; i++) begin
|
||||
if (addr_valid_Q[i])
|
||||
in_last_addr_o = addr_Q[i];
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// FIFO management
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int j;
|
||||
always_comb
|
||||
begin
|
||||
addr_int = addr_Q;
|
||||
addr_valid_int = addr_valid_Q;
|
||||
|
||||
if (in_addr_valid_i && in_addr_ready_o) begin
|
||||
for(j = 0; j < DEPTH; j++) begin
|
||||
if (~addr_valid_Q[j]) begin
|
||||
addr_int[j] = in_addr_i;
|
||||
addr_valid_int[j] = 1'b1;
|
||||
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
int k;
|
||||
always_comb
|
||||
begin
|
||||
rdata_int = rdata_Q;
|
||||
rdata_valid_int = rdata_valid_Q;
|
||||
|
||||
if (in_rdata_valid_i && in_rdata_ready_o) begin
|
||||
for(k = 0; k < DEPTH; k++) begin
|
||||
if (~rdata_valid_Q[k]) begin
|
||||
rdata_int[k] = in_rdata_i;
|
||||
rdata_valid_int[k] = 1'b1;
|
||||
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// move everything by one step
|
||||
always_comb
|
||||
begin
|
||||
addr_n = addr_int;
|
||||
addr_valid_n = addr_valid_int;
|
||||
rdata_n = rdata_int;
|
||||
rdata_valid_n = rdata_valid_int;
|
||||
|
||||
if (out_ready_i && out_valid_o) begin
|
||||
addr_n = {addr_int[1:DEPTH-1], 32'b0};
|
||||
addr_valid_n = {addr_valid_int[1:DEPTH-1], 1'b0};
|
||||
rdata_n = {rdata_int[1:DEPTH-1], 32'b0};
|
||||
rdata_valid_n = {rdata_valid_int[1:DEPTH-1], 1'b0};
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// registers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if(rst_n == 1'b0)
|
||||
begin
|
||||
addr_Q <= '{default: '0};
|
||||
addr_valid_Q <= '0;
|
||||
rdata_Q <= '{default: '0};
|
||||
rdata_valid_Q <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// on a clear signal from outside we invalidate the content of the FIFO
|
||||
// completely and start from an empty state
|
||||
if (clear_i) begin
|
||||
addr_Q[0] <= in_addr_i;
|
||||
addr_valid_Q <= {in_addr_valid_i, {DEPTH-1{1'b0}}};
|
||||
rdata_valid_Q <= '0;
|
||||
end else begin
|
||||
addr_Q <= addr_n;
|
||||
addr_valid_Q <= addr_valid_n;
|
||||
rdata_Q <= rdata_n;
|
||||
rdata_valid_Q <= rdata_valid_n;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
// clear_i deletes everything up to now, i.e. it assumes that addr_i now has
|
||||
// the correct state and uses the current cycle's addr_i to fetch new data
|
||||
module instr_core_interface
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
|
||||
input logic req_i,
|
||||
input logic clear_i,
|
||||
input logic ready_i,
|
||||
input logic [31:0] addr_i,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [31:0] rdata_o,
|
||||
output logic [31:0] last_addr_o,
|
||||
output logic [31:0] addr_o,
|
||||
|
||||
output logic unaligned_valid_o,
|
||||
output logic [31:0] unaligned_rdata_o,
|
||||
|
||||
// goes to instruction memory / instruction cache
|
||||
output logic instr_req_o,
|
||||
output logic [31:0] instr_addr_o,
|
||||
input logic instr_gnt_i,
|
||||
|
@ -42,56 +218,84 @@ module instr_core_interface
|
|||
input logic [31:0] instr_rdata_i
|
||||
);
|
||||
|
||||
enum logic [1:0] {IDLE, WAIT_RVALID, WAIT_GNT } CS, NS;
|
||||
// TODO: THERE IS A PROBLEM WIHT REQ_I AND CLEAR_I
|
||||
// i.e. what happens if req_i is low and clear_i is high? the core will miss
|
||||
// the updated address....
|
||||
|
||||
logic [31:0] rdata_Q;
|
||||
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
|
||||
|
||||
logic wait_gnt;
|
||||
logic [31:0] addr_Q;
|
||||
logic [31:0] addr_next;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if(rst_n == 1'b0)
|
||||
begin
|
||||
CS <= IDLE;
|
||||
rdata_Q <= '0;
|
||||
addr_Q <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
CS <= NS;
|
||||
logic fifo_addr_valid;
|
||||
logic fifo_addr_ready;
|
||||
logic [31:0] fifo_last_addr;
|
||||
|
||||
if (wait_gnt)
|
||||
addr_Q <= instr_addr_o;
|
||||
logic fifo_rdata_valid;
|
||||
logic fifo_rdata_ready;
|
||||
|
||||
if (instr_rvalid_i)
|
||||
rdata_Q <= instr_rdata_i;
|
||||
end
|
||||
end
|
||||
|
||||
assign valid_o = instr_rvalid_i;
|
||||
assign last_addr_o = addr_Q;
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// address selection and increase
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
assign addr_next = (clear_i) ? addr_i : (fifo_last_addr + 32'd4);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// fetch fifo
|
||||
// consumes addresses and rdata
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fetch_fifo fifo_i
|
||||
(
|
||||
.clk ( clk ),
|
||||
.rst_n ( rst_n ),
|
||||
|
||||
.clear_i ( clear_i ),
|
||||
|
||||
.in_addr_valid_i ( fifo_addr_valid ),
|
||||
.in_addr_ready_o ( fifo_addr_ready ),
|
||||
.in_addr_i ( addr_next ),
|
||||
.in_last_addr_o ( fifo_last_addr ),
|
||||
|
||||
.in_rdata_valid_i ( fifo_rdata_valid ),
|
||||
.in_rdata_ready_o ( fifo_rdata_ready ),
|
||||
.in_rdata_i ( instr_rdata_i ),
|
||||
|
||||
.out_valid_o ( valid_o ),
|
||||
.out_ready_i ( ready_i ),
|
||||
.out_rdata_o ( rdata_o ),
|
||||
.out_addr_o ( addr_o ),
|
||||
|
||||
.out_unaligned_valid_o ( unaligned_valid_o ),
|
||||
.out_unaligned_rdata_o ( unaligned_rdata_o )
|
||||
);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// instruction fetch FSM
|
||||
// deals with instruction memory / instruction cache
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
always_comb
|
||||
begin
|
||||
instr_req_o = 1'b0;
|
||||
rdata_o = instr_rdata_i;
|
||||
instr_addr_o = addr_i;
|
||||
wait_gnt = 1'b0;
|
||||
NS = CS;
|
||||
instr_req_o = 1'b0;
|
||||
instr_addr_o = addr_next;
|
||||
fifo_addr_valid = 1'b0;
|
||||
fifo_rdata_valid = 1'b0;
|
||||
NS = CS;
|
||||
|
||||
unique case(CS)
|
||||
// default state, not waiting for requested data
|
||||
IDLE:
|
||||
begin
|
||||
rdata_o = rdata_Q;
|
||||
|
||||
instr_req_o = 1'b0;
|
||||
|
||||
if(req_i) begin
|
||||
if (req_i && fifo_addr_ready) begin
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
wait_gnt = 1'b1;
|
||||
fifo_addr_valid = 1'b1;
|
||||
|
||||
if(instr_gnt_i) //~> granted request
|
||||
NS = WAIT_RVALID;
|
||||
else begin //~> got a request but no grant
|
||||
|
@ -103,25 +307,85 @@ module instr_core_interface
|
|||
// we sent a request but did not yet get a grant
|
||||
WAIT_GNT:
|
||||
begin
|
||||
instr_addr_o = addr_Q;
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
if(instr_gnt_i)
|
||||
NS = WAIT_RVALID;
|
||||
else
|
||||
NS = WAIT_GNT;
|
||||
if (clear_i) begin
|
||||
instr_addr_o = addr_next;
|
||||
|
||||
if (req_i && fifo_addr_ready) begin
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
fifo_addr_valid = 1'b1;
|
||||
|
||||
if(instr_gnt_i) //~> granted request
|
||||
NS = WAIT_ABORTED;
|
||||
else begin //~> got a request but no grant
|
||||
NS = WAIT_GNT;
|
||||
end
|
||||
end else begin
|
||||
if(instr_gnt_i) //~> granted request
|
||||
NS = WAIT_ABORTED;
|
||||
else begin //~> got a request but no grant
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
instr_req_o = 1'b1;
|
||||
instr_addr_o = fifo_last_addr;
|
||||
|
||||
if(instr_gnt_i)
|
||||
NS = WAIT_RVALID;
|
||||
else
|
||||
NS = WAIT_GNT;
|
||||
end
|
||||
end // case: WAIT_GNT
|
||||
|
||||
// we wait for rvalid, after that we are ready to serve a new request
|
||||
WAIT_RVALID :
|
||||
begin
|
||||
WAIT_RVALID: begin
|
||||
|
||||
if (req_i) begin
|
||||
if (req_i && fifo_addr_ready) begin
|
||||
// prepare for next request
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
if (instr_rvalid_i) begin
|
||||
wait_gnt = 1'b1;
|
||||
fifo_rdata_valid = 1'b1;
|
||||
fifo_addr_valid = 1'b1;
|
||||
|
||||
if (instr_gnt_i) begin
|
||||
NS = WAIT_RVALID;
|
||||
end else begin
|
||||
NS = WAIT_GNT;
|
||||
end
|
||||
end else begin
|
||||
// we are requested to abort our current request
|
||||
if (clear_i)
|
||||
NS = WAIT_ABORTED;
|
||||
end
|
||||
end else begin
|
||||
// just wait for rvalid and go back to IDLE, no new request
|
||||
// requested
|
||||
instr_req_o = 1'b0;
|
||||
|
||||
if (instr_rvalid_i) begin
|
||||
fifo_rdata_valid = 1'b1;
|
||||
NS = IDLE;
|
||||
end else begin
|
||||
if (clear_i)
|
||||
NS = WAIT_ABORTED;
|
||||
end
|
||||
end
|
||||
end // case: WAIT_RVALID
|
||||
|
||||
// our last request was aborted, but we didn't yet get a rvalid and
|
||||
// there was no new request sent yet
|
||||
WAIT_ABORTED: begin
|
||||
if (req_i && fifo_addr_ready) begin
|
||||
// prepare for next request
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
if (instr_rvalid_i) begin
|
||||
fifo_addr_valid = 1'b1;
|
||||
|
||||
if (instr_gnt_i) begin
|
||||
NS = WAIT_RVALID;
|
||||
end else begin
|
||||
|
@ -137,7 +401,7 @@ module instr_core_interface
|
|||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
end // case: WAIT_RVALID
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
|
@ -147,4 +411,20 @@ module instr_core_interface
|
|||
endcase
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// registers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if(rst_n == 1'b0)
|
||||
begin
|
||||
CS <= IDLE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
CS <= NS;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue