Make sure instr address output is word aligned

The core handles unaligned instruction fetches by doing two separate
word-aligned instruction fetches. Without this commit, the core can
still output addresses which are not word aligned and relies on the
memory to ignore the LSBs of the address. This is not safe.
This commit is contained in:
Pirmin Vogel 2019-06-20 12:05:11 +01:00 committed by Philipp Wagner
parent 182e10048b
commit b7919a7bd3
2 changed files with 37 additions and 24 deletions

View file

@ -4,10 +4,7 @@ Instruction Fetch
=================
The Instruction-Fetch (IF) stage of the core is able to supply one instruction to the Instruction-Decode (ID) stage per cycle if the instruction cache or the instruction memory is able to serve one instruction per cycle.
The instruction address must be half-word-aligned due to the support of compressed instructions.
It is not possible to jump to instruction addresses that have the LSB bit set.
For optimal performance and timing closure reasons, a prefetcher is used which fetches instruction from the instruction memory, or instruction cache.
For optimal performance and timing closure reasons, a prefetcher is used which fetches instructions from the instruction memory, or instruction cache.
The following table describes the signals that are used to fetch instructions.
This interface is a simplified version of the interface used on the data interface as described in :ref:`load-store-unit`.
@ -21,7 +18,7 @@ The main difference is that the instruction interface does not allow for writes
| ``instr_req_o`` | output | Request valid, must stay high until |
| | | ``instr_gnt_i`` is high for one cycle |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_addr_o[31:0]`` | output | Address |
| ``instr_addr_o[31:0]`` | output | Address, word aligned |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_gnt_i`` | input | The other side accepted the request. |
| | | ``instr_req_o`` may be deasserted in the next |
@ -35,6 +32,15 @@ The main difference is that the instruction interface does not allow for writes
+-------------------------+-----------+-----------------------------------------------+
Misaligned Accesses
-------------------
Externally, the IF interface performs word-aligned instruction fetches only.
Misaligned instruction fetches are handled by performing two separate word-aligned instruction fetches.
Internally, the core can deal with both word- and half-word-aligned instruction addresses to support compressed instructions.
The LSB of the instruction address is ignored internally.
Protocol
--------

View file

@ -54,6 +54,7 @@ module ibex_prefetch_buffer (
pf_fsm_e pf_fsm_cs, pf_fsm_ns;
logic [31:0] instr_addr_q, fetch_addr;
logic [31:0] instr_addr, instr_addr_w_aligned;
logic addr_valid;
logic fifo_valid;
@ -103,20 +104,20 @@ module ibex_prefetch_buffer (
//////////////////////////////////////////////////////////////////////////////
always_comb begin
instr_req_o = 1'b0;
instr_addr_o = fetch_addr;
fifo_valid = 1'b0;
addr_valid = 1'b0;
pf_fsm_ns = pf_fsm_cs;
instr_req_o = 1'b0;
instr_addr = fetch_addr;
fifo_valid = 1'b0;
addr_valid = 1'b0;
pf_fsm_ns = pf_fsm_cs;
unique case(pf_fsm_cs)
// default state, not waiting for requested data
IDLE: begin
instr_addr_o = fetch_addr;
instr_req_o = 1'b0;
instr_addr = fetch_addr;
instr_req_o = 1'b0;
if (branch_i) begin
instr_addr_o = addr_i;
instr_addr = addr_i;
end
if (req_i && (fifo_ready || branch_i )) begin
@ -131,12 +132,12 @@ module ibex_prefetch_buffer (
// we sent a request but did not yet get a grant
WAIT_GNT: begin
instr_addr_o = instr_addr_q;
instr_req_o = 1'b1;
instr_addr = instr_addr_q;
instr_req_o = 1'b1;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
instr_addr = addr_i;
addr_valid = 1'b1;
end
//~> granted request or not
@ -145,10 +146,10 @@ module ibex_prefetch_buffer (
// we wait for rvalid, after that we are ready to serve a new request
WAIT_RVALID: begin
instr_addr_o = fetch_addr;
instr_addr = fetch_addr;
if (branch_i) begin
instr_addr_o = addr_i;
instr_addr = addr_i;
end
if (req_i && (fifo_ready || branch_i)) begin
@ -183,15 +184,15 @@ module ibex_prefetch_buffer (
// there was no new request sent yet
// we assume that req_i is set to high
WAIT_ABORTED: begin
instr_addr_o = instr_addr_q;
instr_addr = instr_addr_q;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
instr_addr = addr_i;
addr_valid = 1'b1;
end
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
instr_req_o = 1'b1;
// no need to send address, already done in WAIT_RVALID
//~> granted request or not
@ -217,9 +218,15 @@ module ibex_prefetch_buffer (
pf_fsm_cs <= pf_fsm_ns;
if (addr_valid) begin
instr_addr_q <= instr_addr_o;
instr_addr_q <= instr_addr;
end
end
end
/////////////////
// Output Addr //
/////////////////
assign instr_addr_w_aligned = {instr_addr[31:2], 2'b00};
assign instr_addr_o = instr_addr_w_aligned;
endmodule