mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 12:17:19 -04:00
amoadd.d riscv tests passing
This commit is contained in:
parent
3b75716a59
commit
e3c446e40d
13 changed files with 288 additions and 173 deletions
|
@ -77,7 +77,7 @@ Coming.
|
|||
|
||||
## Planned Improvements
|
||||
|
||||
While developing Ariane it has become evident that, in order to support Linux, the atomic extension is going to be mandatory. While the core is currently booting Linux by emulating Atomics in BBL (in a single core environment this is trivially met by disabling interrupts) this is not the behavior which is intended. For that reason we are going to fully support all atomic extensions in the very near future.
|
||||
> Atomics are implemented for a single core environment. They will fail in a multi-core setup
|
||||
|
||||
## Going Beyond
|
||||
|
||||
|
|
|
@ -191,49 +191,9 @@ package ariane_pkg;
|
|||
DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW
|
||||
} fu_op;
|
||||
|
||||
// ----------------------
|
||||
// Extract Bytes from Op
|
||||
// ----------------------
|
||||
function automatic logic [1:0] extract_transfer_size (fu_op op);
|
||||
case (op)
|
||||
LD, SD,
|
||||
AMO_LRD, AMO_SCD,
|
||||
AMO_SWAPD, AMO_ADDD,
|
||||
AMO_ANDD, AMO_ORD,
|
||||
AMO_XORD, AMO_MAXD,
|
||||
AMO_MAXDU, AMO_MIND,
|
||||
AMO_MINDU: begin
|
||||
return 2'b11;
|
||||
end
|
||||
LW, LWU, SW,
|
||||
AMO_LRW, AMO_SCW,
|
||||
AMO_SWAPW, AMO_ADDW,
|
||||
AMO_ANDW, AMO_ORW,
|
||||
AMO_XORW, AMO_MAXW,
|
||||
AMO_MAXWU, AMO_MINW,
|
||||
AMO_MINWU: begin
|
||||
return 2'b10;
|
||||
end
|
||||
LH, LHU, SH: return 2'b01;
|
||||
LB, SB, LBU: return 2'b00;
|
||||
default: return 2'b11;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function automatic logic is_amo (fu_op op);
|
||||
case (op)
|
||||
AMO_LRD, AMO_SCD,
|
||||
AMO_SWAPD, AMO_ADDD,
|
||||
AMO_ANDD, AMO_ORD,
|
||||
AMO_XORD, AMO_MAXD,
|
||||
AMO_MAXDU, AMO_MIND,
|
||||
AMO_MINDU,
|
||||
AMO_LRW, AMO_SCW,
|
||||
AMO_SWAPW, AMO_ADDW,
|
||||
AMO_ANDW, AMO_ORW,
|
||||
AMO_XORW, AMO_MAXW,
|
||||
AMO_MAXWU, AMO_MINW,
|
||||
AMO_MINWU: begin
|
||||
case (op) inside
|
||||
[AMO_LRW:AMO_MINDU]: begin
|
||||
return 1'b1;
|
||||
end
|
||||
default: return 1'b0;
|
||||
|
@ -397,4 +357,92 @@ package ariane_pkg;
|
|||
return { {51 {instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 };
|
||||
endfunction
|
||||
|
||||
// ----------------------
|
||||
// LSU Functions
|
||||
// ----------------------
|
||||
// align data to address e.g.: shift data to be naturally 64
|
||||
function automatic logic [63:0] data_align (logic [2:0] addr, logic [63:0] data);
|
||||
case (addr)
|
||||
3'b000: return data;
|
||||
3'b001: return {data[55:0], data[63:56]};
|
||||
3'b010: return {data[47:0], data[63:48]};
|
||||
3'b011: return {data[39:0], data[63:40]};
|
||||
3'b100: return {data[31:0], data[63:32]};
|
||||
3'b101: return {data[23:0], data[63:24]};
|
||||
3'b110: return {data[15:0], data[63:16]};
|
||||
3'b111: return {data[7:0], data[63:8]};
|
||||
endcase
|
||||
return data;
|
||||
endfunction
|
||||
|
||||
// generate byte enable mask
|
||||
function automatic logic [7:0] be_gen(logic [2:0] addr, logic [1:0] size);
|
||||
case (size)
|
||||
2'b11: begin
|
||||
return 8'b1111_1111;
|
||||
end
|
||||
2'b10: begin
|
||||
case (addr[2:0])
|
||||
3'b000: return 8'b0000_1111;
|
||||
3'b001: return 8'b0001_1110;
|
||||
3'b010: return 8'b0011_1100;
|
||||
3'b011: return 8'b0111_1000;
|
||||
3'b100: return 8'b1111_0000;
|
||||
endcase
|
||||
end
|
||||
2'b01: begin
|
||||
case (addr[2:0])
|
||||
3'b000: return 8'b0000_0011;
|
||||
3'b001: return 8'b0000_0110;
|
||||
3'b010: return 8'b0000_1100;
|
||||
3'b011: return 8'b0001_1000;
|
||||
3'b100: return 8'b0011_0000;
|
||||
3'b101: return 8'b0110_0000;
|
||||
3'b110: return 8'b1100_0000;
|
||||
endcase
|
||||
end
|
||||
2'b00: begin
|
||||
case (addr[2:0])
|
||||
3'b000: return 8'b0000_0001;
|
||||
3'b001: return 8'b0000_0010;
|
||||
3'b010: return 8'b0000_0100;
|
||||
3'b011: return 8'b0000_1000;
|
||||
3'b100: return 8'b0001_0000;
|
||||
3'b101: return 8'b0010_0000;
|
||||
3'b110: return 8'b0100_0000;
|
||||
3'b111: return 8'b1000_0000;
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
return 8'b0;
|
||||
endfunction
|
||||
|
||||
// ----------------------
|
||||
// Extract Bytes from Op
|
||||
// ----------------------
|
||||
function automatic logic [1:0] extract_transfer_size(fu_op op);
|
||||
case (op)
|
||||
LD, SD,
|
||||
AMO_LRD, AMO_SCD,
|
||||
AMO_SWAPD, AMO_ADDD,
|
||||
AMO_ANDD, AMO_ORD,
|
||||
AMO_XORD, AMO_MAXD,
|
||||
AMO_MAXDU, AMO_MIND,
|
||||
AMO_MINDU: begin
|
||||
return 2'b11;
|
||||
end
|
||||
LW, LWU, SW,
|
||||
AMO_LRW, AMO_SCW,
|
||||
AMO_SWAPW, AMO_ADDW,
|
||||
AMO_ANDW, AMO_ORW,
|
||||
AMO_XORW, AMO_MAXW,
|
||||
AMO_MAXWU, AMO_MINW,
|
||||
AMO_MINWU: begin
|
||||
return 2'b10;
|
||||
end
|
||||
LH, LHU, SH: return 2'b01;
|
||||
LB, SB, LBU: return 2'b00;
|
||||
default: return 2'b11;
|
||||
endcase
|
||||
endfunction
|
||||
endpackage
|
||||
|
|
|
@ -192,6 +192,7 @@ module ariane #(
|
|||
logic dcache_flush_ctrl_cache;
|
||||
logic dcache_flush_ack_cache_ctrl;
|
||||
logic set_debug_pc;
|
||||
logic flush_commit;
|
||||
|
||||
icache_areq_i_t icache_areq_ex_cache;
|
||||
icache_areq_o_t icache_areq_cache_ex;
|
||||
|
@ -422,6 +423,7 @@ module ariane #(
|
|||
.fence_i_o ( fence_i_commit_controller ),
|
||||
.fence_o ( fence_commit_controller ),
|
||||
.sfence_vma_o ( sfence_vma_commit_controller ),
|
||||
.flush_commit_o ( flush_commit ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
@ -519,6 +521,7 @@ module ariane #(
|
|||
.fence_i_i ( fence_i_commit_controller ),
|
||||
.fence_i ( fence_commit_controller ),
|
||||
.sfence_vma_i ( sfence_vma_commit_controller ),
|
||||
.flush_commit_i ( flush_commit ),
|
||||
|
||||
.flush_icache_o ( icache_flush_ctrl_cache ),
|
||||
.*
|
||||
|
|
|
@ -18,10 +18,10 @@ import std_cache_pkg::*;
|
|||
|
||||
|
||||
module axi_adapter #(
|
||||
parameter int unsigned DATA_WIDTH = 256,
|
||||
parameter logic CRITICAL_WORD_FIRST = 0, // the AXI subsystem needs to support wrapping reads for this feature
|
||||
parameter int unsigned AXI_ID_WIDTH = 10
|
||||
)(
|
||||
parameter int unsigned DATA_WIDTH = 256,
|
||||
parameter logic CRITICAL_WORD_FIRST = 0, // the AXI subsystem needs to support wrapping reads for this feature
|
||||
parameter int unsigned AXI_ID_WIDTH = 10
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
|
@ -202,9 +202,13 @@ module axi_adapter #(
|
|||
|
||||
axi.w_valid = 1'b1;
|
||||
axi.w_last = (cnt_q == '0) ? 1'b1 : 1'b0;
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
|
||||
if (type_i == SINGLE_REQ) begin
|
||||
axi.w_data = wdata_i[0];
|
||||
axi.w_strb = be_i[0];
|
||||
end else begin
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
end
|
||||
axi.aw_valid = 1'b1;
|
||||
// we are here because we want to write a cache line
|
||||
axi.aw_len = BURST_SIZE;
|
||||
|
@ -251,8 +255,13 @@ module axi_adapter #(
|
|||
// ~> from write, there is an outstanding write
|
||||
WAIT_LAST_W_READY: begin
|
||||
axi.w_valid = 1'b1;
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
if (type_i == SINGLE_REQ) begin
|
||||
axi.w_data = wdata_i[0];
|
||||
axi.w_strb = be_i[0];
|
||||
end else begin
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
end
|
||||
|
||||
// this is the last write
|
||||
axi.w_last = (cnt_q == '0) ? 1'b1 : 1'b0;
|
||||
|
|
|
@ -23,6 +23,9 @@ module amo_alu (
|
|||
always_comb begin
|
||||
amo_result_o = '0;
|
||||
case (amo_op)
|
||||
ariane_pkg::AMO_SC: begin
|
||||
amo_result_o = amo_operand_b;
|
||||
end
|
||||
ariane_pkg::AMO_SWAP: begin
|
||||
amo_result_o = amo_operand_b;
|
||||
end
|
||||
|
@ -33,7 +36,7 @@ module amo_alu (
|
|||
amo_result_o = amo_operand_a & amo_operand_b;
|
||||
end
|
||||
ariane_pkg::AMO_OR: begin
|
||||
amo_result_o = amo_operand_a & amo_operand_b;
|
||||
amo_result_o = amo_operand_a | amo_operand_b;
|
||||
end
|
||||
ariane_pkg::AMO_XOR: begin
|
||||
amo_result_o = amo_operand_a ^ amo_operand_b;
|
||||
|
|
|
@ -47,6 +47,9 @@ module miss_handler #(
|
|||
input logic [NR_PORTS-1:0][55:0] mshr_addr_i,
|
||||
output logic [NR_PORTS-1:0] mshr_addr_matches_o,
|
||||
output logic [NR_PORTS-1:0] mshr_index_matches_o,
|
||||
// AMO
|
||||
input amo_req_t amo_req_i,
|
||||
output amo_resp_t amo_resp_o,
|
||||
// Port to SRAMs, for refill and eviction
|
||||
output logic [DCACHE_SET_ASSOC-1:0] req_o,
|
||||
output logic [DCACHE_INDEX_WIDTH-1:0] addr_o, // address into cache array
|
||||
|
@ -56,22 +59,25 @@ module miss_handler #(
|
|||
output logic we_o
|
||||
);
|
||||
|
||||
// 0 IDLE
|
||||
// 1 FLUSHING
|
||||
// 2 FLUSH
|
||||
// 3 WB_CACHELINE_FLUSH
|
||||
// 4 FLUSH_REQ_STATUS
|
||||
// 5 WB_CACHELINE_MISS
|
||||
// 6 WAIT_GNT_SRAM
|
||||
// 7 MISS
|
||||
// 8 REQ_CACHELINE
|
||||
// 9 MISS_REPL
|
||||
// A SAVE_CACHELINE
|
||||
// B INIT
|
||||
|
||||
// FSM states
|
||||
enum logic [3:0] { IDLE, FLUSHING, FLUSH, WB_CACHELINE_FLUSH, FLUSH_REQ_STATUS, WB_CACHELINE_MISS, WAIT_GNT_SRAM, MISS,
|
||||
REQ_CACHELINE, MISS_REPL, SAVE_CACHELINE, INIT } state_d, state_q;
|
||||
enum logic [3:0] {
|
||||
IDLE, // 0
|
||||
FLUSHING, // 1
|
||||
FLUSH, // 2
|
||||
WB_CACHELINE_FLUSH, // 3
|
||||
FLUSH_REQ_STATUS, // 4
|
||||
WB_CACHELINE_MISS, // 5
|
||||
WAIT_GNT_SRAM, // 6
|
||||
MISS, // 7
|
||||
REQ_CACHELINE, // 8
|
||||
MISS_REPL, // 9
|
||||
SAVE_CACHELINE, // A
|
||||
INIT, // B
|
||||
AMO_LOAD, // C
|
||||
AMO_SAVE_LOAD, // D
|
||||
AMO_STORE // E
|
||||
} state_d, state_q;
|
||||
|
||||
// Registers
|
||||
mshr_t mshr_d, mshr_q;
|
||||
logic [DCACHE_INDEX_WIDTH-1:0] cnt_d, cnt_q;
|
||||
|
@ -79,6 +85,7 @@ module miss_handler #(
|
|||
// cache line to evict
|
||||
cache_line_t evict_cl_d, evict_cl_q;
|
||||
|
||||
logic serve_amo_d, serve_amo_q;
|
||||
// Request from one FSM
|
||||
logic [NR_PORTS-1:0] miss_req_valid;
|
||||
logic [NR_PORTS-1:0] miss_req_bypass;
|
||||
|
@ -90,11 +97,13 @@ module miss_handler #(
|
|||
|
||||
// Cache Line Refill <-> AXI
|
||||
logic req_fsm_miss_valid;
|
||||
logic req_fsm_miss_bypass;
|
||||
logic [63:0] req_fsm_miss_addr;
|
||||
logic [DCACHE_LINE_WIDTH-1:0] req_fsm_miss_wdata;
|
||||
logic req_fsm_miss_we;
|
||||
logic [(DCACHE_LINE_WIDTH/8)-1:0] req_fsm_miss_be;
|
||||
req_t req_fsm_miss_req;
|
||||
logic [1:0] req_fsm_miss_size;
|
||||
|
||||
logic gnt_miss_fsm;
|
||||
logic valid_miss_fsm;
|
||||
logic [(DCACHE_LINE_WIDTH/64)-1:0][63:0] data_miss_fsm;
|
||||
|
@ -103,6 +112,10 @@ module miss_handler #(
|
|||
logic lfsr_enable;
|
||||
logic [DCACHE_SET_ASSOC-1:0] lfsr_oh;
|
||||
logic [$clog2(DCACHE_SET_ASSOC-1)-1:0] lfsr_bin;
|
||||
// AMOs
|
||||
ariane_pkg::amo_t amo_op;
|
||||
logic [63:0] amo_operand_a, amo_operand_b, amo_result_o;
|
||||
logic [63:0] amo_operand_a_sext32;
|
||||
|
||||
// ------------------------------
|
||||
// Cache Management
|
||||
|
@ -129,14 +142,16 @@ module miss_handler #(
|
|||
lfsr_enable = 1'b0;
|
||||
// to AXI refill
|
||||
req_fsm_miss_valid = 1'b0;
|
||||
req_fsm_miss_bypass = 1'b0;
|
||||
req_fsm_miss_addr = '0;
|
||||
req_fsm_miss_wdata = '0;
|
||||
req_fsm_miss_we = 1'b0;
|
||||
req_fsm_miss_be = '0;
|
||||
req_fsm_miss_req = CACHE_LINE_REQ;
|
||||
req_fsm_miss_size = 2'b11;
|
||||
// core
|
||||
flush_ack_o = 1'b0;
|
||||
miss_o = 1'b0; // to performance counter
|
||||
serve_amo_d = serve_amo_q;
|
||||
// --------------------------------
|
||||
// Flush and Miss operation
|
||||
// --------------------------------
|
||||
|
@ -148,11 +163,30 @@ module miss_handler #(
|
|||
// communicate to the requester which unit we are currently serving
|
||||
active_serving_o = '0;
|
||||
active_serving_o[mshr_q.id] = mshr_q.valid;
|
||||
// AMOs
|
||||
amo_resp_o.ack = 1'b0;
|
||||
amo_resp_o.result = '0;
|
||||
// silence the unit when not used
|
||||
amo_op = amo_req_i.amo_op;
|
||||
amo_operand_a = '0;
|
||||
amo_operand_b = '0;
|
||||
amo_operand_a_sext32 = '0;
|
||||
|
||||
case (state_q)
|
||||
|
||||
IDLE: begin
|
||||
|
||||
// lowest priority are AMOs, wait until everything else is served before going for the AMOs
|
||||
if (amo_req_i.req) begin
|
||||
// 1. Flush the cache
|
||||
if (!serve_amo_q) begin
|
||||
state_d = FLUSH_REQ_STATUS;
|
||||
serve_amo_d = 1'b1;
|
||||
// 2. Do the AMO
|
||||
end else begin
|
||||
state_d = AMO_LOAD;
|
||||
serve_amo_d = 1'b0;
|
||||
end
|
||||
end
|
||||
// check if we want to flush and can flush e.g.: we are not busy anymore
|
||||
// TODO: Check that the busy flag is indeed needed
|
||||
if (flush_i && !busy_i) begin
|
||||
|
@ -330,6 +364,63 @@ module miss_handler #(
|
|||
if (cnt_q[DCACHE_INDEX_WIDTH-1:DCACHE_BYTE_OFFSET] == DCACHE_NUM_WORDS-1)
|
||||
state_d = IDLE;
|
||||
end
|
||||
// ----------------------
|
||||
// AMOs
|
||||
// ----------------------
|
||||
// TODO(zarubaf) Move this closer to memory
|
||||
// ~> we are here because we need to do the AMO, the cache is clean at this point
|
||||
// start by executing the load
|
||||
AMO_LOAD: begin
|
||||
req_fsm_miss_valid = 1'b1;
|
||||
// address is in operand a
|
||||
req_fsm_miss_addr = amo_req_i.operand_a;
|
||||
req_fsm_miss_req = SINGLE_REQ;
|
||||
req_fsm_miss_size = amo_req_i.size;
|
||||
// the request has been granted
|
||||
if (gnt_miss_fsm) begin
|
||||
state_d = AMO_SAVE_LOAD;
|
||||
end
|
||||
end
|
||||
// save the load value
|
||||
AMO_SAVE_LOAD: begin
|
||||
if (valid_miss_fsm) begin
|
||||
// we are only concerned about the lower 64-bit
|
||||
mshr_d.wdata = data_miss_fsm[0];
|
||||
state_d = AMO_STORE;
|
||||
end
|
||||
end
|
||||
// and do the store
|
||||
AMO_STORE: begin
|
||||
automatic logic [63:0] load_data;
|
||||
// re-align load data
|
||||
load_data = data_align(amo_req_i.operand_a[2:0], mshr_q.wdata);
|
||||
// Sign-extend for word operation
|
||||
if (amo_req_i.size == 2'b10) begin
|
||||
amo_operand_a = sext32(load_data[31:0]);
|
||||
end else begin
|
||||
amo_operand_a = load_data;
|
||||
end
|
||||
|
||||
amo_operand_b = amo_req_i.operand_b;
|
||||
// we do not need a store request for load reserved
|
||||
req_fsm_miss_valid = (amo_req_i.amo_op == AMO_LR) ? 1'b0 : 1'b1;
|
||||
// for a load reserved we do not want to write
|
||||
req_fsm_miss_we = (amo_req_i.amo_op == AMO_LR) ? 1'b0 : 1'b1;
|
||||
req_fsm_miss_req = SINGLE_REQ;
|
||||
req_fsm_miss_size = amo_req_i.size;
|
||||
req_fsm_miss_addr = amo_req_i.operand_a;
|
||||
|
||||
req_fsm_miss_wdata = data_align(amo_req_i.operand_a[2:0], amo_result_o);
|
||||
req_fsm_miss_be = be_gen(amo_req_i.operand_a[2:0], amo_req_i.size);
|
||||
|
||||
// the request is valid or we didn't need to go for another store
|
||||
if (valid_miss_fsm || (amo_req_i.amo_op == AMO_LR)) begin
|
||||
state_d = IDLE;
|
||||
amo_resp_o.ack = 1'b1;
|
||||
// write-back the result -> SC will always succeed in the current setting
|
||||
amo_resp_o.result = (amo_req_i.amo_op == AMO_SC) ? 1'b1 : amo_operand_a;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -361,12 +452,14 @@ module miss_handler #(
|
|||
cnt_q <= '0;
|
||||
evict_way_q <= '0;
|
||||
evict_cl_q <= '0;
|
||||
serve_amo_q <= 1'b0;
|
||||
end else begin
|
||||
mshr_q <= mshr_d;
|
||||
state_q <= state_d;
|
||||
cnt_q <= cnt_d;
|
||||
evict_way_q <= evict_way_d;
|
||||
evict_cl_q <= evict_cl_d;
|
||||
serve_amo_q <= serve_amo_d;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -448,20 +541,20 @@ module miss_handler #(
|
|||
);
|
||||
|
||||
// ----------------------
|
||||
// Cache Line Arbiter
|
||||
// Cache Line AXI Refill
|
||||
// ----------------------
|
||||
axi_adapter #(
|
||||
.DATA_WIDTH ( DCACHE_LINE_WIDTH ),
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
|
||||
) i_miss_axi_adapter (
|
||||
.req_i ( req_fsm_miss_valid ),
|
||||
.type_i ( CACHE_LINE_REQ ),
|
||||
.type_i ( req_fsm_miss_req ),
|
||||
.gnt_o ( gnt_miss_fsm ),
|
||||
.addr_i ( req_fsm_miss_addr ),
|
||||
.we_i ( req_fsm_miss_we ),
|
||||
.wdata_i ( req_fsm_miss_wdata ),
|
||||
.be_i ( req_fsm_miss_be ),
|
||||
.size_i ( 2'b11 ),
|
||||
.size_i ( req_fsm_miss_size ),
|
||||
.id_i ( '0 ),
|
||||
.gnt_id_o ( ), // open
|
||||
.valid_o ( valid_miss_fsm ),
|
||||
|
@ -481,6 +574,16 @@ module miss_handler #(
|
|||
.*
|
||||
);
|
||||
|
||||
// -----------------
|
||||
// AMO ALU
|
||||
// -----------------
|
||||
amo_alu i_amo_alu (
|
||||
.amo_op ( amo_op ),
|
||||
.amo_operand_a ( amo_operand_a ),
|
||||
.amo_operand_b ( amo_operand_b ),
|
||||
.amo_result_o ( amo_result_o )
|
||||
);
|
||||
|
||||
// -----------------
|
||||
// Struct Split
|
||||
// -----------------
|
||||
|
|
|
@ -36,8 +36,6 @@ module std_nbdcache #(
|
|||
AXI_BUS.Master bypass_if
|
||||
);
|
||||
|
||||
assign amo_resp_o = '0;
|
||||
|
||||
// -------------------------------
|
||||
// Controller <-> Arbiter
|
||||
// -------------------------------
|
||||
|
@ -131,6 +129,9 @@ module std_nbdcache #(
|
|||
) i_miss_handler (
|
||||
.flush_i ( flush_i ),
|
||||
.busy_i ( |busy ),
|
||||
// AMOs
|
||||
.amo_req_i ( amo_req_i ),
|
||||
.amo_resp_o ( amo_resp_o ),
|
||||
.miss_req_i ( miss_req ),
|
||||
.miss_gnt_o ( miss_gnt ),
|
||||
.bypass_gnt_o ( bypass_gnt ),
|
||||
|
|
|
@ -28,7 +28,6 @@ module commit_stage #(
|
|||
// from scoreboard
|
||||
input scoreboard_entry_t [NR_COMMIT_PORTS-1:0] commit_instr_i, // the instruction we want to commit
|
||||
output logic [NR_COMMIT_PORTS-1:0] commit_ack_o, // acknowledge that we are indeed committing
|
||||
|
||||
// to register file
|
||||
output logic [NR_COMMIT_PORTS-1:0][4:0] waddr_o, // register file write address
|
||||
output logic [NR_COMMIT_PORTS-1:0][63:0] wdata_o, // register file write data
|
||||
|
@ -50,6 +49,7 @@ module commit_stage #(
|
|||
output logic commit_csr_o, // commit the pending CSR instruction
|
||||
output logic fence_i_o, // flush I$ and pipeline
|
||||
output logic fence_o, // flush D$ and pipeline
|
||||
output logic flush_commit_o, // request a pipeline flush
|
||||
output logic sfence_vma_o // flush TLBs and pipeline
|
||||
);
|
||||
|
||||
|
@ -58,6 +58,8 @@ module commit_stage #(
|
|||
|
||||
assign pc_o = commit_instr_i[0].pc;
|
||||
|
||||
logic instr_0_is_amo;
|
||||
assign instr_0_is_amo = is_amo(commit_instr_i[0].op);
|
||||
// -------------------
|
||||
// Commit Instruction
|
||||
// -------------------
|
||||
|
@ -82,6 +84,7 @@ module commit_stage #(
|
|||
fence_i_o = 1'b0;
|
||||
fence_o = 1'b0;
|
||||
sfence_vma_o = 1'b0;
|
||||
flush_commit_o = 1'b0;
|
||||
|
||||
// we will not commit the instruction if we took an exception
|
||||
// and we do not commit the instruction if we requested a halt
|
||||
|
@ -103,7 +106,7 @@ module commit_stage #(
|
|||
// check whether the instruction we retire was a store
|
||||
// do not commit the instruction if we got an exception since the store buffer will be cleared
|
||||
// by the subsequent flush triggered by an exception
|
||||
if (commit_instr_i[0].fu == STORE) begin
|
||||
if (commit_instr_i[0].fu == STORE && !instr_0_is_amo) begin
|
||||
// check if the LSU is ready to accept another commit entry (e.g.: a non-speculative store)
|
||||
if (commit_lsu_ready_i)
|
||||
commit_lsu_o = 1'b1;
|
||||
|
@ -154,10 +157,12 @@ module commit_stage #(
|
|||
// ------------------
|
||||
// AMO
|
||||
// ------------------
|
||||
if (is_amo(commit_instr_i[0].op)) begin
|
||||
// TODO(zarubaf): Flush pipeline
|
||||
amo_valid_commit_o = 1'b1;
|
||||
if (instr_0_is_amo) begin
|
||||
// AMO finished
|
||||
commit_ack_o[0] = amo_resp_i.ack;
|
||||
// flush the pipeline
|
||||
flush_commit_o = amo_resp_i.ack;
|
||||
amo_valid_commit_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -170,6 +175,7 @@ module commit_stage #(
|
|||
&& !halt_i
|
||||
&& !(commit_instr_i[0].fu inside {CSR})
|
||||
&& !flush_dcache_i
|
||||
&& !instr_0_is_amo
|
||||
&& !single_step_i) begin
|
||||
// only if the first instruction didn't throw an exception and this instruction won't throw an exception
|
||||
// and the operator is of type ALU, LOAD, CTRL_FLOW, MULT
|
||||
|
|
|
@ -36,7 +36,8 @@ module controller (
|
|||
input logic flush_csr_i, // We got an instruction which altered the CSR, flush the pipeline
|
||||
input logic fence_i_i, // fence.i in
|
||||
input logic fence_i, // fence in
|
||||
input logic sfence_vma_i // We got an instruction to flush the TLBs and pipeline
|
||||
input logic sfence_vma_i, // We got an instruction to flush the TLBs and pipeline
|
||||
input logic flush_commit_i // Flush request from commit stage
|
||||
);
|
||||
|
||||
// active fence - high if we are currently flushing the dcache
|
||||
|
@ -118,10 +119,8 @@ module controller (
|
|||
flush_tlb_o = 1'b1;
|
||||
end
|
||||
|
||||
// ---------------------------------
|
||||
// CSR instruction with side-effect
|
||||
// ---------------------------------
|
||||
if (flush_csr_i) begin
|
||||
// Set PC to commit stage and flush pipleine
|
||||
if (flush_csr_i || flush_commit_i) begin
|
||||
set_pc_commit_o = 1'b1;
|
||||
flush_if_o = 1'b1;
|
||||
flush_unissued_instr_o = 1'b1;
|
||||
|
|
|
@ -352,8 +352,8 @@ module frontend (
|
|||
// On a pipeline flush start fetching from the next address
|
||||
// of the instruction in the commit stage
|
||||
if (set_pc_commit_i) begin
|
||||
// we came here from a flush request of a CSR instruction,
|
||||
// as CSR instructions do not exist in a compressed form
|
||||
// we came here from a flush request of a CSR instruction or AMO,
|
||||
// as CSR or AMO instructions do not exist in a compressed form
|
||||
// we can unconditionally do PC + 4 here
|
||||
// TODO(zarubaf) This adder can at least be merged with the one in the csr_regfile stage
|
||||
npc_d = pc_commit_i + 64'h4;
|
||||
|
|
52
src/lsu.sv
52
src/lsu.sv
|
@ -256,54 +256,10 @@ module lsu #(
|
|||
// ---------------
|
||||
// Byte Enable
|
||||
// ---------------
|
||||
always_comb begin : byte_enable
|
||||
be_i = 8'b0;
|
||||
// we can generate the byte enable from the virtual address since the last
|
||||
// 12 bit are the same anyway
|
||||
// and we can always generate the byte enable from the address at hand
|
||||
case (operator_i)
|
||||
LD, SD: begin // double word
|
||||
be_i = 8'b1111_1111;
|
||||
end
|
||||
LW, LWU, SW: begin// word
|
||||
case (vaddr_i[2:0])
|
||||
3'b000: be_i = 8'b0000_1111;
|
||||
3'b001: be_i = 8'b0001_1110;
|
||||
3'b010: be_i = 8'b0011_1100;
|
||||
3'b011: be_i = 8'b0111_1000;
|
||||
3'b100: be_i = 8'b1111_0000;
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
LH, LHU, SH: begin // half word
|
||||
case (vaddr_i[2:0])
|
||||
3'b000: be_i = 8'b0000_0011;
|
||||
3'b001: be_i = 8'b0000_0110;
|
||||
3'b010: be_i = 8'b0000_1100;
|
||||
3'b011: be_i = 8'b0001_1000;
|
||||
3'b100: be_i = 8'b0011_0000;
|
||||
3'b101: be_i = 8'b0110_0000;
|
||||
3'b110: be_i = 8'b1100_0000;
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
LB, LBU, SB: begin // byte
|
||||
case (vaddr_i[2:0])
|
||||
3'b000: be_i = 8'b0000_0001;
|
||||
3'b001: be_i = 8'b0000_0010;
|
||||
3'b010: be_i = 8'b0000_0100;
|
||||
3'b011: be_i = 8'b0000_1000;
|
||||
3'b100: be_i = 8'b0001_0000;
|
||||
3'b101: be_i = 8'b0010_0000;
|
||||
3'b110: be_i = 8'b0100_0000;
|
||||
3'b111: be_i = 8'b1000_0000;
|
||||
endcase
|
||||
end
|
||||
default: begin
|
||||
be_i = 8'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
// we can generate the byte enable from the virtual address since the last
|
||||
// 12 bit are the same anyway
|
||||
// and we can always generate the byte enable from the address at hand
|
||||
assign be_i = be_gen(vaddr_i[2:0], extract_transfer_size(operator_i));
|
||||
|
||||
// ------------------------
|
||||
// Misaligned Exception
|
||||
|
|
|
@ -253,6 +253,10 @@ module store_buffer (
|
|||
@(posedge clk_i) rst_ni && (speculative_status_cnt_q == DEPTH_SPEC) |-> !valid_i)
|
||||
else $error ("[Speculative Queue] You are trying to push new data although the buffer is not ready");
|
||||
|
||||
speculative_buffer_underflow: assert property (
|
||||
@(posedge clk_i) rst_ni && (speculative_status_cnt_q == 0) |-> !commit_i)
|
||||
else $error ("[Speculative Queue] You are committing although there are no stores to commit");
|
||||
|
||||
commit_buffer_overflow: assert property (
|
||||
@(posedge clk_i) rst_ni && (commit_status_cnt_q == DEPTH_SPEC) |-> !commit_i)
|
||||
else $error("[Commit Queue] You are trying to commit a store although the buffer is full");
|
||||
|
|
|
@ -57,9 +57,9 @@ module store_unit (
|
|||
} state_d, state_q;
|
||||
|
||||
// store buffer control signals
|
||||
logic st_ready;
|
||||
logic st_valid;
|
||||
logic st_valid_without_flush;
|
||||
logic st_ready;
|
||||
logic st_valid;
|
||||
logic st_valid_without_flush;
|
||||
|
||||
// keep the data and the byte enable for the second cycle (after address translation)
|
||||
logic [63:0] st_data_n, st_data_q;
|
||||
|
@ -165,7 +165,7 @@ module store_unit (
|
|||
// the only difference is that we do not want to store this request
|
||||
pop_st_o = 1'b1;
|
||||
st_valid = 1'b0;
|
||||
state_d = IDLE;
|
||||
state_d = IDLE;
|
||||
valid_o = 1'b1;
|
||||
end
|
||||
|
||||
|
@ -179,18 +179,22 @@ module store_unit (
|
|||
// re-align the write data to comply with the address offset
|
||||
always_comb begin
|
||||
st_be_n = lsu_ctrl_i.be;
|
||||
st_data_n = lsu_ctrl_i.data;
|
||||
st_data_n = data_align(lsu_ctrl_i.vaddr[2:0], lsu_ctrl_i.data);
|
||||
st_data_size_n = extract_transfer_size(lsu_ctrl_i.operator);
|
||||
|
||||
case (lsu_ctrl_i.vaddr[2:0])
|
||||
3'b000: st_data_n = lsu_ctrl_i.data;
|
||||
3'b001: st_data_n = {lsu_ctrl_i.data[55:0], lsu_ctrl_i.data[63:56]};
|
||||
3'b010: st_data_n = {lsu_ctrl_i.data[47:0], lsu_ctrl_i.data[63:48]};
|
||||
3'b011: st_data_n = {lsu_ctrl_i.data[39:0], lsu_ctrl_i.data[63:40]};
|
||||
3'b100: st_data_n = {lsu_ctrl_i.data[31:0], lsu_ctrl_i.data[63:32]};
|
||||
3'b101: st_data_n = {lsu_ctrl_i.data[23:0], lsu_ctrl_i.data[63:24]};
|
||||
3'b110: st_data_n = {lsu_ctrl_i.data[15:0], lsu_ctrl_i.data[63:16]};
|
||||
3'b111: st_data_n = {lsu_ctrl_i.data[7:0], lsu_ctrl_i.data[63:8]};
|
||||
// save AMO op for next cycle
|
||||
case (lsu_ctrl_i.operator)
|
||||
AMO_LRW, AMO_LRD: amo_op_d = AMO_LR;
|
||||
AMO_SCW, AMO_SCD: amo_op_d = AMO_SC;
|
||||
AMO_SWAPW, AMO_SWAPD: amo_op_d = AMO_SWAP;
|
||||
AMO_ADDW, AMO_ADDD: amo_op_d = AMO_ADD;
|
||||
AMO_ANDW, AMO_ANDD: amo_op_d = AMO_AND;
|
||||
AMO_ORW, AMO_ORD: amo_op_d = AMO_OR;
|
||||
AMO_XORW, AMO_XORD: amo_op_d = AMO_XOR;
|
||||
AMO_MAXW, AMO_MAXD: amo_op_d = AMO_MAX;
|
||||
AMO_MAXWU, AMO_MAXDU: amo_op_d = AMO_MAXU;
|
||||
AMO_MINW, AMO_MIND: amo_op_d = AMO_MIN;
|
||||
AMO_MINWU, AMO_MINDU: amo_op_d = AMO_MINU;
|
||||
default: amo_op_d = AMO_NONE;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -231,27 +235,6 @@ module store_unit (
|
|||
.req_port_o ( req_port_o )
|
||||
);
|
||||
|
||||
// ---------------
|
||||
// AMO Buffer
|
||||
// ---------------
|
||||
always_comb begin
|
||||
amo_op_d = amo_op_q;
|
||||
|
||||
case (lsu_ctrl_i.operator)
|
||||
AMO_LRW, AMO_LRD: amo_op_d = AMO_LR;
|
||||
AMO_SCW, AMO_SCD: amo_op_d = AMO_SC;
|
||||
AMO_SWAPW, AMO_SWAPD: amo_op_d = AMO_SWAP;
|
||||
AMO_ADDW, AMO_ADDD: amo_op_d = AMO_ADD;
|
||||
AMO_ANDW, AMO_ANDD: amo_op_d = AMO_AND;
|
||||
AMO_ORW, AMO_ORD: amo_op_d = AMO_OR;
|
||||
AMO_XORW, AMO_XORD: amo_op_d = AMO_XOR;
|
||||
AMO_MAXW, AMO_MAXD: amo_op_d = AMO_MAX;
|
||||
AMO_MAXWU, AMO_MAXDU: amo_op_d = AMO_MAXU;
|
||||
AMO_MINW, AMO_MIND: amo_op_d = AMO_MIN;
|
||||
AMO_MINWU, AMO_MINDU: amo_op_d = AMO_MINU;
|
||||
endcase
|
||||
end
|
||||
|
||||
amo_buffer i_amo_buffer (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
@ -280,7 +263,7 @@ module store_unit (
|
|||
trans_id_q <= '0;
|
||||
amo_op_q <= AMO_NONE;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
state_q <= state_d;
|
||||
st_be_q <= st_be_n;
|
||||
st_data_q <= st_data_n;
|
||||
trans_id_q <= trans_id_n;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue