mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 12:17:19 -04:00
Dev dcache 32bits (#849)
Reduce dcache data output width from 64 to 32 bits in cv32a6 configuration Signed-off-by: sjthales <sebastien.jacq@thalesgroup.com>
This commit is contained in:
parent
48af8dab6e
commit
0b61544da8
14 changed files with 226 additions and 146 deletions
|
@ -119,7 +119,6 @@ module wt_axi_adapter import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
always_comb begin : p_axi_req
|
||||
// write channel
|
||||
axi_wr_id_in = arb_idx;
|
||||
axi_wr_data = dcache_data.data;
|
||||
axi_wr_addr = {{64-riscv::PLEN{1'b0}}, dcache_data.paddr};
|
||||
axi_wr_size = dcache_data.size[1:0];
|
||||
axi_wr_req = 1'b0;
|
||||
|
@ -135,6 +134,12 @@ module wt_axi_adapter import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
axi_rd_req = 1'b0;
|
||||
axi_rd_lock = '0;
|
||||
axi_rd_blen = '0;
|
||||
|
||||
if (dcache_data.paddr[2] == 1'b0) begin
|
||||
axi_wr_data = {{64-riscv::XLEN{1'b0}}, dcache_data.data};
|
||||
end else begin
|
||||
axi_wr_data = {dcache_data.data, {64-riscv::XLEN{1'b0}}};
|
||||
end
|
||||
|
||||
// arbiter mux
|
||||
if (arb_idx) begin
|
||||
|
@ -171,7 +176,7 @@ module wt_axi_adapter import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
//////////////////////////////////////
|
||||
wt_cache_pkg::DCACHE_STORE_REQ: begin
|
||||
axi_wr_req = 1'b1;
|
||||
axi_wr_be = wt_cache_pkg::toByteEnable8(dcache_data.paddr[2:0], dcache_data.size[1:0]);
|
||||
axi_wr_be = wt_cache_pkg::to_byte_enable8(dcache_data.paddr[2:0], dcache_data.size[1:0]);
|
||||
end
|
||||
//////////////////////////////////////
|
||||
wt_cache_pkg::DCACHE_ATOMIC_REQ: begin
|
||||
|
@ -182,7 +187,7 @@ module wt_axi_adapter import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// an atomic, this is safe.
|
||||
invalidate = arb_gnt;
|
||||
axi_wr_req = 1'b1;
|
||||
axi_wr_be = wt_cache_pkg::toByteEnable8(dcache_data.paddr[2:0], dcache_data.size[1:0]);
|
||||
axi_wr_be = wt_cache_pkg::to_byte_enable8(dcache_data.paddr[2:0], dcache_data.size[1:0]);
|
||||
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;
|
||||
|
@ -212,7 +217,11 @@ module wt_axi_adapter import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
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 = ~dcache_data.data;
|
||||
if (dcache_data.paddr[2] == 1'b0) begin
|
||||
axi_wr_data = {{64-riscv::XLEN{1'b1}}, ~dcache_data.data};
|
||||
end else begin
|
||||
axi_wr_data = {~dcache_data.data, {64-riscv::XLEN{1'b1}}};
|
||||
end
|
||||
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};
|
||||
|
|
|
@ -66,15 +66,15 @@ module wt_dcache import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic wr_ack;
|
||||
logic [DCACHE_CL_IDX_WIDTH-1:0] wr_idx;
|
||||
logic [DCACHE_OFFSET_WIDTH-1:0] wr_off;
|
||||
logic [63:0] wr_data;
|
||||
logic [7:0] wr_data_be;
|
||||
riscv::xlen_t wr_data;
|
||||
logic [(riscv::XLEN/8)-1:0] wr_data_be;
|
||||
|
||||
// miss unit <-> controllers/wbuffer
|
||||
logic [NumPorts-1:0] miss_req;
|
||||
logic [NumPorts-1:0] miss_ack;
|
||||
logic [NumPorts-1:0] miss_nc;
|
||||
logic [NumPorts-1:0] miss_we;
|
||||
logic [NumPorts-1:0][63:0] miss_wdata;
|
||||
logic [NumPorts-1:0][riscv::XLEN-1:0] miss_wdata;
|
||||
logic [NumPorts-1:0][riscv::PLEN-1:0] miss_paddr;
|
||||
logic [NumPorts-1:0][DCACHE_SET_ASSOC-1:0] miss_vld_bits;
|
||||
logic [NumPorts-1:0][2:0] miss_size;
|
||||
|
@ -91,7 +91,7 @@ module wt_dcache import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic [NumPorts-1:0][DCACHE_TAG_WIDTH-1:0] rd_tag;
|
||||
logic [NumPorts-1:0][DCACHE_CL_IDX_WIDTH-1:0] rd_idx;
|
||||
logic [NumPorts-1:0][DCACHE_OFFSET_WIDTH-1:0] rd_off;
|
||||
logic [63:0] rd_data;
|
||||
riscv::xlen_t rd_data;
|
||||
logic [DCACHE_SET_ASSOC-1:0] rd_vld_bits;
|
||||
logic [DCACHE_SET_ASSOC-1:0] rd_hit_oh;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic miss_req_o,
|
||||
input logic miss_ack_i,
|
||||
output logic miss_we_o, // unused (set to 0)
|
||||
output logic [63:0] miss_wdata_o, // unused (set to 0)
|
||||
output riscv::xlen_t miss_wdata_o, // unused (set to 0)
|
||||
output logic [DCACHE_SET_ASSOC-1:0] miss_vld_bits_o, // valid bits at the missed index
|
||||
output logic [riscv::PLEN-1:0] miss_paddr_o,
|
||||
output logic miss_nc_o, // request to I/O space
|
||||
|
@ -44,7 +44,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic rd_req_o, // read the word at offset off_i[:3] in all ways
|
||||
output logic rd_tag_only_o, // set to zero here
|
||||
input logic rd_ack_i,
|
||||
input logic [63:0] rd_data_i,
|
||||
input riscv::xlen_t rd_data_i,
|
||||
input logic [DCACHE_SET_ASSOC-1:0] rd_vld_bits_i,
|
||||
input logic [DCACHE_SET_ASSOC-1:0] rd_hit_oh_i
|
||||
);
|
||||
|
|
|
@ -43,7 +43,7 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic [NumPorts-1:0] rd_ack_o,
|
||||
output logic [DCACHE_SET_ASSOC-1:0] rd_vld_bits_o,
|
||||
output logic [DCACHE_SET_ASSOC-1:0] rd_hit_oh_o,
|
||||
output logic [63:0] rd_data_o,
|
||||
output riscv::xlen_t rd_data_o,
|
||||
|
||||
// only available on port 0, uses address signals of port 0
|
||||
input logic wr_cl_vld_i,
|
||||
|
@ -61,23 +61,23 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic wr_ack_o,
|
||||
input logic [DCACHE_CL_IDX_WIDTH-1:0] wr_idx_i,
|
||||
input logic [DCACHE_OFFSET_WIDTH-1:0] wr_off_i,
|
||||
input logic [63:0] wr_data_i,
|
||||
input logic [7:0] wr_data_be_i,
|
||||
input riscv::xlen_t wr_data_i,
|
||||
input logic [(riscv::XLEN/8)-1:0] wr_data_be_i,
|
||||
|
||||
// forwarded wbuffer
|
||||
input wbuffer_t [DCACHE_WBUF_DEPTH-1:0] wbuffer_data_i
|
||||
);
|
||||
|
||||
logic [DCACHE_NUM_BANKS-1:0] bank_req;
|
||||
logic [DCACHE_NUM_BANKS-1:0] bank_we;
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][7:0] bank_be;
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_CL_IDX_WIDTH-1:0] bank_idx;
|
||||
logic [DCACHE_CL_IDX_WIDTH-1:0] bank_idx_d, bank_idx_q;
|
||||
logic [DCACHE_OFFSET_WIDTH-1:0] bank_off_d, bank_off_q;
|
||||
logic [DCACHE_NUM_BANKS-1:0] bank_req;
|
||||
logic [DCACHE_NUM_BANKS-1:0] bank_we;
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][(riscv::XLEN/8)-1:0] bank_be;
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_CL_IDX_WIDTH-1:0] bank_idx;
|
||||
logic [DCACHE_CL_IDX_WIDTH-1:0] bank_idx_d, bank_idx_q;
|
||||
logic [DCACHE_OFFSET_WIDTH-1:0] bank_off_d, bank_off_q;
|
||||
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][63:0] bank_wdata; //
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][63:0] bank_rdata; //
|
||||
logic [DCACHE_SET_ASSOC-1:0][63:0] rdata_cl; // selected word from each cacheline
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][riscv::XLEN-1:0] bank_wdata; //
|
||||
logic [DCACHE_NUM_BANKS-1:0][DCACHE_SET_ASSOC-1:0][riscv::XLEN-1:0] bank_rdata; //
|
||||
logic [DCACHE_SET_ASSOC-1:0][riscv::XLEN-1:0] rdata_cl; // selected word from each cacheline
|
||||
|
||||
logic [DCACHE_TAG_WIDTH-1:0] rd_tag;
|
||||
logic [DCACHE_SET_ASSOC-1:0] vld_req; // bit enable for valid regs
|
||||
|
@ -89,8 +89,8 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic [$clog2(NumPorts)-1:0] vld_sel_d, vld_sel_q;
|
||||
|
||||
logic [DCACHE_WBUF_DEPTH-1:0] wbuffer_hit_oh;
|
||||
logic [7:0] wbuffer_be;
|
||||
logic [63:0] wbuffer_rdata, rdata;
|
||||
logic [(riscv::XLEN/8)-1:0] wbuffer_be;
|
||||
riscv::xlen_t wbuffer_rdata, rdata;
|
||||
logic [riscv::PLEN-1:0] wbuffer_cmp_addr;
|
||||
|
||||
logic cmp_en_d, cmp_en_q;
|
||||
|
@ -111,11 +111,11 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// byte enable mapping
|
||||
for (genvar k=0;k<DCACHE_NUM_BANKS;k++) begin : gen_bank
|
||||
for (genvar j=0;j<DCACHE_SET_ASSOC;j++) begin : gen_bank_way
|
||||
assign bank_be[k][j] = (wr_cl_we_i[j] & wr_cl_vld_i) ? wr_cl_data_be_i[k*8 +: 8] :
|
||||
assign bank_be[k][j] = (wr_cl_we_i[j] & wr_cl_vld_i) ? wr_cl_data_be_i[k*(riscv::XLEN/8) +: (riscv::XLEN/8)] :
|
||||
(wr_req_i[j] & wr_ack_o) ? wr_data_be_i :
|
||||
'0;
|
||||
|
||||
assign bank_wdata[k][j] = (wr_cl_we_i[j] & wr_cl_vld_i) ? wr_cl_data_i[k*64 +: 64] :
|
||||
assign bank_wdata[k][j] = (wr_cl_we_i[j] & wr_cl_vld_i) ? wr_cl_data_i[k*riscv::XLEN +: riscv::XLEN] :
|
||||
wr_data_i;
|
||||
end
|
||||
end
|
||||
|
@ -161,7 +161,7 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
bank_idx = '{default:wr_idx_i};
|
||||
|
||||
for(int k=0; k<NumPorts; k++) begin
|
||||
bank_collision[k] = rd_off_i[k][DCACHE_OFFSET_WIDTH-1:3] == wr_off_i[DCACHE_OFFSET_WIDTH-1:3];
|
||||
bank_collision[k] = rd_off_i[k][DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES] == wr_off_i[DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES];
|
||||
end
|
||||
|
||||
if(wr_cl_vld_i & |wr_cl_we_i) begin
|
||||
|
@ -171,16 +171,16 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
end else begin
|
||||
if(rd_acked) begin
|
||||
if(!rd_tag_only_i[vld_sel_d]) begin
|
||||
bank_req = dcache_cl_bin2oh(rd_off_i[vld_sel_d][DCACHE_OFFSET_WIDTH-1:3]);
|
||||
bank_idx[rd_off_i[vld_sel_d][DCACHE_OFFSET_WIDTH-1:3]] = rd_idx_i[vld_sel_d];
|
||||
bank_req = dcache_cl_bin2oh(rd_off_i[vld_sel_d][DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES]);
|
||||
bank_idx[rd_off_i[vld_sel_d][DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES]] = rd_idx_i[vld_sel_d];
|
||||
end
|
||||
end
|
||||
|
||||
if(|wr_req_i) begin
|
||||
if(rd_tag_only_i[vld_sel_d] || !(rd_ack_o[vld_sel_d] && bank_collision[vld_sel_d])) begin
|
||||
wr_ack_o = 1'b1;
|
||||
bank_req |= dcache_cl_bin2oh(wr_off_i[DCACHE_OFFSET_WIDTH-1:3]);
|
||||
bank_we = dcache_cl_bin2oh(wr_off_i[DCACHE_OFFSET_WIDTH-1:3]);
|
||||
bank_req |= dcache_cl_bin2oh(wr_off_i[DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES]);
|
||||
bank_we = dcache_cl_bin2oh(wr_off_i[DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES]);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -190,7 +190,8 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// tag comparison, hit generatio, readoud muxes
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
logic [DCACHE_OFFSET_WIDTH-1:0] wr_cl_off;
|
||||
logic [DCACHE_OFFSET_WIDTH-riscv::XLEN_ALIGN_BYTES-1:0] wr_cl_off;
|
||||
logic [DCACHE_OFFSET_WIDTH-riscv::XLEN_ALIGN_BYTES-1:0] wr_cl_nc_off;
|
||||
logic [$clog2(DCACHE_WBUF_DEPTH)-1:0] wbuffer_hit_idx;
|
||||
logic [$clog2(DCACHE_SET_ASSOC)-1:0] rd_hit_idx;
|
||||
|
||||
|
@ -204,11 +205,11 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// tag comparison of ways >0
|
||||
assign rd_hit_oh_o[i] = (rd_tag == tag_rdata[i]) & rd_vld_bits_o[i] & cmp_en_q;
|
||||
// byte offset mux of ways >0
|
||||
assign rdata_cl[i] = bank_rdata[bank_off_q[DCACHE_OFFSET_WIDTH-1:3]][i];
|
||||
assign rdata_cl[i] = bank_rdata[bank_off_q[DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES]][i];
|
||||
end
|
||||
|
||||
for(genvar k=0; k<DCACHE_WBUF_DEPTH; k++) begin : gen_wbuffer_hit
|
||||
assign wbuffer_hit_oh[k] = (|wbuffer_data_i[k].valid) & (wbuffer_data_i[k].wtag == (wbuffer_cmp_addr >> 3));
|
||||
assign wbuffer_hit_oh[k] = (|wbuffer_data_i[k].valid) & (wbuffer_data_i[k].wtag == (wbuffer_cmp_addr >> riscv::XLEN_ALIGN_BYTES));
|
||||
end
|
||||
|
||||
lzc #(
|
||||
|
@ -231,16 +232,17 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
assign wbuffer_be = (|wbuffer_hit_oh) ? wbuffer_data_i[wbuffer_hit_idx].valid : '0;
|
||||
|
||||
if (Axi64BitCompliant) begin : gen_axi_off
|
||||
assign wr_cl_off = (wr_cl_nc_i) ? '0 : wr_cl_off_i[DCACHE_OFFSET_WIDTH-1:3];
|
||||
assign wr_cl_nc_off = riscv::IS_XLEN64 ? '0 : wr_cl_off_i[2];
|
||||
assign wr_cl_off = (wr_cl_nc_i) ? wr_cl_nc_off : wr_cl_off_i[DCACHE_OFFSET_WIDTH-1:riscv::XLEN_ALIGN_BYTES];
|
||||
end else begin : gen_piton_off
|
||||
assign wr_cl_off = wr_cl_off_i[DCACHE_OFFSET_WIDTH-1:3];
|
||||
end
|
||||
|
||||
assign rdata = (wr_cl_vld_i) ? wr_cl_data_i[wr_cl_off*64 +: 64] :
|
||||
|
||||
assign rdata = (wr_cl_vld_i) ? wr_cl_data_i[wr_cl_off*riscv::XLEN +: riscv::XLEN] :
|
||||
rdata_cl[rd_hit_idx];
|
||||
|
||||
// overlay bytes that hit in the write buffer
|
||||
for(genvar k=0; k<8; k++) begin : gen_rd_data
|
||||
for(genvar k=0; k<(riscv::XLEN/8); k++) begin : gen_rd_data
|
||||
assign rd_data_o[8*k +: 8] = (wbuffer_be[k]) ? wbuffer_rdata[8*k +: 8] : rdata[8*k +: 8];
|
||||
end
|
||||
|
||||
|
@ -253,7 +255,7 @@ module wt_dcache_mem import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
for (genvar k = 0; k < DCACHE_NUM_BANKS; k++) begin : gen_data_banks
|
||||
// Data RAM
|
||||
sram #(
|
||||
.DATA_WIDTH ( ariane_pkg::DCACHE_SET_ASSOC * 64 ),
|
||||
.DATA_WIDTH ( ariane_pkg::DCACHE_SET_ASSOC * riscv::XLEN ),
|
||||
.NUM_WORDS ( wt_cache_pkg::DCACHE_NUM_WORDS )
|
||||
) i_data_sram (
|
||||
.clk_i ( clk_i ),
|
||||
|
|
|
@ -37,7 +37,7 @@ module wt_dcache_missunit import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic [NumPorts-1:0] miss_ack_o,
|
||||
input logic [NumPorts-1:0] miss_nc_i,
|
||||
input logic [NumPorts-1:0] miss_we_i,
|
||||
input logic [NumPorts-1:0][63:0] miss_wdata_i,
|
||||
input logic [NumPorts-1:0][riscv::XLEN-1:0] miss_wdata_i,
|
||||
input logic [NumPorts-1:0][riscv::PLEN-1:0] miss_paddr_i,
|
||||
input logic [NumPorts-1:0][DCACHE_SET_ASSOC-1:0] miss_vld_bits_i,
|
||||
input logic [NumPorts-1:0][2:0] miss_size_i,
|
||||
|
@ -95,7 +95,8 @@ module wt_dcache_missunit import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic mask_reads, lock_reqs;
|
||||
logic amo_sel, miss_is_write;
|
||||
logic amo_req_d, amo_req_q;
|
||||
logic [63:0] amo_data, amo_rtrn_mux;
|
||||
logic [63:0] amo_rtrn_mux;
|
||||
riscv::xlen_t amo_data;
|
||||
logic [riscv::PLEN-1:0] tmp_paddr;
|
||||
logic [$clog2(NumPorts)-1:0] miss_port_idx;
|
||||
logic [DCACHE_CL_IDX_WIDTH-1:0] cnt_d, cnt_q;
|
||||
|
@ -151,7 +152,7 @@ module wt_dcache_missunit import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
// generate random cacheline index
|
||||
lfsr #(
|
||||
.LfsrWidth ( ariane_pkg::DCACHE_SET_ASSOC ),
|
||||
.LfsrWidth ( 8 ),
|
||||
.OutWidth ( $clog2(ariane_pkg::DCACHE_SET_ASSOC))
|
||||
) i_lfsr_inv (
|
||||
.clk_i ( clk_i ),
|
||||
|
@ -200,9 +201,9 @@ module wt_dcache_missunit import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
///////////////////////////////////////////////////////
|
||||
|
||||
// if size = 32bit word, select appropriate offset, replicate for openpiton...
|
||||
assign amo_data = (amo_req_i.size==2'b10) ? {amo_req_i.operand_b[0 +: 32],
|
||||
amo_req_i.operand_b[0 +: 32]} :
|
||||
amo_req_i.operand_b;
|
||||
assign amo_data = riscv::IS_XLEN64 ? (amo_req_i.size==2'b10) ? {amo_req_i.operand_b[0 +: 32],amo_req_i.operand_b[0 +: 32]} : amo_req_i.operand_b :
|
||||
amo_req_i.operand_b[0 +: 32];
|
||||
|
||||
|
||||
// note: openpiton returns a full cacheline!
|
||||
if (Axi64BitCompliant) begin : gen_axi_rtrn_mux
|
||||
|
@ -212,9 +213,10 @@ module wt_dcache_missunit import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
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_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;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic [riscv::PLEN-1:0] miss_paddr_o,
|
||||
output logic miss_req_o,
|
||||
output logic miss_we_o, // always 1 here
|
||||
output logic [63:0] miss_wdata_o,
|
||||
output riscv::xlen_t miss_wdata_o,
|
||||
output logic [DCACHE_SET_ASSOC-1:0] miss_vld_bits_o, // unused here (set to 0)
|
||||
output logic miss_nc_o, // request to I/O space
|
||||
output logic [2:0] miss_size_o, //
|
||||
|
@ -81,7 +81,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
output logic rd_req_o, // read the word at offset off_i[:3] in all ways
|
||||
output logic rd_tag_only_o, // set to 1 here as we do not have to read the data arrays
|
||||
input logic rd_ack_i,
|
||||
input logic [63:0] rd_data_i, // unused
|
||||
input riscv::xlen_t rd_data_i, // unused
|
||||
input logic [DCACHE_SET_ASSOC-1:0] rd_vld_bits_i, // unused
|
||||
input logic [DCACHE_SET_ASSOC-1:0] rd_hit_oh_i,
|
||||
// cacheline writes
|
||||
|
@ -92,8 +92,8 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
input logic wr_ack_i,
|
||||
output logic [DCACHE_CL_IDX_WIDTH-1:0] wr_idx_o,
|
||||
output logic [DCACHE_OFFSET_WIDTH-1:0] wr_off_o,
|
||||
output logic [63:0] wr_data_o,
|
||||
output logic [7:0] wr_data_be_o,
|
||||
output riscv::xlen_t wr_data_o,
|
||||
output logic [(riscv::XLEN/8)-1:0] wr_data_be_o,
|
||||
// to forwarding logic and miss unit
|
||||
output wbuffer_t [DCACHE_WBUF_DEPTH-1:0] wbuffer_data_o,
|
||||
output logic [DCACHE_MAX_TX-1:0][riscv::PLEN-1:0] tx_paddr_o, // used to check for address collisions with read operations
|
||||
|
@ -106,13 +106,14 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic [DCACHE_WBUF_DEPTH-1:0] dirty;
|
||||
logic [DCACHE_WBUF_DEPTH-1:0] tocheck;
|
||||
logic [DCACHE_WBUF_DEPTH-1:0] wbuffer_hit_oh, inval_hit;
|
||||
logic [DCACHE_WBUF_DEPTH-1:0][7:0] bdirty;
|
||||
//logic [DCACHE_WBUF_DEPTH-1:0][7:0] bdirty;
|
||||
logic [DCACHE_WBUF_DEPTH-1:0][(riscv::XLEN/8)-1:0] bdirty;
|
||||
|
||||
logic [$clog2(DCACHE_WBUF_DEPTH)-1:0] next_ptr, dirty_ptr, hit_ptr, wr_ptr, check_ptr_d, check_ptr_q, check_ptr_q1, rtrn_ptr;
|
||||
logic [CACHE_ID_WIDTH-1:0] tx_id, rtrn_id;
|
||||
|
||||
logic [2:0] bdirty_off;
|
||||
logic [7:0] tx_be;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] bdirty_off;
|
||||
logic [(riscv::XLEN/8)-1:0] tx_be;
|
||||
logic [riscv::PLEN-1:0] wr_paddr, rd_paddr;
|
||||
logic [DCACHE_TAG_WIDTH-1:0] rd_tag_d, rd_tag_q;
|
||||
logic [DCACHE_SET_ASSOC-1:0] rd_hit_oh_d, rd_hit_oh_q;
|
||||
|
@ -148,7 +149,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
for (genvar k=0; k<DCACHE_MAX_TX;k++) begin : gen_tx_vld
|
||||
assign tx_vld_o[k] = tx_stat_q[k].vld;
|
||||
assign tx_paddr_o[k] = wbuffer_q[tx_stat_q[k].ptr].wtag<<3;
|
||||
assign tx_paddr_o[k] = wbuffer_q[tx_stat_q[k].ptr].wtag<<riscv::XLEN_ALIGN_BYTES;
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
@ -164,7 +165,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
// get byte offset
|
||||
lzc #(
|
||||
.WIDTH ( 8 )
|
||||
.WIDTH ( riscv::XLEN/8 )
|
||||
) i_vld_bdirty (
|
||||
.in_i ( bdirty[dirty_ptr] ),
|
||||
.cnt_o ( bdirty_off ),
|
||||
|
@ -182,15 +183,16 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// note: openpiton can only handle aligned offsets + size, and hence
|
||||
// we have to split unaligned data into multiple transfers (see toSize64)
|
||||
// e.g. if we have the following valid bytes: 0011_1001 -> TX0: 0000_0001, TX1: 0000_1000, TX2: 0011_0000
|
||||
assign miss_size_o = toSize64(bdirty[dirty_ptr]);
|
||||
|
||||
assign miss_size_o = riscv::IS_XLEN64 ? toSize64(bdirty[dirty_ptr]):
|
||||
toSize32(bdirty[dirty_ptr]);
|
||||
|
||||
// replicate transfers shorter than a dword
|
||||
assign miss_wdata_o = repData64(wbuffer_dirty_mux.data,
|
||||
bdirty_off,
|
||||
miss_size_o[1:0]);
|
||||
assign miss_wdata_o = riscv::IS_XLEN64 ? repData64(wbuffer_dirty_mux.data, bdirty_off, miss_size_o[1:0]):
|
||||
repData32(wbuffer_dirty_mux.data, bdirty_off, miss_size_o[1:0]);
|
||||
|
||||
assign tx_be = toByteEnable8(bdirty_off,
|
||||
miss_size_o[1:0]);
|
||||
assign tx_be = riscv::IS_XLEN64 ? to_byte_enable8(bdirty_off, miss_size_o[1:0]):
|
||||
to_byte_enable4(bdirty_off, miss_size_o[1:0]);
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// TX status registers and ID counters
|
||||
|
@ -273,7 +275,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
// trigger TAG readout in cache
|
||||
assign rd_tag_only_o = 1'b1;
|
||||
assign rd_paddr = wbuffer_check_mux.wtag<<3;
|
||||
assign rd_paddr = wbuffer_check_mux.wtag<<riscv::XLEN_ALIGN_BYTES;
|
||||
assign rd_req_o = |tocheck;
|
||||
assign rd_tag_o = rd_tag_q;//delay by one cycle
|
||||
assign rd_idx_o = rd_paddr[DCACHE_INDEX_WIDTH-1:DCACHE_OFFSET_WIDTH];
|
||||
|
@ -285,7 +287,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// if we wrote into a word while it was in-flight, we cannot write the dirty bytes to the cache
|
||||
// when the TX returns
|
||||
assign wr_data_be_o = tx_stat_q[rtrn_id].be & (~wbuffer_q[rtrn_ptr].dirty);
|
||||
assign wr_paddr = wbuffer_q[rtrn_ptr].wtag<<3;
|
||||
assign wr_paddr = wbuffer_q[rtrn_ptr].wtag<<riscv::XLEN_ALIGN_BYTES;
|
||||
assign wr_idx_o = wr_paddr[DCACHE_INDEX_WIDTH-1:DCACHE_OFFSET_WIDTH];
|
||||
assign wr_off_o = wr_paddr[DCACHE_OFFSET_WIDTH-1:0];
|
||||
assign wr_data_o = wbuffer_q[rtrn_ptr].data;
|
||||
|
@ -302,7 +304,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
for (genvar k=0; k<DCACHE_WBUF_DEPTH; k++) begin : gen_flags
|
||||
// only for debug, will be pruned
|
||||
assign debug_paddr[k] = wbuffer_q[k].wtag << 3;
|
||||
assign debug_paddr[k] = wbuffer_q[k].wtag << riscv::XLEN_ALIGN_BYTES;
|
||||
|
||||
// dirty bytes that are ready for transmission.
|
||||
// note that we cannot retransmit a word that is already in-flight
|
||||
|
@ -312,12 +314,12 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
assign dirty[k] = |bdirty[k];
|
||||
assign valid[k] = |wbuffer_q[k].valid;
|
||||
assign wbuffer_hit_oh[k] = valid[k] & (wbuffer_q[k].wtag == {req_port_i.address_tag, req_port_i.address_index[DCACHE_INDEX_WIDTH-1:3]});
|
||||
assign wbuffer_hit_oh[k] = valid[k] & (wbuffer_q[k].wtag == {req_port_i.address_tag, req_port_i.address_index[DCACHE_INDEX_WIDTH-1:riscv::XLEN_ALIGN_BYTES]});
|
||||
|
||||
// checks if an invalidation/cache refill hits a particular word
|
||||
// note: an invalidation can hit multiple words!
|
||||
// need to respect previous cycle, too, since we add a cycle of latency to the rd_hit_oh_i signal...
|
||||
assign wtag_comp[k] = wbuffer_q[k].wtag[DCACHE_INDEX_WIDTH-4:DCACHE_OFFSET_WIDTH-3];
|
||||
assign wtag_comp[k] = wbuffer_q[k].wtag[DCACHE_INDEX_WIDTH-riscv::XLEN_ALIGN_BYTES-1:DCACHE_OFFSET_WIDTH-riscv::XLEN_ALIGN_BYTES];
|
||||
assign inval_hit[k] = (wr_cl_vld_d & valid[k] & (wtag_comp[k] == wr_cl_idx_d)) |
|
||||
(wr_cl_vld_q & valid[k] & (wtag_comp[k] == wr_cl_idx_q));
|
||||
|
||||
|
@ -425,7 +427,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// once TX write response came back, we can clear the TX block. if it was not dirty, we
|
||||
// can completely evict it - otherwise we have to leave it there for retransmission
|
||||
if (evict) begin
|
||||
for (int k=0; k<8; k++) begin
|
||||
for (int k=0; k<(riscv::XLEN/8); k++) begin
|
||||
if (tx_stat_q[rtrn_id].be[k]) begin
|
||||
wbuffer_d[rtrn_ptr].txblock[k] = 1'b0;
|
||||
if (!wbuffer_q[rtrn_ptr].dirty[k]) begin
|
||||
|
@ -447,7 +449,7 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
// mark bytes sent out to the memory system
|
||||
if (miss_req_o && miss_ack_i) begin
|
||||
dirty_rd_en = 1'b1;
|
||||
for (int k=0; k<8; k++) begin
|
||||
for (int k=0; k<(riscv::XLEN/8); k++) begin
|
||||
if (tx_be[k]) begin
|
||||
wbuffer_d[dirty_ptr].dirty[k] = 1'b0;
|
||||
wbuffer_d[dirty_ptr].txblock[k] = 1'b1;
|
||||
|
@ -466,10 +468,10 @@ module wt_dcache_wbuffer import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
ni_pending_d[wr_ptr] = is_ni;
|
||||
|
||||
wbuffer_d[wr_ptr].checked = 1'b0;
|
||||
wbuffer_d[wr_ptr].wtag = {req_port_i.address_tag, req_port_i.address_index[DCACHE_INDEX_WIDTH-1:3]};
|
||||
wbuffer_d[wr_ptr].wtag = {req_port_i.address_tag, req_port_i.address_index[DCACHE_INDEX_WIDTH-1:riscv::XLEN_ALIGN_BYTES]};
|
||||
|
||||
// mark bytes as dirty
|
||||
for (int k=0; k<8; k++) begin
|
||||
for (int k=0; k<(riscv::XLEN/8); k++) begin
|
||||
if (req_port_i.data_be[k]) begin
|
||||
wbuffer_d[wr_ptr].valid[k] = 1'b1;
|
||||
wbuffer_d[wr_ptr].dirty[k] = 1'b1;
|
||||
|
|
|
@ -572,16 +572,16 @@ package ariane_pkg;
|
|||
default: return 1'b0;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
|
||||
typedef struct packed {
|
||||
logic valid;
|
||||
logic [riscv::VLEN-1:0] vaddr;
|
||||
logic overflow;
|
||||
logic [63:0] data;
|
||||
logic [7:0] be;
|
||||
fu_t fu;
|
||||
fu_op operator;
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic valid;
|
||||
logic [riscv::VLEN-1:0] vaddr;
|
||||
logic overflow;
|
||||
riscv::xlen_t data;
|
||||
logic [(riscv::XLEN/8)-1:0] be;
|
||||
fu_t fu;
|
||||
fu_op operator;
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
} lsu_ctrl_t;
|
||||
|
||||
// ---------------
|
||||
|
@ -723,14 +723,14 @@ package ariane_pkg;
|
|||
logic [63:0] result; // sign-extended, result
|
||||
} amo_resp_t;
|
||||
|
||||
// D$ data requests
|
||||
// D$ data requests
|
||||
typedef struct packed {
|
||||
logic [DCACHE_INDEX_WIDTH-1:0] address_index;
|
||||
logic [DCACHE_TAG_WIDTH-1:0] address_tag;
|
||||
logic [63:0] data_wdata;
|
||||
riscv::xlen_t data_wdata;
|
||||
logic data_req;
|
||||
logic data_we;
|
||||
logic [7:0] data_be;
|
||||
logic [(riscv::XLEN/8)-1:0] data_be;
|
||||
logic [1:0] data_size;
|
||||
logic kill_req;
|
||||
logic tag_valid;
|
||||
|
@ -739,7 +739,7 @@ package ariane_pkg;
|
|||
typedef struct packed {
|
||||
logic data_gnt;
|
||||
logic data_rvalid;
|
||||
logic [63:0] data_rdata;
|
||||
riscv::xlen_t data_rdata;
|
||||
} dcache_req_o_t;
|
||||
|
||||
// ----------------------
|
||||
|
@ -826,6 +826,32 @@ package ariane_pkg;
|
|||
endcase
|
||||
return 8'b0;
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] be_gen_32(logic [1:0] addr, logic [1:0] size);
|
||||
case (size)
|
||||
2'b10: begin
|
||||
return 4'b1111;
|
||||
end
|
||||
2'b01: begin
|
||||
case (addr[1:0])
|
||||
2'b00: return 4'b0011;
|
||||
2'b01: return 4'b0110;
|
||||
2'b10: return 4'b1100;
|
||||
|
||||
endcase
|
||||
end
|
||||
2'b00: begin
|
||||
case (addr[1:0])
|
||||
2'b00: return 4'b0001;
|
||||
2'b01: return 4'b0010;
|
||||
2'b10: return 4'b0100;
|
||||
2'b11: return 4'b1000;
|
||||
endcase
|
||||
end
|
||||
default: return 4'b0;
|
||||
endcase
|
||||
return 4'b0;
|
||||
endfunction
|
||||
|
||||
// ----------------------
|
||||
// Extract Bytes from Op
|
||||
|
|
|
@ -37,17 +37,18 @@ package riscv;
|
|||
|
||||
// Warning: When using STD_CACHE, configuration must be PLEN=56 and VLEN=64
|
||||
// Warning: VLEN must be superior or equal to PLEN
|
||||
localparam VLEN = (XLEN == 32) ? 32 : 64; // virtual address length
|
||||
localparam PLEN = (XLEN == 32) ? 34 : 56; // physical address length
|
||||
localparam VLEN = (XLEN == 32) ? 32 : 64; // virtual address length
|
||||
localparam PLEN = (XLEN == 32) ? 34 : 56; // physical address length
|
||||
|
||||
localparam IS_XLEN32 = (XLEN == 32) ? 1'b1 : 1'b0;
|
||||
localparam IS_XLEN64 = (XLEN == 32) ? 1'b0 : 1'b1;
|
||||
localparam ModeW = (XLEN == 32) ? 1 : 4;
|
||||
localparam ASIDW = (XLEN == 32) ? 9 : 16;
|
||||
localparam PPNW = (XLEN == 32) ? 22 : 44;
|
||||
localparam vm_mode_t MODE_SV = (XLEN == 32) ? ModeSv32 : ModeSv39;
|
||||
localparam SV = (MODE_SV == ModeSv32) ? 32 : 39;
|
||||
localparam VPN2 = (VLEN-31 < 8) ? VLEN-31 : 8;
|
||||
localparam IS_XLEN32 = (XLEN == 32) ? 1'b1 : 1'b0;
|
||||
localparam IS_XLEN64 = (XLEN == 32) ? 1'b0 : 1'b1;
|
||||
localparam ModeW = (XLEN == 32) ? 1 : 4;
|
||||
localparam ASIDW = (XLEN == 32) ? 9 : 16;
|
||||
localparam PPNW = (XLEN == 32) ? 22 : 44;
|
||||
localparam vm_mode_t MODE_SV = (XLEN == 32) ? ModeSv32 : ModeSv39;
|
||||
localparam SV = (MODE_SV == ModeSv32) ? 32 : 39;
|
||||
localparam VPN2 = (VLEN-31 < 8) ? VLEN-31 : 8;
|
||||
localparam XLEN_ALIGN_BYTES = $clog2(XLEN/8);
|
||||
|
||||
typedef logic [XLEN-1:0] xlen_t;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ package wt_cache_pkg;
|
|||
localparam DCACHE_NUM_WORDS = 2**(ariane_pkg::DCACHE_INDEX_WIDTH-DCACHE_OFFSET_WIDTH);
|
||||
localparam DCACHE_CL_IDX_WIDTH = $clog2(DCACHE_NUM_WORDS);// excluding byte offset
|
||||
|
||||
localparam DCACHE_NUM_BANKS = ariane_pkg::DCACHE_LINE_WIDTH/64;
|
||||
localparam DCACHE_NUM_BANKS = ariane_pkg::DCACHE_LINE_WIDTH/riscv::XLEN;
|
||||
localparam DCACHE_NUM_BANKS_WIDTH = $clog2(DCACHE_NUM_BANKS);
|
||||
|
||||
// write buffer parameterization
|
||||
|
@ -75,21 +75,22 @@ package wt_cache_pkg;
|
|||
|
||||
|
||||
typedef struct packed {
|
||||
logic [ariane_pkg::DCACHE_TAG_WIDTH+(ariane_pkg::DCACHE_INDEX_WIDTH-3)-1:0] wtag;
|
||||
logic [63:0] data;
|
||||
logic [7:0] dirty; // byte is dirty
|
||||
logic [7:0] valid; // byte is valid
|
||||
logic [7:0] txblock; // byte is part of transaction in-flight
|
||||
logic checked; // if cache state of this word has been checked
|
||||
logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] hit_oh; // valid way in the cache
|
||||
logic [ariane_pkg::DCACHE_TAG_WIDTH+(ariane_pkg::DCACHE_INDEX_WIDTH-riscv::XLEN_ALIGN_BYTES)-1:0] wtag;
|
||||
riscv::xlen_t data;
|
||||
logic [(riscv::XLEN/8)-1:0] dirty; // byte is dirty
|
||||
logic [(riscv::XLEN/8)-1:0] valid; // byte is valid
|
||||
logic [(riscv::XLEN/8)-1:0] txblock; // byte is part of transaction in-flight
|
||||
logic checked; // if cache state of this word has been checked
|
||||
logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] hit_oh; // valid way in the cache
|
||||
} wbuffer_t;
|
||||
|
||||
// TX status registers are indexed with the transaction ID
|
||||
// they basically store which bytes from which buffer entry are part
|
||||
// of that transaction
|
||||
|
||||
typedef struct packed {
|
||||
logic vld;
|
||||
logic [7:0] be;
|
||||
logic [(riscv::XLEN/8)-1:0] be;
|
||||
logic [$clog2(DCACHE_WBUF_DEPTH)-1:0] ptr;
|
||||
} tx_stat_t;
|
||||
|
||||
|
@ -149,7 +150,7 @@ package wt_cache_pkg;
|
|||
logic [2:0] size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte)
|
||||
logic [L1D_WAY_WIDTH-1:0] way; // way to replace
|
||||
logic [riscv::PLEN-1:0] paddr; // physical address
|
||||
logic [63:0] data; // word width of processor (no block stores at the moment)
|
||||
riscv::xlen_t data; // word width of processor (no block stores at the moment)
|
||||
logic nc; // noncacheable
|
||||
logic [CACHE_ID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane)
|
||||
ariane_pkg::amo_t amo_op; // amo opcode
|
||||
|
@ -296,7 +297,7 @@ package wt_cache_pkg;
|
|||
return cnt;
|
||||
endfunction : popcnt64
|
||||
|
||||
function automatic logic [7:0] toByteEnable8(
|
||||
function automatic logic [7:0] to_byte_enable8(
|
||||
input logic [2:0] offset,
|
||||
input logic [1:0] size
|
||||
);
|
||||
|
@ -309,7 +310,21 @@ package wt_cache_pkg;
|
|||
default: be = '1; // dword
|
||||
endcase // size
|
||||
return be;
|
||||
endfunction : toByteEnable8
|
||||
endfunction : to_byte_enable8
|
||||
|
||||
function automatic logic [3:0] to_byte_enable4(
|
||||
input logic [1:0] offset,
|
||||
input logic [1:0] size
|
||||
);
|
||||
logic [3:0] be;
|
||||
be = '0;
|
||||
unique case(size)
|
||||
2'b00: be[offset] = '1; // byte
|
||||
2'b01: be[offset +:2 ] = '1; // hword
|
||||
default: be = '1; // word
|
||||
endcase // size
|
||||
return be;
|
||||
endfunction : to_byte_enable4
|
||||
|
||||
// openpiton requires the data to be replicated in case of smaller sizes than dwords
|
||||
function automatic logic [63:0] repData64(
|
||||
|
@ -326,6 +341,20 @@ package wt_cache_pkg;
|
|||
endcase // size
|
||||
return out;
|
||||
endfunction : repData64
|
||||
|
||||
function automatic logic [31:0] repData32(
|
||||
input logic [31:0] data,
|
||||
input logic [1:0] offset,
|
||||
input logic [1:0] size
|
||||
);
|
||||
logic [31:0] out;
|
||||
unique case(size)
|
||||
2'b00: for(int k=0; k<4; k++) out[k*8 +: 8] = data[offset*8 +: 8]; // byte
|
||||
2'b01: for(int k=0; k<2; k++) out[k*16 +: 16] = data[offset*8 +: 16]; // hword
|
||||
default: out = data; // word
|
||||
endcase // size
|
||||
return out;
|
||||
endfunction : repData32
|
||||
|
||||
// note: this is openpiton specific. cannot transmit unaligned words.
|
||||
// hence we default to individual bytes in that case, and they have to be transmitted
|
||||
|
@ -342,6 +371,19 @@ package wt_cache_pkg;
|
|||
endcase // be
|
||||
return size;
|
||||
endfunction : toSize64
|
||||
|
||||
|
||||
function automatic logic [1:0] toSize32(
|
||||
input logic [3:0] be
|
||||
);
|
||||
logic [1:0] size;
|
||||
unique case(be)
|
||||
4'b1111: size = 2'b10; // word
|
||||
4'b1100, 4'b0011: size = 2'b01; // hword
|
||||
default: size = 2'b00; // individual bytes
|
||||
endcase // be
|
||||
return size;
|
||||
endfunction : toSize32
|
||||
|
||||
// align the physical address to the specified size:
|
||||
// 000: bytes
|
||||
|
|
|
@ -89,10 +89,10 @@ module load_store_unit import ariane_pkg::*; #(
|
|||
// Address Generation Unit (AGU)
|
||||
// ------------------------------
|
||||
// virtual address as calculated by the AGU in the first cycle
|
||||
logic [riscv::VLEN-1:0] vaddr_i;
|
||||
riscv::xlen_t vaddr_xlen;
|
||||
logic overflow;
|
||||
logic [7:0] be_i;
|
||||
logic [riscv::VLEN-1:0] vaddr_i;
|
||||
riscv::xlen_t vaddr_xlen;
|
||||
logic overflow;
|
||||
logic [(riscv::XLEN/8)-1:0] be_i;
|
||||
|
||||
assign vaddr_xlen = $unsigned($signed(fu_data_i.imm) + $signed(fu_data_i.operand_a));
|
||||
assign vaddr_i = vaddr_xlen[riscv::VLEN-1:0];
|
||||
|
@ -195,9 +195,9 @@ module load_store_unit import ariane_pkg::*; #(
|
|||
|
||||
assign dcache_req_ports_o[0].address_index = '0;
|
||||
assign dcache_req_ports_o[0].address_tag = '0;
|
||||
assign dcache_req_ports_o[0].data_wdata = 64'b0;
|
||||
assign dcache_req_ports_o[0].data_wdata = '0;
|
||||
assign dcache_req_ports_o[0].data_req = 1'b0;
|
||||
assign dcache_req_ports_o[0].data_be = 8'hFF;
|
||||
assign dcache_req_ports_o[0].data_be = '1;
|
||||
assign dcache_req_ports_o[0].data_size = 2'b11;
|
||||
assign dcache_req_ports_o[0].data_we = 1'b0;
|
||||
assign dcache_req_ports_o[0].kill_req = '0;
|
||||
|
@ -352,7 +352,8 @@ module load_store_unit import ariane_pkg::*; #(
|
|||
// 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(fu_data_i.operator));
|
||||
assign be_i = riscv::IS_XLEN64 ? be_gen(vaddr_i[2:0], extract_transfer_size(fu_data_i.operator)):
|
||||
be_gen_32(vaddr_i[1:0], extract_transfer_size(fu_data_i.operator));
|
||||
|
||||
// ------------------------
|
||||
// Misaligned Exception
|
||||
|
@ -446,7 +447,7 @@ module load_store_unit import ariane_pkg::*; #(
|
|||
// new data arrives here
|
||||
lsu_ctrl_t lsu_req_i;
|
||||
|
||||
assign lsu_req_i = {lsu_valid_i, vaddr_i, overflow, {{64-riscv::XLEN{1'b0}}, fu_data_i.operand_b}, be_i, fu_data_i.fu, fu_data_i.operator, fu_data_i.trans_id};
|
||||
assign lsu_req_i = {lsu_valid_i, vaddr_i, overflow, fu_data_i.operand_b, be_i, fu_data_i.fu, fu_data_i.operator, fu_data_i.trans_id};
|
||||
|
||||
lsu_bypass lsu_bypass_i (
|
||||
.lsu_req_i ( lsu_req_i ),
|
||||
|
|
|
@ -52,9 +52,9 @@ module load_unit import ariane_pkg::*; #(
|
|||
// in order to decouple the response interface from the request interface we need a
|
||||
// a queue which can hold all outstanding memory requests
|
||||
struct packed {
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic [2:0] address_offset;
|
||||
fu_op operator;
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] address_offset;
|
||||
fu_op operator;
|
||||
} load_data_d, load_data_q, in_data;
|
||||
|
||||
// page offset is defined as the lower 12 bits, feed through for address checker
|
||||
|
@ -65,7 +65,7 @@ module load_unit import ariane_pkg::*; #(
|
|||
assign req_port_o.data_we = 1'b0;
|
||||
assign req_port_o.data_wdata = '0;
|
||||
// compose the queue data, control is handled in the FSM
|
||||
assign in_data = {lsu_ctrl_i.trans_id, lsu_ctrl_i.vaddr[2:0], lsu_ctrl_i.operator};
|
||||
assign in_data = {lsu_ctrl_i.trans_id, lsu_ctrl_i.vaddr[riscv::XLEN_ALIGN_BYTES-1:0], lsu_ctrl_i.operator};
|
||||
// output address
|
||||
// we can now output the lower 12 bit as the index to the cache
|
||||
assign req_port_o.address_index = lsu_ctrl_i.vaddr[ariane_pkg::DCACHE_INDEX_WIDTH-1:0];
|
||||
|
@ -313,7 +313,7 @@ module load_unit import ariane_pkg::*; #(
|
|||
// ---------------
|
||||
// Sign Extend
|
||||
// ---------------
|
||||
logic [63:0] shifted_data;
|
||||
riscv::xlen_t shifted_data;
|
||||
|
||||
// realign as needed
|
||||
assign shifted_data = req_port_i.data_rdata >> {load_data_q.address_offset, 3'b000};
|
||||
|
@ -333,27 +333,24 @@ module load_unit import ariane_pkg::*; #(
|
|||
end */
|
||||
|
||||
// result mux fast
|
||||
logic [7:0] sign_bits;
|
||||
logic [2:0] idx_d, idx_q;
|
||||
logic [(riscv::XLEN/8)-1:0] sign_bits;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] idx_d, idx_q;
|
||||
logic sign_bit, signed_d, signed_q, fp_sign_d, fp_sign_q;
|
||||
|
||||
|
||||
// prepare these signals for faster selection in the next cycle
|
||||
assign signed_d = load_data_d.operator inside {ariane_pkg::LW, ariane_pkg::LH, ariane_pkg::LB};
|
||||
assign fp_sign_d = load_data_d.operator inside {ariane_pkg::FLW, ariane_pkg::FLH, ariane_pkg::FLB};
|
||||
assign idx_d = (load_data_d.operator inside {ariane_pkg::LW, ariane_pkg::FLW}) ? load_data_d.address_offset + 3 :
|
||||
|
||||
assign idx_d = ((load_data_d.operator inside {ariane_pkg::LW, ariane_pkg::FLW}) & riscv::IS_XLEN64) ? load_data_d.address_offset + 3 :
|
||||
(load_data_d.operator inside {ariane_pkg::LH, ariane_pkg::FLH}) ? load_data_d.address_offset + 1 :
|
||||
load_data_d.address_offset;
|
||||
|
||||
|
||||
assign sign_bits = { req_port_i.data_rdata[63],
|
||||
req_port_i.data_rdata[55],
|
||||
req_port_i.data_rdata[47],
|
||||
req_port_i.data_rdata[39],
|
||||
req_port_i.data_rdata[31],
|
||||
req_port_i.data_rdata[23],
|
||||
req_port_i.data_rdata[15],
|
||||
req_port_i.data_rdata[7] };
|
||||
for (genvar i = 0; i < (riscv::XLEN/8); i++) begin : gen_sign_bits
|
||||
assign sign_bits[i] = req_port_i.data_rdata[(i+1)*8-1];
|
||||
end
|
||||
|
||||
|
||||
// select correct sign bit in parallel to result shifter above
|
||||
// pull to 0 if unsigned
|
||||
|
|
|
@ -80,12 +80,11 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
|
||||
// input registers
|
||||
logic data_rvalid_q;
|
||||
logic [31:0] data_rdata_q, data_rdata_n;
|
||||
riscv::xlen_t data_rdata_q;
|
||||
|
||||
riscv::pte_sv32_t pte;
|
||||
assign pte = riscv::pte_sv32_t'(data_rdata_q);
|
||||
|
||||
assign data_rdata_n = (req_port_o.address_index[2] == 1'b1) ? req_port_i.data_rdata[63:32] : req_port_i.data_rdata[31:0];
|
||||
|
||||
enum logic[2:0] {
|
||||
IDLE,
|
||||
|
@ -124,7 +123,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
// we are never going to kill this request
|
||||
assign req_port_o.kill_req = '0;
|
||||
// we are never going to write with the HPTW
|
||||
assign req_port_o.data_wdata = 64'b0;
|
||||
assign req_port_o.data_wdata = '0;
|
||||
// -----------
|
||||
// TLB Update
|
||||
// -----------
|
||||
|
@ -163,7 +162,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
);
|
||||
|
||||
|
||||
assign req_port_o.data_be = be_gen(req_port_o.address_index[2:0],req_port_o.data_size );
|
||||
assign req_port_o.data_be = be_gen_32(req_port_o.address_index[1:0],req_port_o.data_size );
|
||||
|
||||
//-------------------
|
||||
// Page table walker
|
||||
|
@ -399,7 +398,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
tlb_update_asid_q <= tlb_update_asid_n;
|
||||
vaddr_q <= vaddr_n;
|
||||
global_mapping_q <= global_mapping_n;
|
||||
data_rdata_q <= data_rdata_n;
|
||||
data_rdata_q <= req_port_i.data_rdata;
|
||||
data_rvalid_q <= req_port_i.data_rvalid;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ module store_buffer import ariane_pkg::*; (
|
|||
|
||||
input logic [riscv::PLEN-1:0] paddr_i, // physical address of store which needs to be placed in the queue
|
||||
input riscv::xlen_t data_i, // data which is placed in the queue
|
||||
input logic [7:0] be_i, // byte enable in
|
||||
input logic [(riscv::XLEN/8)-1:0] be_i, // byte enable in
|
||||
input logic [1:0] data_size_i, // type of request we are making (e.g.: bytes to write)
|
||||
|
||||
// D$ interface
|
||||
|
@ -47,11 +47,11 @@ module store_buffer import ariane_pkg::*; (
|
|||
// 1. Speculative queue
|
||||
// 2. Commit queue which is non-speculative, e.g.: the store will definitely happen.
|
||||
struct packed {
|
||||
logic [riscv::PLEN-1:0] address;
|
||||
riscv::xlen_t data;
|
||||
logic [7:0] be;
|
||||
logic [1:0] data_size;
|
||||
logic valid; // this entry is valid, we need this for checking if the address offset matches
|
||||
logic [riscv::PLEN-1:0] address;
|
||||
riscv::xlen_t data;
|
||||
logic [(riscv::XLEN/8)-1:0] be;
|
||||
logic [1:0] data_size;
|
||||
logic valid; // this entry is valid, we need this for checking if the address offset matches
|
||||
} speculative_queue_n [DEPTH_SPEC-1:0], speculative_queue_q [DEPTH_SPEC-1:0],
|
||||
commit_queue_n [DEPTH_COMMIT-1:0], commit_queue_q [DEPTH_COMMIT-1:0];
|
||||
|
||||
|
@ -133,8 +133,7 @@ module store_buffer import ariane_pkg::*; (
|
|||
assign req_port_o.address_tag = commit_queue_q[commit_read_pointer_q].address[ariane_pkg::DCACHE_TAG_WIDTH +
|
||||
ariane_pkg::DCACHE_INDEX_WIDTH-1 :
|
||||
ariane_pkg::DCACHE_INDEX_WIDTH];
|
||||
assign req_port_o.data_wdata = (req_port_o.address_index[2] == 1'b0) ? {{64-riscv::XLEN{1'b0}}, commit_queue_q[commit_read_pointer_q].data} :
|
||||
{commit_queue_q[commit_read_pointer_q].data, {64-riscv::XLEN{1'b0}}};
|
||||
assign req_port_o.data_wdata = commit_queue_q[commit_read_pointer_q].data;
|
||||
assign req_port_o.data_be = commit_queue_q[commit_read_pointer_q].be;
|
||||
assign req_port_o.data_size = commit_queue_q[commit_read_pointer_q].data_size;
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ module store_unit import ariane_pkg::*; (
|
|||
assign instr_is_amo = is_amo(lsu_ctrl_i.operator);
|
||||
// keep the data and the byte enable for the second cycle (after address translation)
|
||||
riscv::xlen_t st_data_n, st_data_q;
|
||||
logic [7:0] st_be_n, st_be_q;
|
||||
logic [(riscv::XLEN/8)-1:0] st_be_n, st_be_q;
|
||||
logic [1:0] st_data_size_n, st_data_size_q;
|
||||
amo_t amo_op_d, amo_op_q;
|
||||
|
||||
|
@ -181,7 +181,7 @@ module store_unit import ariane_pkg::*; (
|
|||
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]
|
||||
: data_align(lsu_ctrl_i.vaddr[2:0], {{64-riscv::XLEN{1'b0}}, 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.operator);
|
||||
// save AMO op for next cycle
|
||||
case (lsu_ctrl_i.operator)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue