amoadd.d riscv tests passing

This commit is contained in:
Florian Zaruba 2018-09-21 18:50:26 +02:00
parent 3b75716a59
commit e3c446e40d
No known key found for this signature in database
GPG key ID: E742FFE8EC38A792
13 changed files with 288 additions and 173 deletions

View file

@ -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

View file

@ -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

View file

@ -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 ),
.*

View file

@ -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;

View file

@ -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;

View file

@ -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
// -----------------

View file

@ -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 ),

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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");

View file

@ -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;