Code_coverage: Add conditions for the AMO Extension (#1554)

This commit is contained in:
AEzzejjari 2023-10-19 21:08:40 +01:00 committed by GitHub
parent 74675b400c
commit 29a3f14868
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 187 deletions

View file

@ -1,2 +1,2 @@
cv32a6_embedded:
gates: 129232
gates: 127005

View file

@ -209,82 +209,59 @@ module wt_axi_adapter
end
//////////////////////////////////////
wt_cache_pkg::DCACHE_ATOMIC_REQ: begin
// default
// push back an invalidation here.
// since we only keep one read tx in flight, and since
// the dcache drains all writes/reads before executing
// an atomic, this is safe.
invalidate = arb_gnt;
axi_wr_req = 1'b1;
axi_wr_be = '0;
unique case (dcache_data.size[1:0])
2'b00:
axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0]] = '1; // byte
2'b01:
axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0]+:2] = '1; // hword
2'b10:
axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0]+:4] = '1; // word
default:
axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0]+:8] = '1; // dword
endcase
amo_gen_r_d = 1'b1;
// need to use a separate ID here, so concat an additional bit
axi_wr_id_in[1] = 1'b1;
if(CVA6Cfg.RVA) begin
// default
// push back an invalidation here.
// since we only keep one read tx in flight, and since
// the dcache drains all writes/reads before executing
// an atomic, this is safe.
invalidate = arb_gnt;
axi_wr_req = 1'b1;
axi_wr_be = '0;
unique case(dcache_data.size[1:0])
2'b00: axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0]] = '1; // byte
2'b01: axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0] +:2 ] = '1; // hword
2'b10: axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0] +:4 ] = '1; // word
default: axi_wr_be[0][dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0] +:8 ] = '1; // dword
endcase
amo_gen_r_d = 1'b1;
// need to use a separate ID here, so concat an additional bit
axi_wr_id_in[1] = 1'b1;
unique case (dcache_data.amo_op)
AMO_LR: begin
axi_rd_lock = 1'b1;
axi_rd_req = 1'b1;
axi_rd_id_in[1] = 1'b1;
// tie to zero in this special case
axi_wr_req = 1'b0;
axi_wr_be = '0;
end
AMO_SC: begin
axi_wr_lock = 1'b1;
amo_gen_r_d = 1'b0;
// needed to properly encode success. store the result at offset within the returned
// AXI data word aligned with the requested word size.
amo_off_d = dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-
1:0] & ~((1 << dcache_data.size[1:0]) - 1);
end
// RISC-V atops have a load semantic
AMO_SWAP:
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ATOMICSWAP
};
AMO_ADD:
axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ADD};
AMO_AND: begin
// in this case we need to invert the data to get a "CLR"
axi_wr_data = ~{(CVA6Cfg.AxiDataWidth / riscv::XLEN) {dcache_data.data}};
axi_wr_user = ~{(CVA6Cfg.AxiDataWidth / riscv::XLEN) {dcache_data.user}};
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_CLR
};
end
AMO_OR:
axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SET};
AMO_XOR:
axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_EOR};
AMO_MAX:
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMAX
};
AMO_MAXU:
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMAX
};
AMO_MIN:
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMIN
};
AMO_MINU:
axi_wr_atop = {
axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMIN
};
default: ; // Do nothing
endcase
unique case (dcache_data.amo_op)
AMO_LR: begin
axi_rd_lock = 1'b1;
axi_rd_req = 1'b1;
axi_rd_id_in[1] = 1'b1;
// tie to zero in this special case
axi_wr_req = 1'b0;
axi_wr_be = '0;
end
AMO_SC: begin
axi_wr_lock = 1'b1;
amo_gen_r_d = 1'b0;
// needed to properly encode success. store the result at offset within the returned
// AXI data word aligned with the requested word size.
amo_off_d = dcache_data.paddr[$clog2(CVA6Cfg.AxiDataWidth/8)-1:0] & ~((1 << dcache_data.size[1:0]) - 1);
end
// RISC-V atops have a load semantic
AMO_SWAP: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ATOMICSWAP};
AMO_ADD: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ADD};
AMO_AND: begin
// in this case we need to invert the data to get a "CLR"
axi_wr_data = ~{(CVA6Cfg.AxiDataWidth/riscv::XLEN){dcache_data.data}};
axi_wr_user = ~{(CVA6Cfg.AxiDataWidth/riscv::XLEN){dcache_data.user}};
axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_CLR};
end
AMO_OR: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SET};
AMO_XOR: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_EOR};
AMO_MAX: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMAX};
AMO_MAXU: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMAX};
AMO_MIN: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMIN};
AMO_MINU: axi_wr_atop = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMIN};
default: ; // Do nothing
endcase
end
end
default: ; // Do nothing
//////////////////////////////////////
@ -490,7 +467,7 @@ module wt_axi_adapter
dcache_rd_shift_d[0] = axi_rd_data;
dcache_rd_shift_user_d[0] = axi_rd_user;
end
end else if (dcache_sc_rtrn) begin
end else if (CVA6Cfg.RVA && dcache_sc_rtrn) begin
// encode lr/sc success
dcache_rd_shift_d[0] = '0;
dcache_rd_shift_user_d[0] = '0;
@ -541,9 +518,9 @@ module wt_axi_adapter
// note that this self invalidation is handled in this way due to the
// write-through cache architecture, which is aligned with the openpiton
// cache subsystem.
end else if (invalidate) begin
dcache_rtrn_type_d = wt_cache_pkg::DCACHE_INV_REQ;
dcache_rtrn_vld_d = 1'b1;
end else if (CVA6Cfg.RVA && invalidate) begin
dcache_rtrn_type_d = wt_cache_pkg::DCACHE_INV_REQ;
dcache_rtrn_vld_d = 1'b1;
dcache_rtrn_inv_d.all = 1'b1;
dcache_rtrn_inv_d.idx = dcache_data.paddr[ariane_pkg::DCACHE_INDEX_WIDTH-1:0];
@ -556,7 +533,7 @@ module wt_axi_adapter
dcache_rtrn_vld_d = axi_rd_last;
// if this was an atomic op
if (axi_rd_id_out[1]) begin
if (CVA6Cfg.RVA && axi_rd_id_out[1]) begin
dcache_rtrn_type_d = wt_cache_pkg::DCACHE_ATOMIC_ACK;
// check if transaction was issued over write channel and pop that ID
@ -575,7 +552,7 @@ module wt_axi_adapter
b_pop = 1'b1;
// this was an atomic
if (wr_id_out[1]) begin
if (CVA6Cfg.RVA && wr_id_out[1]) begin
dcache_rtrn_type_d = wt_cache_pkg::DCACHE_ATOMIC_ACK;
// silently discard b response if we already popped the fifo

View file

@ -243,54 +243,55 @@ module wt_dcache_missunit
// if size = 32bit word, select appropriate offset, replicate for openpiton...
always_comb begin
if (riscv::IS_XLEN64) begin
if (amo_req_i.size == 2'b10) begin
amo_data = {amo_req_i.operand_b[0+:32], amo_req_i.operand_b[0+:32]};
end else begin
amo_data = amo_req_i.operand_b;
if (CVA6Cfg.RVA) begin
if (riscv::IS_XLEN64) begin
if (amo_req_i.size==2'b10) begin
amo_data = {amo_req_i.operand_b[0 +: 32], amo_req_i.operand_b[0 +: 32]};
end else begin
amo_data = amo_req_i.operand_b;
end
end else begin
amo_data = amo_req_i.operand_b[0 +: 32];
end
if (ariane_pkg::DATA_USER_EN) begin
amo_user = amo_data;
end else begin
amo_user = '0;
end
end
end
if (CVA6Cfg.RVA) begin
// note: openpiton returns a full cacheline!
if (CVA6Cfg.NOCType == config_pkg::NOC_TYPE_AXI4_ATOP) begin : gen_axi_rtrn_mux
if (CVA6Cfg.AxiDataWidth > 64) begin
assign amo_rtrn_mux = mem_rtrn_i.data[amo_req_i.operand_a[$clog2(CVA6Cfg.AxiDataWidth/8)-1:3]*64 +: 64];
end else begin
assign amo_rtrn_mux = mem_rtrn_i.data[0 +: 64];
end
end else begin : gen_piton_rtrn_mux
assign amo_rtrn_mux = mem_rtrn_i.data[amo_req_i.operand_a[DCACHE_OFFSET_WIDTH-1:3]*64 +: 64];
end
end else begin
amo_data = amo_req_i.operand_b[0+:32];
end
if (ariane_pkg::DATA_USER_EN) begin
amo_user = amo_data;
end else begin
amo_user = '0;
end
// always sign extend 32bit values
assign amo_resp_o.result = (amo_req_i.size==2'b10) ? {{32{amo_rtrn_mux[amo_req_i.operand_a[2]*32 + 31]}},amo_rtrn_mux[amo_req_i.operand_a[2]*32 +: 32]} :
amo_rtrn_mux ;
assign amo_req_d = amo_req_i.req;
end
// note: openpiton returns a full cacheline!
if (CVA6Cfg.NOCType == config_pkg::NOC_TYPE_AXI4_ATOP) begin : gen_axi_rtrn_mux
if (CVA6Cfg.AxiDataWidth > 64) begin
assign amo_rtrn_mux = mem_rtrn_i.data[amo_req_i.operand_a[$clog2(
CVA6Cfg.AxiDataWidth/8
)-1:3]*64+:64];
end else begin
assign amo_rtrn_mux = mem_rtrn_i.data[0+:64];
end
end else begin : gen_piton_rtrn_mux
assign amo_rtrn_mux = mem_rtrn_i.data[amo_req_i.operand_a[DCACHE_OFFSET_WIDTH-1:3]*64+:64];
end
// always sign extend 32bit values
assign amo_resp_o.result = (amo_req_i.size==2'b10) ? {{32{amo_rtrn_mux[amo_req_i.operand_a[2]*32 + 31]}},amo_rtrn_mux[amo_req_i.operand_a[2]*32 +: 32]} :
amo_rtrn_mux ;
assign amo_req_d = amo_req_i.req;
// outgoing memory requests (AMOs are always uncached)
assign mem_data_o.tid = (amo_sel) ? AmoTxId : miss_id_i[miss_port_idx];
assign mem_data_o.nc = (amo_sel) ? 1'b1 : miss_nc_i[miss_port_idx];
assign mem_data_o.way = (amo_sel) ? '0 : repl_way;
assign mem_data_o.data = (amo_sel) ? amo_data : miss_wdata_i[miss_port_idx];
assign mem_data_o.user = (amo_sel) ? amo_user : miss_wuser_i[miss_port_idx];
assign mem_data_o.size = (amo_sel) ? amo_req_i.size : miss_size_i[miss_port_idx];
assign mem_data_o.amo_op = (amo_sel) ? amo_req_i.amo_op : AMO_NONE;
assign mem_data_o.tid = (CVA6Cfg.RVA && amo_sel) ? AmoTxId : miss_id_i[miss_port_idx];
assign mem_data_o.nc = (CVA6Cfg.RVA && amo_sel) ? 1'b1 : miss_nc_i[miss_port_idx];
assign mem_data_o.way = (CVA6Cfg.RVA && amo_sel) ? '0 : repl_way;
assign mem_data_o.data = (CVA6Cfg.RVA && amo_sel) ? amo_data : miss_wdata_i[miss_port_idx];
assign mem_data_o.user = (CVA6Cfg.RVA && amo_sel) ? amo_user : miss_wuser_i[miss_port_idx];
assign mem_data_o.size = (CVA6Cfg.RVA && amo_sel) ? amo_req_i.size : miss_size_i [miss_port_idx];
assign mem_data_o.amo_op = (CVA6Cfg.RVA && amo_sel) ? amo_req_i.amo_op : AMO_NONE;
assign tmp_paddr = (amo_sel) ? amo_req_i.operand_a[riscv::PLEN-1:0] : miss_paddr_i[miss_port_idx];
assign mem_data_o.paddr = paddrSizeAlign(tmp_paddr, mem_data_o.size);
assign tmp_paddr = (CVA6Cfg.RVA && amo_sel) ? amo_req_i.operand_a[riscv::PLEN-1:0] : miss_paddr_i[miss_port_idx];
assign mem_data_o.paddr = paddrSizeAlign(tmp_paddr, mem_data_o.size);
///////////////////////////////////////////////////////
// back-off mechanism for LR/SC completion guarantee
@ -347,17 +348,19 @@ module wt_dcache_missunit
end
end
DCACHE_ATOMIC_ACK: begin
if (amo_req_q) begin
amo_ack = 1'b1;
// need to set SC backoff counter if
// this op failed
if (amo_req_i.amo_op == AMO_SC) begin
if (amo_resp_o.result > 0) begin
sc_fail = 1'b1;
end else begin
sc_pass = 1'b1;
if(CVA6Cfg.RVA) begin
if (amo_req_q) begin
amo_ack = 1'b1;
// need to set SC backoff counter if
// this op failed
if (amo_req_i.amo_op == AMO_SC) begin
if (amo_resp_o.result>0) begin
sc_fail = 1'b1;
end else begin
sc_pass = 1'b1;
end
end
end
end
end
end
DCACHE_INV_REQ: begin
@ -443,7 +446,7 @@ module wt_dcache_missunit
end else begin
state_d = DRAIN;
end
end else if (amo_req_i.req) begin
end else if (CVA6Cfg.RVA && amo_req_i.req) begin
if (wbuffer_empty_i && !mshr_vld_q) begin
state_d = AMO;
end else begin
@ -533,23 +536,27 @@ module wt_dcache_missunit
//////////////////////////////////
// send out amo op request
AMO: begin
mem_data_o.rtype = DCACHE_ATOMIC_REQ;
amo_sel = 1'b1;
// if this is an LR, we need to consult the backoff counter
if ((amo_req_i.amo_op != AMO_LR) || sc_backoff_over) begin
mem_data_req_o = 1'b1;
if (mem_data_ack_i) begin
state_d = AMO_WAIT;
end
if(CVA6Cfg.RVA) begin
mem_data_o.rtype = DCACHE_ATOMIC_REQ;
amo_sel = 1'b1;
// if this is an LR, we need to consult the backoff counter
if ((amo_req_i.amo_op != AMO_LR) || sc_backoff_over) begin
mem_data_req_o = 1'b1;
if (mem_data_ack_i) begin
state_d = AMO_WAIT;
end
end
end
end
//////////////////////////////////
// block and wait until AMO OP returns
AMO_WAIT: begin
amo_sel = 1'b1;
if (amo_ack) begin
amo_resp_o.ack = 1'b1;
state_d = IDLE;
if(CVA6Cfg.RVA) begin
amo_sel = 1'b1;
if (amo_ack) begin
amo_resp_o.ack = 1'b1;
state_d = IDLE;
end
end
end
//////////////////////////////////

View file

@ -106,7 +106,7 @@ module commit_stage
commit_lsu_o = 1'b0;
commit_csr_o = 1'b0;
// amos will commit on port 0
wdata_o[0] = (amo_resp_i.ack) ? amo_resp_i.result[riscv::XLEN-1:0] : commit_instr_i[0].result;
wdata_o[0] = (CVA6Cfg.RVA && amo_resp_i.ack) ? amo_resp_i.result[riscv::XLEN-1:0] : commit_instr_i[0].result;
csr_op_o = ADD; // this corresponds to a CSR NOP
csr_wdata_o = {riscv::XLEN{1'b0}};
fence_i_o = 1'b0;

View file

@ -136,12 +136,18 @@ module controller
end
// Set PC to commit stage and flush pipeline
if (flush_csr_i || flush_commit_i || flush_acc_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
if (flush_csr_i || flush_acc_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end else if (CVA6Cfg.RVA && flush_commit_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
// ---------------------------------

View file

@ -187,24 +187,28 @@ module store_unit
always_comb begin
st_be_n = lsu_ctrl_i.be;
// don't shift the data if we are going to perform an AMO as we still need to operate on this data
st_data_n = instr_is_amo ? lsu_ctrl_i.data[riscv::XLEN-1:0] :
st_data_n = (CVA6Cfg.RVA && instr_is_amo) ? lsu_ctrl_i.data[riscv::XLEN-1:0] :
data_align(lsu_ctrl_i.vaddr[2:0], lsu_ctrl_i.data);
st_data_size_n = extract_transfer_size(lsu_ctrl_i.operation);
// save AMO op for next cycle
case (lsu_ctrl_i.operation)
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
if(CVA6Cfg.RVA) begin
case (lsu_ctrl_i.operation)
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 else begin
amo_op_d = AMO_NONE;
end
end
logic store_buffer_valid, amo_buffer_valid;
@ -249,23 +253,28 @@ module store_unit
.req_port_o (req_port_o)
);
amo_buffer #(
.CVA6Cfg(CVA6Cfg)
) i_amo_buffer (
.clk_i,
.rst_ni,
.flush_i,
.valid_i (amo_buffer_valid),
.ready_o (amo_buffer_ready),
.paddr_i (paddr_i),
.amo_op_i (amo_op_q),
.data_i (st_data_q),
.data_size_i (st_data_size_q),
.amo_req_o (amo_req_o),
.amo_resp_i (amo_resp_i),
.amo_valid_commit_i(amo_valid_commit_i),
.no_st_pending_i (no_st_pending_o)
);
if(CVA6Cfg.RVA) begin
amo_buffer #(
.CVA6Cfg ( CVA6Cfg )
) i_amo_buffer (
.clk_i,
.rst_ni,
.flush_i,
.valid_i ( amo_buffer_valid ),
.ready_o ( amo_buffer_ready ),
.paddr_i ( paddr_i ),
.amo_op_i ( amo_op_q ),
.data_i ( st_data_q ),
.data_size_i ( st_data_size_q ),
.amo_req_o ( amo_req_o ),
.amo_resp_i ( amo_resp_i ),
.amo_valid_commit_i ( amo_valid_commit_i ),
.no_st_pending_i ( no_st_pending_o )
);
end else begin
assign amo_buffer_ready = '1;
assign amo_req_o = '0;
end
// ---------------
// Registers