mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 21:17:59 -04:00
[RTL] - Remove timing loop in LSU
- Relates to issue #265 - External signals data_rvalid_i and data_err_i were factored into the external data_req_o signal - To improve timing, these signals are decoupled - The second part of an unaligned transaction will now be issued even if the first received an error response - The state machine will service the abandoned requests - pmp_err_q fixed to only update at specific times
This commit is contained in:
parent
e9c2b2ecb3
commit
36db104160
2 changed files with 71 additions and 19 deletions
|
@ -48,6 +48,10 @@ The LSU is able to handle misaligned memory accesses, meaning accesses that are
|
|||
However, it does so by performing two separate word-aligned accesses.
|
||||
This means that at least two cycles are needed for misaligned loads and stores.
|
||||
|
||||
If an error response is received for the first transaction, the second transaction will still be issued.
|
||||
The second transaction will then follow the normal bus protocol, but its response/data will be ignored.
|
||||
If a new load/store request is received while waiting for an abandoned second part to complete, it will not be serviced until the state machine returns to IDLE.
|
||||
|
||||
.. _lsu-protocol:
|
||||
|
||||
Protocol
|
||||
|
@ -61,6 +65,8 @@ The protocol that is used by the LSU to communicate with a memory works as follo
|
|||
|
||||
3. The memory answers with a ``data_rvalid_i`` set high for exactly one cycle to signal the response from the bus or the memory using ``data_err_i`` and ``data_rdata_i`` (during the very same cycle). This may happen one or more cycles after the grant has been received. If ``data_err_i`` is low, the request could successfully be handled at the destination and in the case of a load, ``data_rdata_i`` contains valid data. If ``data_err_i`` is high, an error occurred in the memory system and the core will raise an exception.
|
||||
|
||||
4. When multiple granted requests are outstanding, it is assumed that the memory requests will be kept in-order and one ``data_rvalid_i`` will be signalled for each of them, in the order they were issued.
|
||||
|
||||
:numref:`timing1`, :numref:`timing2` and :numref:`timing3` show example-timing diagrams of the protocol.
|
||||
|
||||
.. wavedrom::
|
||||
|
|
|
@ -76,11 +76,13 @@ module ibex_load_store_unit (
|
|||
logic split_misaligned_access;
|
||||
logic handle_misaligned_q, handle_misaligned_d; // high after receiving grant for first
|
||||
// part of a misaligned access
|
||||
logic pmp_err_d;
|
||||
logic pmp_err_q;
|
||||
logic data_or_pmp_err;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID
|
||||
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID,
|
||||
WAIT_GNT_ERR, WAIT_RVALID_ERR, WAIT_RVALID_DONE
|
||||
} ls_fsm_e;
|
||||
|
||||
ls_fsm_e ls_fsm_cs, ls_fsm_ns;
|
||||
|
@ -321,12 +323,14 @@ module ibex_load_store_unit (
|
|||
addr_incr_req_o = 1'b0;
|
||||
handle_misaligned_d = handle_misaligned_q;
|
||||
data_or_pmp_err = 1'b0;
|
||||
pmp_err_d = pmp_err_q;
|
||||
|
||||
unique case (ls_fsm_cs)
|
||||
|
||||
IDLE: begin
|
||||
if (data_req_ex_i) begin
|
||||
data_req_o = 1'b1;
|
||||
pmp_err_d = data_pmp_err_i;
|
||||
if (data_gnt_i) begin
|
||||
handle_misaligned_d = split_misaligned_access;
|
||||
ls_fsm_ns = split_misaligned_access ? WAIT_RVALID_MIS : WAIT_RVALID;
|
||||
|
@ -338,6 +342,10 @@ module ibex_load_store_unit (
|
|||
|
||||
WAIT_GNT_MIS: begin
|
||||
data_req_o = 1'b1;
|
||||
// data_pmp_err_i is valid during the address phase of a request. An error will block the
|
||||
// external request and so a data_gnt_i might never be signalled. The registered version
|
||||
// pmp_err_q is only updated for new address phases and so can be used in WAIT_GNT* and
|
||||
// WAIT_RVALID* states
|
||||
if (data_gnt_i || pmp_err_q) begin
|
||||
handle_misaligned_d = 1'b1;
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
|
@ -345,32 +353,34 @@ module ibex_load_store_unit (
|
|||
end
|
||||
|
||||
WAIT_RVALID_MIS: begin
|
||||
// push out second request
|
||||
data_req_o = 1'b1;
|
||||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = 1'b1;
|
||||
// first part rvalid is received, or gets a pmp error
|
||||
// pmp_err_i will hold stable until the address is updated, and
|
||||
// therefore pmp_err_q is valid in both WAIT_GNT_MIS and WAIT_RVALID_MIS states
|
||||
|
||||
// first part rvalid is received, or gets a PMP error
|
||||
if (data_rvalid_i || pmp_err_q) begin
|
||||
// Update the PMP error for the second part
|
||||
pmp_err_d = data_pmp_err_i;
|
||||
if (pmp_err_q || data_err_i) begin
|
||||
// first part created an error, abort transaction
|
||||
data_valid_o = 1'b1;
|
||||
data_or_pmp_err = 1'b1;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = IDLE;
|
||||
// If already granted, wait for second rvalid
|
||||
ls_fsm_ns = data_gnt_i ? WAIT_RVALID_ERR : WAIT_GNT_ERR;
|
||||
|
||||
end else begin
|
||||
// push out second request
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
// second grant is received
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end else begin
|
||||
// second grant is NOT received, but first rvalid
|
||||
ls_fsm_ns = WAIT_GNT;
|
||||
end
|
||||
// No error in first part, proceed with second part
|
||||
ls_fsm_ns = data_gnt_i ? WAIT_RVALID : WAIT_GNT;
|
||||
end
|
||||
|
||||
end else begin
|
||||
// first part rvalid is NOT received
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
if (data_gnt_i) begin
|
||||
// second grant is received
|
||||
ls_fsm_ns = WAIT_RVALID_DONE;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -385,8 +395,6 @@ module ibex_load_store_unit (
|
|||
|
||||
WAIT_RVALID: begin
|
||||
data_req_o = 1'b0;
|
||||
// pmp_err_i will hold stable until the address is updated, and
|
||||
// therefore pmp_err_q is valid in both WAIT_GNT and WAIT_RVALID states
|
||||
if (data_rvalid_i || pmp_err_q) begin
|
||||
data_valid_o = 1'b1;
|
||||
data_or_pmp_err = data_err_i | pmp_err_q;
|
||||
|
@ -397,6 +405,44 @@ module ibex_load_store_unit (
|
|||
end
|
||||
end
|
||||
|
||||
WAIT_GNT_ERR: begin
|
||||
// Wait for the grant of the abandoned second access
|
||||
data_req_o = 1'b1;
|
||||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = 1'b1;
|
||||
if (pmp_err_q) begin
|
||||
// The second part was suppressed by a PMP error
|
||||
ls_fsm_ns = IDLE;
|
||||
end else if (data_gnt_i) begin
|
||||
ls_fsm_ns = WAIT_RVALID_ERR;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_RVALID_ERR: begin
|
||||
// Wait for the rvalid, but do nothing with it
|
||||
if (data_rvalid_i || pmp_err_q) begin
|
||||
ls_fsm_ns = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_RVALID_DONE: begin
|
||||
// Wait for the first rvalid, second request is already granted
|
||||
if (data_rvalid_i) begin
|
||||
// Update the pmp error for the second part
|
||||
pmp_err_d = data_pmp_err_i;
|
||||
// The first part cannot see a PMP error in this state
|
||||
if (data_err_i) begin
|
||||
// first part created an error, abort transaction and wait for second rvalid
|
||||
data_valid_o = 1'b1;
|
||||
data_or_pmp_err = 1'b1;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = WAIT_RVALID_ERR;
|
||||
end else begin
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
ls_fsm_ns = ls_fsm_e'(1'bX);
|
||||
end
|
||||
|
@ -424,7 +470,7 @@ module ibex_load_store_unit (
|
|||
ls_fsm_cs <= ls_fsm_ns;
|
||||
addr_last_q <= addr_last_d;
|
||||
handle_misaligned_q <= handle_misaligned_d;
|
||||
pmp_err_q <= data_pmp_err_i;
|
||||
pmp_err_q <= pmp_err_d;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -451,7 +497,7 @@ module ibex_load_store_unit (
|
|||
assign load_err_o = data_or_pmp_err & ~data_we_q;
|
||||
assign store_err_o = data_or_pmp_err & data_we_q;
|
||||
|
||||
assign busy_o = (ls_fsm_cs == WAIT_RVALID) | (data_req_o == 1'b1);
|
||||
assign busy_o = (ls_fsm_cs != IDLE);
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue