mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
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:
parent
182e10048b
commit
b7919a7bd3
2 changed files with 37 additions and 24 deletions
|
@ -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
|
||||
--------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue