Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to latest CLIC spec (Version 0.9-draft, 4/11/2023) #859

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion bhv/cv32e40x_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ module cv32e40x_wrapper
core_i.if_stage_i cv32e40x_if_stage_sva #(.CLIC(CLIC)) if_stage_sva
(
.m_c_obi_instr_if (core_i.m_c_obi_instr_if), // SVA monitor modport cannot connect to a master modport
.align_err_i (core_i.if_stage_i.align_check_i.align_err),
.*
);

Expand Down
20 changes: 2 additions & 18 deletions rtl/cv32e40x_alignment_buffer.sv
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
// Error propagation signals for bus, mpu and alignment checker (pointers)
logic bus_err_unaligned, bus_err;
mpu_status_e mpu_status_unaligned, mpu_status;
align_status_e align_status_unaligned, align_status;

// resp_valid gated while flushing
logic resp_valid_gated;
Expand Down Expand Up @@ -167,7 +166,6 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
assign instr = (valid_q[rptr]) ? resp_q[rptr].bus_resp.rdata : resp_i.bus_resp.rdata;
assign bus_err = (valid_q[rptr]) ? resp_q[rptr].bus_resp.err : resp_i.bus_resp.err;
assign mpu_status = (valid_q[rptr]) ? resp_q[rptr].mpu_status : resp_i.mpu_status;
assign align_status = (valid_q[rptr]) ? resp_q[rptr].align_status : resp_i.align_status;


// Unaligned instructions will either be split across index 0 and 1, or index 0 and incoming data
Expand All @@ -190,10 +188,9 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
!(instr_is_clic_ptr_o || instr_is_mret_ptr_o || instr_is_tbljmp_ptr_o);


// Set mpu_status, align_status and bus error for unaligned instructions
// Set mpu_status and bus error for unaligned instructions
always_comb begin
mpu_status_unaligned = MPU_OK;
align_status_unaligned = ALIGN_OK;
bus_err_unaligned = 1'b0;
// There is valid data in q1 (valid q0 is implied)
if(valid_q[rptr2]) begin
Expand All @@ -204,18 +201,12 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
mpu_status_unaligned = MPU_RE_FAULT;
end

if((resp_q[rptr2].align_status != ALIGN_OK) || (resp_q[rptr].align_status != ALIGN_OK)) begin
align_status_unaligned = ALIGN_RE_ERR;
end

// Bus error from either entry
bus_err_unaligned = (resp_q[rptr2].bus_resp.err || resp_q[rptr].bus_resp.err);
end else begin
// Compressed, use only mpu_status from q0
mpu_status_unaligned = resp_q[rptr].mpu_status;

align_status_unaligned = resp_q[rptr].align_status;

// bus error from q0
bus_err_unaligned = resp_q[rptr].bus_resp.err;
end
Expand All @@ -229,24 +220,19 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
mpu_status_unaligned = MPU_RE_FAULT;
end

if((resp_q[rptr].align_status != ALIGN_OK) || (resp_i.align_status != ALIGN_OK)) begin
align_status_unaligned = ALIGN_RE_ERR;
end

// Bus error from q0 and resp_i
bus_err_unaligned = (resp_q[rptr].bus_resp.err || resp_i.bus_resp.err);
end else begin
// There is unaligned data in q0 and it is compressed
mpu_status_unaligned = resp_q[rptr].mpu_status;
align_status_unaligned = resp_q[rptr].align_status;

// Bus error from q0
bus_err_unaligned = resp_q[rptr].bus_resp.err;
end
end else begin
// There is no data in the buffer, use input
mpu_status_unaligned = resp_i.mpu_status;
bus_err_unaligned = resp_i.bus_resp.err;
align_status_unaligned = resp_i.align_status;
end
end
end
Expand All @@ -258,7 +244,6 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
instr_instr_o.bus_resp.rdata = instr;
instr_instr_o.bus_resp.err = bus_err;
instr_instr_o.mpu_status = mpu_status;
instr_instr_o.align_status = align_status;
instr_valid_o = 1'b0;

// Invalidate output if we get killed
Expand All @@ -269,7 +254,6 @@ module cv32e40x_alignment_buffer import cv32e40x_pkg::*;
instr_instr_o.bus_resp.rdata = instr_unaligned;
instr_instr_o.bus_resp.err = bus_err_unaligned;
instr_instr_o.mpu_status = mpu_status_unaligned;
instr_instr_o.align_status = align_status_unaligned;

if (!valid) begin
// No instruction valid
Expand Down
2 changes: 1 addition & 1 deletion rtl/cv32e40x_controller_bypass.sv
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ module cv32e40x_controller_bypass import cv32e40x_pkg::*;
// Also deassert for trigger match, as with dcsr.timing==0 we do not execute before entering debug mode
// CLIC pointer fetches go through the pipeline, but no write enables should be active.
if (if_id_pipe_i.instr.bus_resp.err || !(if_id_pipe_i.instr.mpu_status == MPU_OK) || if_id_pipe_i.trigger_match ||
if_id_pipe_i.instr_meta.clic_ptr || if_id_pipe_i.instr_meta.mret_ptr || !(if_id_pipe_i.instr.align_status == ALIGN_OK)) begin
if_id_pipe_i.instr_meta.clic_ptr || if_id_pipe_i.instr_meta.mret_ptr) begin
ctrl_byp_o.deassert_we = 1'b1;
end

Expand Down
4 changes: 1 addition & 3 deletions rtl/cv32e40x_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,6 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
// M | 1 | 1 | Debug entry (restart from dm_halt_addr_i)
//
assign exception_in_wb = ((ex_wb_pipe_i.instr.mpu_status != MPU_OK) ||
(ex_wb_pipe_i.instr.align_status != ALIGN_OK) ||
ex_wb_pipe_i.instr.bus_resp.err ||
ex_wb_pipe_i.illegal_insn ||
(ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ecall_insn) ||
Expand All @@ -350,7 +349,6 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;

// Set exception cause
assign exception_cause_wb = (ex_wb_pipe_i.instr.mpu_status != MPU_OK) ? EXC_CAUSE_INSTR_FAULT :
(ex_wb_pipe_i.instr.align_status != ALIGN_OK) ? EXC_CAUSE_INSTR_MISALIGNED :
ex_wb_pipe_i.instr.bus_resp.err ? EXC_CAUSE_INSTR_BUS_FAULT :
ex_wb_pipe_i.illegal_insn ? EXC_CAUSE_ILLEGAL_INSN :
(ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ecall_insn) ? EXC_CAUSE_ECALL_MMODE :
Expand Down Expand Up @@ -1031,7 +1029,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
branch_taken_n = 1'b1;
end
end else if (clic_ptr_in_id || mret_ptr_in_id) begin
if (!(if_id_pipe_i.instr.bus_resp.err || (if_id_pipe_i.instr.mpu_status != MPU_OK) || (if_id_pipe_i.instr.align_status != ALIGN_OK))) begin
if (!(if_id_pipe_i.instr.bus_resp.err || (if_id_pipe_i.instr.mpu_status != MPU_OK))) begin
if (!branch_taken_q) begin
ctrl_fsm_o.pc_set = 1'b1;
ctrl_fsm_o.pc_mux = PC_POINTER;
Expand Down
12 changes: 12 additions & 0 deletions rtl/cv32e40x_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,12 @@ dcsr_we = 1'b1;
mcause_n.mpie = mstatus_n.mpie;
mcause_we = 1'b1;

// Mret to lower privilege mode clear mintthresh
if (priv_lvl_n < PRIV_LVL_M) begin
mintthresh_n = 32'h00000000;
mintthresh_we = 1'b1;
end

if (ctrl_fsm_i.csr_restore_mret_ptr) begin
// Clear mcause.minhv if the mret also caused a successful CLIC pointer fetch
mcause_n.minhv = 1'b0;
Expand All @@ -1137,6 +1143,12 @@ dcsr_we = 1'b1;
// Not really needed, but allows for asserting mstatus_we == mcause_we to check aliasing formally
mcause_n = mcause_rdata;
mcause_we = 1'b1;

// Dret to lower privilege mode clear mintthresh
if (priv_lvl_n < PRIV_LVL_M) begin
mintthresh_n = 32'h00000000;
mintthresh_we = 1'b1;
end
end

end //ctrl_fsm_i.csr_restore_dret
Expand Down
1 change: 0 additions & 1 deletion rtl/cv32e40x_ex_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ module cv32e40x_ex_stage import cv32e40x_pkg::*;
assign previous_exception = (id_ex_pipe_i.illegal_insn ||
id_ex_pipe_i.instr.bus_resp.err ||
(id_ex_pipe_i.instr.mpu_status != MPU_OK) ||
(id_ex_pipe_i.instr.align_status != ALIGN_OK) ||
|id_ex_pipe_i.trigger_match) &&
id_ex_pipe_i.instr_valid;

Expand Down
1 change: 0 additions & 1 deletion rtl/cv32e40x_id_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ module cv32e40x_id_stage import cv32e40x_pkg::*;
id_ex_pipe_o.instr.bus_resp.rdata <= {16'h0, if_id_pipe_i.compressed_instr};
id_ex_pipe_o.instr.bus_resp.err <= if_id_pipe_i.instr.bus_resp.err;
id_ex_pipe_o.instr.mpu_status <= if_id_pipe_i.instr.mpu_status;
id_ex_pipe_o.instr.align_status <= if_id_pipe_i.instr.align_status;
end else begin
id_ex_pipe_o.instr <= if_id_pipe_i.instr;
end
Expand Down
68 changes: 11 additions & 57 deletions rtl/cv32e40x_if_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
logic prefetch_trans_valid;
logic prefetch_trans_ready;
logic [31:0] prefetch_trans_addr;
logic prefetch_trans_ptr;
inst_resp_t prefetch_inst_resp;
logic prefetch_one_txn_pend_n;
logic [ALBUF_CNT_WIDTH-1:0] prefetch_outstnd_cnt_q;
Expand All @@ -129,15 +128,6 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
obi_inst_req_t bus_trans;
obi_inst_req_t core_trans;

logic alcheck_resp_valid;
inst_resp_t alcheck_resp;
logic alcheck_trans_valid;
logic alcheck_trans_ready;
obi_inst_req_t alcheck_trans;

logic align_check_en;
logic address_misaligned;

// Local instr_valid
logic instr_valid;

Expand Down Expand Up @@ -169,7 +159,9 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
PC_BOOT: branch_addr_n = {boot_addr_i[31:2], 2'b0};
PC_JUMP: branch_addr_n = jump_target_id_i;
PC_BRANCH: branch_addr_n = branch_target_ex_i;
PC_MRET: branch_addr_n = mepc_i; // PC is restored when returning from IRQ/exception
// An mret that restarts a CLIC pointer fetch must make sure the address is aligned to XLEN/8.
// Clearing branch_addr_n[1] when an mepc is used as part of CLIC pointer fetch.
PC_MRET: branch_addr_n = {mepc_i[31:2], (mepc_i[1] & !ctrl_fsm_i.pc_set_clicv), mepc_i[0]}; // PC is restored when returning from IRQ/exception
PC_DRET: branch_addr_n = dpc_i;
PC_WB_PLUS4: branch_addr_n = ctrl_fsm_i.pipe_pc; // Jump to next instruction forces prefetch buffer reload
PC_TRAP_EXC: branch_addr_n = {mtvec_addr_i, 7'h0}; // All the exceptions go to base address
Expand Down Expand Up @@ -218,7 +210,6 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
.trans_valid_o ( prefetch_trans_valid ),
.trans_ready_i ( prefetch_trans_ready ),
.trans_addr_o ( prefetch_trans_addr ),
.trans_ptr_o ( prefetch_trans_ptr ),

.resp_valid_i ( prefetch_resp_valid ),
.resp_i ( prefetch_inst_resp ),
Expand All @@ -245,7 +236,7 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
.A_EXT ( A_EXT ),
.CORE_REQ_TYPE ( obi_inst_req_t ),
.CORE_RESP_TYPE ( inst_resp_t ),
.BUS_RESP_TYPE ( inst_resp_t ),
.BUS_RESP_TYPE ( obi_inst_resp_t ),
.PMA_NUM_REGIONS ( PMA_NUM_REGIONS ),
.PMA_CFG ( PMA_CFG ),
.DEBUG ( DEBUG ),
Expand All @@ -271,49 +262,14 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
.core_resp_valid_o ( prefetch_resp_valid ),
.core_resp_o ( prefetch_inst_resp ),

.bus_trans_valid_o ( alcheck_trans_valid ),
.bus_trans_ready_i ( alcheck_trans_ready ),
.bus_trans_o ( alcheck_trans ),
.bus_resp_valid_i ( alcheck_resp_valid ),
.bus_resp_i ( alcheck_resp )
.bus_trans_valid_o ( bus_trans_valid ),
.bus_trans_ready_i ( bus_trans_ready ),
.bus_trans_o ( bus_trans ),
.bus_resp_valid_i ( bus_resp_valid ),
.bus_resp_i ( bus_resp )
);


assign align_check_en = prefetch_trans_ptr;
assign address_misaligned = |prefetch_trans_addr[1:0];

cv32e40x_align_check
#(
.IF_STAGE ( 1 ),
.CORE_RESP_TYPE ( inst_resp_t ),
.BUS_RESP_TYPE ( obi_inst_resp_t ),
.CORE_REQ_TYPE ( obi_inst_req_t )
)
align_check_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.align_check_en_i ( align_check_en ),
.misaligned_access_i ( address_misaligned ),

.core_one_txn_pend_n ( prefetch_one_txn_pend_n ),
.core_align_err_wait_i( 1'b1 ),
.core_align_err_o ( ), // Unconnected on purpose

.core_trans_valid_i ( alcheck_trans_valid ),
.core_trans_ready_o ( alcheck_trans_ready ),
.core_trans_i ( alcheck_trans ),
.core_resp_valid_o ( alcheck_resp_valid ),
.core_resp_o ( alcheck_resp ),

.bus_trans_valid_o ( bus_trans_valid ),
.bus_trans_ready_i ( bus_trans_ready ),
.bus_trans_o ( bus_trans ),
.bus_resp_valid_i ( bus_resp_valid ),
.bus_resp_i ( bus_resp )

);

//////////////////////////////////////////////////////////////////////////////
// OBI interface
//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -380,8 +336,7 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;


// Set flag to indicate that instruction/sequence will be aborted due to known exceptions or trigger match
assign abort_op_o = instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK) ||
(instr_decompressed.align_status != ALIGN_OK) || |trigger_match_i;
assign abort_op_o = instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK) || |trigger_match_i;

// Signal current privilege level of IF
assign priv_lvl_if_o = prefetch_priv_lvl;
Expand Down Expand Up @@ -446,7 +401,7 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
// For mret pointers, the pointer address is only needed downstream if the pointer fetch fails.
// If the pointer fetch is successful, the address of the mret (i.e. the previous PC) is needed.
if(prefetch_is_mret_ptr ?
(instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK) || (instr_decompressed.align_status != ALIGN_OK)) :
(instr_decompressed.bus_resp.err || (instr_decompressed.mpu_status != MPU_OK)) :
1'b1) begin
if_id_pipe_o.pc <= pc_if_o;
end
Expand All @@ -470,7 +425,6 @@ module cv32e40x_if_stage import cv32e40x_pkg::*;
// Need to update bus error status and mpu status, but may omit the 32-bit instruction word
if_id_pipe_o.instr.bus_resp.err <= instr_decompressed.bus_resp.err;
if_id_pipe_o.instr.mpu_status <= instr_decompressed.mpu_status;
if_id_pipe_o.instr.align_status <= instr_decompressed.align_status;
end else begin
// Regular instruction, update the whole instr field
if_id_pipe_o.instr <= seq_valid ? seq_instr : instr_decompressed;
Expand Down
20 changes: 11 additions & 9 deletions rtl/cv32e40x_mpu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,8 @@ module cv32e40x_mpu import cv32e40x_pkg::*;

// Forward transaction response towards core
assign core_resp_valid_o = bus_resp_valid_i || mpu_err_trans_valid;
assign core_resp_o.bus_resp = bus_resp_i.bus_resp;
assign core_resp_o.mpu_status = mpu_status;
assign core_resp_o.align_status = bus_resp_i.align_status;


// Report MPU errors to the core immediately
assign core_mpu_err_o = mpu_err;
Expand Down Expand Up @@ -213,15 +212,18 @@ module cv32e40x_mpu import cv32e40x_pkg::*;
// Tie to 1'b0 if this MPU is instantiatied in the IF stage
generate
if (IF_STAGE) begin: mpu_if
assign instr_fetch_access = 1'b1;
assign load_access = 1'b0;
assign core_trans_we = 1'b0;
assign instr_fetch_access = 1'b1;
assign load_access = 1'b0;
assign core_trans_we = 1'b0;
assign core_resp_o.bus_resp = bus_resp_i;
end
else begin: mpu_lsu
assign instr_fetch_access = 1'b0;
assign load_access = !core_trans_i.we;
assign core_trans_we = core_trans_i.we;
assign core_resp_o.wpt_match = '0; // Will be set by upstream wpt-module within load_store_unit
assign instr_fetch_access = 1'b0;
assign load_access = !core_trans_i.we;
assign core_trans_we = core_trans_i.we;
assign core_resp_o.wpt_match = '0; // Will be set by upstream wpt-module within load_store_unit
assign core_resp_o.align_status = bus_resp_i.align_status;
assign core_resp_o.bus_resp = bus_resp_i.bus_resp;
end
endgenerate

Expand Down
4 changes: 1 addition & 3 deletions rtl/cv32e40x_prefetch_unit.sv
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ module cv32e40x_prefetch_unit import cv32e40x_pkg::*;
output logic trans_valid_o,
input logic trans_ready_i,
output logic [31:0] trans_addr_o,
output logic trans_ptr_o,

input logic resp_valid_i,
input inst_resp_t resp_i,
Expand Down Expand Up @@ -100,8 +99,7 @@ module cv32e40x_prefetch_unit import cv32e40x_pkg::*;
.fetch_priv_lvl_access_o ( fetch_priv_lvl_resp ),
.trans_valid_o ( trans_valid_o ),
.trans_ready_i ( trans_ready_i ),
.trans_addr_o ( trans_addr_o ),
.trans_ptr_o ( trans_ptr_o )
.trans_addr_o ( trans_addr_o )
);


Expand Down
5 changes: 1 addition & 4 deletions rtl/cv32e40x_prefetcher.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ module cv32e40x_prefetcher import cv32e40x_pkg::*;
// Transaction request interface
output logic trans_valid_o, // Transaction request valid (to bus interface adapter)
input logic trans_ready_i, // Transaction request ready (transaction gets accepted when trans_valid_o and trans_ready_i are both 1)
output logic [31:0] trans_addr_o, // Transaction address (only valid when trans_valid_o = 1). No stability requirements.
output logic trans_ptr_o // Transaction is fetching a pointer
output logic [31:0] trans_addr_o // Transaction address (only valid when trans_valid_o = 1). No stability requirements.
);


Expand All @@ -79,8 +78,6 @@ module cv32e40x_prefetcher import cv32e40x_pkg::*;
// and will always be ready to accept responses.
assign trans_valid_o = fetch_valid_i;

assign trans_ptr_o = fetch_ptr_access_o;

assign fetch_ready_o = trans_valid_o && trans_ready_i;

// FSM (state_q, next_state) to control trans_addr_o
Expand Down
Loading