Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@
[submodule "vendor/zero-day/axi_tagcontroller"]
path = vendor/zero-day/axi_tagcontroller
url = https://github.com/ninolomata/axi_cheri_tagcontroller.git
[submodule "corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils"]
path = corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils
url = https://github.com/CTSRD-CHERI/RVFI-DII-utils.git
76 changes: 37 additions & 39 deletions core/branch_unit.sv
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright 2025 Bruno Sá and Zero-Day Labs.
// Copyright 2025 Capabilities Limited.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
Expand Down Expand Up @@ -32,6 +33,8 @@ module branch_unit #(
input fu_data_t fu_data_i,
// Instruction PC - ISSUE_STAGE
input logic [CVA6Cfg.PCLEN-1:0] pc_i,
// Instruction stream DII ID - ISSUE_STAGE
input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i,
// Instruction is compressed - ISSUE_STAGE
input logic is_compressed_instr_i,
// any functional unit is valid, check that there is no accidental mis-predict - TO_BE_COMPLETED
Expand All @@ -53,36 +56,47 @@ module branch_unit #(
// Branch exception in - CLU Unit
input exception_t clu_exception_i
);
logic [CVA6Cfg.VLEN-1:0] next_pc_off;
logic [CVA6Cfg.VLEN-1:0] next_pc_addr;
logic [CVA6Cfg.PCLEN-1:0] target_address;
logic [CVA6Cfg.PCLEN-1:0] next_pc;


// CHERI Signals
logic cap_mode;
// Decode input capability operand a and pcc
cva6_cheri_pkg::cap_pcc_t operand_a;
cva6_cheri_pkg::cap_pcc_t pcc;
cva6_cheri_pkg::addrw_t pcc_base;
cva6_cheri_pkg::cap_reg_t pcc;

// Signals for CHERI exception handling
cva6_cheri_pkg::cap_pcc_t target_pcc;
cva6_cheri_pkg::cap_reg_t target_pcc;
cva6_cheri_pkg::cap_meta_data_t target_pcc_meta;
cva6_cheri_pkg::addrw_t target_pcc_base;
cva6_cheri_pkg::addrwe_t target_pcc_top;
cva6_cheri_pkg::addrw_t target_pcc_address;
cva6_cheri_pkg::addrwe_t target_pcc_address_end;
cva6_cheri_pkg::addrwe_t min_instr_off;
logic target_pcc_is_sealed;
assign target_pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::cap_pcc_t'(target_address) : target_address;
assign pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::cap_pcc_t'(pc_i) : pc_i;
assign pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::cap_reg_t'(pc_i) : pc_i;
assign cap_mode = CVA6Cfg.CheriPresent ? (pcc.flags.cap_mode || fu_data_i.operation inside {ariane_pkg::CJALR, ariane_pkg::CINVOKE}) : 1'b0;
assign operand_a = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::cap_reg_to_cap_pcc(fu_data_i.operand_a) : fu_data_i.operand_a;
assign pcc_base = CVA6Cfg.CheriPresent ? pcc.base : '0;
assign target_pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::cap_reg_t'(target_address) : target_address;
assign target_pcc_meta = cva6_cheri_pkg::get_cap_reg_meta_data(target_pcc);
assign target_pcc_base = cva6_cheri_pkg::get_cap_reg_base(target_pcc, target_pcc_meta);
assign target_pcc_top = cva6_cheri_pkg::get_cap_reg_top(target_pcc, target_pcc_meta);
assign min_instr_off = ((CVA6Cfg.RVC) ? {{CVA6Cfg.XLEN-1{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-2{1'b0}}, 3'h4});
assign target_pcc_address = target_pcc.addr;
assign target_pcc_address_end = {1'b0,target_pcc_address} + min_instr_off;

// calculate next PC, depending on whether the instruction is compressed or not this may be different
// TODO(zarubaf): We already calculate this a couple of times, maybe re-use?
assign next_pc_off = ((is_compressed_instr_i) ? {{CVA6Cfg.VLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.VLEN-3{1'b0}}, 3'h4});
assign next_pc_addr = pc_i[CVA6Cfg.VLEN-1:0] + next_pc_off;

// here we handle the various possibilities of mis-predicts
always_comb begin : mispredict_handler
// set the jump base, for JALR we need to look at the register, for all other control flow instructions we can take the current PC
automatic logic [CVA6Cfg.VLEN-1:0] jump_base;
automatic logic [CVA6Cfg.VLEN-1:0] jump_base_addr;
automatic logic [CVA6Cfg.VLEN-1:0] next_pc_off;
automatic logic [CVA6Cfg.VLEN-1:0] next_pc_addr;
automatic cva6_cheri_pkg::cap_pcc_t jump_base_cap;
automatic cva6_cheri_pkg::cap_pcc_t next_pc_tmp, target_address_tmp;
// TODO(zarubaf): The ALU can be used to calculate the branch target
Expand All @@ -101,18 +115,13 @@ module branch_unit #(
resolved_branch_o.valid = branch_valid_i;
resolved_branch_o.is_mispredict = 1'b0;
resolved_branch_o.cf_type = branch_predict_i.cf;
// calculate next PC, depending on whether the instruction is compressed or not this may be different
// TODO(zarubaf): We already calculate this a couple of times, maybe re-use?
next_pc_off = ((is_compressed_instr_i) ? {{CVA6Cfg.VLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.VLEN-3{1'b0}}, 3'h4});
next_pc_addr = pc_i[CVA6Cfg.VLEN-1:0] + next_pc_off;
// Assume that capability is always representable since there is a inbounds check here
next_pc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::set_cap_pcc_cursor(pcc, next_pc_addr) : next_pc_addr;
next_pc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::set_cap_reg_addr(pcc, next_pc_addr) : next_pc_addr;
// calculate target address simple 64 bit addition
if (CVA6Cfg.CheriPresent) begin
target_address = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::set_cap_pcc_cursor(jump_base_cap, jump_base_addr) : '0;
target_address = CVA6Cfg.CheriPresent ? cva6_cheri_pkg::set_cap_reg_address(jump_base_cap, jump_base_addr, cva6_cheri_pkg::get_cap_reg_meta_data(jump_base_cap)) : '0;
end else begin
// calculate target address simple 64 bit addition
target_address = $unsigned($signed(jump_base) + $signed(fu_data_i.imm[CVA6Cfg.VLEN-1:0]));
// calculate target address simple 64 bit addition
target_address = $unsigned($signed(jump_base) + $signed(fu_data_i.imm[CVA6Cfg.VLEN-1:0]));
end
// on a JALR we are supposed to reset the LSB to 0 (according to the specification)
if (fu_data_i.operation inside {ariane_pkg::CINVOKE, ariane_pkg::JALR, ariane_pkg::CJALR}) target_address[0] = 1'b0;
Expand All @@ -132,7 +141,7 @@ module branch_unit #(
next_pc_tmp.otype = cva6_cheri_pkg::UNSEALED_CAP;
end else begin
if (!cap_mode) begin
next_pc_tmp = cva6_cheri_pkg::set_cap_pcc_cursor(cva6_cheri_pkg::PCC_NULL_CAP, next_pc[CVA6Cfg.VLEN-1:0]);
next_pc_tmp = cva6_cheri_pkg::set_cap_reg_addr(cva6_cheri_pkg::PCC_NULL_CAP, next_pc[CVA6Cfg.VLEN-1:0]);
next_pc_tmp.tag = 1'b0;
end else begin
next_pc_tmp = next_pc;
Expand All @@ -144,6 +153,7 @@ module branch_unit #(
branch_result_o = next_pc;
end
resolved_branch_o.pc = pc_i[CVA6Cfg.VLEN-1:0];
if (CVA6Cfg.RVFI_DII) resolved_branch_o.dii_id = dii_id_i;
// There are only two sources of mispredicts:
// 1. Branches
// 2. Jumps to register addresses
Expand Down Expand Up @@ -194,15 +204,10 @@ module branch_unit #(
branch_exception_o.gva = CVA6Cfg.RVH ? v_i : 1'b0;

// Decode target address (next PCC) fields
target_pcc_base = target_pcc.base;
target_pcc_top = target_pcc.top;
target_pcc_address = target_pcc.addr;
target_pcc_is_sealed = (operand_a.otype != cva6_cheri_pkg::UNSEALED_CAP);
// TODO-cheri(ninolomata): fix this once we disable compressed instructions without trigering errors
min_instr_off = ((CVA6Cfg.RVC && !CVA6Cfg.RVFI_DII) ? {{CVA6Cfg.XLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-3{1'b0}}, 3'h4});
// Only throw instruction address misaligned exception if this is indeed a `taken` conditional branch or
// an unconditional jump
if (branch_valid_i && (target_address[0] || ((!CVA6Cfg.RVC || CVA6Cfg.RVFI_DII) && target_address[1])) && jump_taken) begin
if (branch_valid_i && (target_address[0] || (!CVA6Cfg.RVC && target_address[1])) && jump_taken) begin
branch_exception_o.valid = 1'b1;
end
if (CVA6Cfg.CheriPresent && branch_valid_i && jump_taken) begin
Expand All @@ -214,8 +219,8 @@ module branch_unit #(
branch_exception_o.valid = 1'b1;
end
end
// Check if target address is in bounds
if (target_pcc_address < target_pcc_base || ((target_pcc_address + min_instr_off) > target_pcc_top)) begin
// Check if target address is in bounds (or has become unrepresentable)
if (target_pcc_address < target_pcc_base || target_pcc_address_end > target_pcc_top || !target_pcc.tag) begin
branch_exception_o.cause = cva6_cheri_pkg::CAP_EXCEPTION;
cheri_tval.cause = cva6_cheri_pkg::CAP_LENGTH_VIOLATION;
cheri_tval.cap_idx = {6'b100000};
Expand Down Expand Up @@ -245,18 +250,11 @@ module branch_unit #(
end
end
if (CVA6Cfg.CheriPresent && branch_valid_i) begin
// Check PCC bounds every instruction
if(pcc.addr < pcc.base || $unsigned(pcc.addr) > pcc.top) begin
branch_exception_o.cause = cva6_cheri_pkg::CAP_EXCEPTION;
cheri_tval.cause = cva6_cheri_pkg::CAP_LENGTH_VIOLATION;
cheri_tval.cap_idx = {6'b100000};
branch_exception_o.valid = 1'b1;
end
// Update tval
branch_exception_o.tval = cheri_tval;
if (CVA6Cfg.CheriPresent && clu_exception_i.valid && fu_data_i.operation inside {ariane_pkg::CINVOKE}) begin
branch_exception_o = clu_exception_i;
end
// Update tval
branch_exception_o.tval = cheri_tval;
if (clu_exception_i.valid && fu_data_i.operation inside {ariane_pkg::CINVOKE}) begin
branch_exception_o = clu_exception_i;
end
end
end
endmodule
16 changes: 4 additions & 12 deletions core/cache_subsystem/wt_cache_subsystem.sv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright 2025 Capabilities Limited.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
Expand Down Expand Up @@ -33,7 +34,6 @@ module wt_cache_subsystem
parameter type dcache_req_o_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter type rvfi_dii_inst_pack_t = logic,
parameter int unsigned NumPorts = 4,
parameter type noc_req_t = logic,
parameter type noc_resp_t = logic
Expand Down Expand Up @@ -73,11 +73,7 @@ module wt_cache_subsystem
// Invalidations
input logic [63:0] inval_addr_i,
input logic inval_valid_i,
output logic inval_ready_o,
// RVFI_DII Interface
input logic rvfi_dii_rtrn_vld_i,
input rvfi_dii_inst_pack_t rvfi_dii_inst_pack_i,
output logic rvfi_dii_data_ready_o
output logic inval_ready_o
// TODO: interrupt interface
);

Expand Down Expand Up @@ -122,16 +118,12 @@ module wt_cache_subsystem
.CVA6Cfg(CVA6Cfg),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.exception_t (exception_t),
.rvfi_dii_inst_pack_t (rvfi_dii_inst_pack_t)
.exception_t (exception_t)
) i_cva6_rvfi_dii_generator (
.clk_i (clk_i),
.rst_ni (rst_ni),
.dreq_i (icache_dreq_i),
.dreq_o (icache_dreq_o),
.rvfi_dii_rtrn_vld_i (rvfi_dii_rtrn_vld_i),
.rvfi_dii_inst_pack_i (rvfi_dii_inst_pack_i),
.rvfi_dii_data_ready_o (rvfi_dii_data_ready_o)
.dreq_o (icache_dreq_o)
);
assign icache_areq_o = '0;
assign icache_adapter_data_req = '0;
Expand Down
13 changes: 11 additions & 2 deletions core/cheri_unit.sv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2022 Bruno Sá and Zero-Day Labs.
// Copyright 2025 Capabilities Limited.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
Expand Down Expand Up @@ -26,6 +27,7 @@ module cheri_unit import ariane_pkg::*; import cva6_cheri_pkg::*;#(
input logic v_i ,
input fu_data_t fu_data_i,
input cap_pcc_t pcc_i, // Current PCC
input cap_reg_t ddc_i, // Current DDC
input logic clu_valid_i,
input addrw_t alu_result_i,
output cap_reg_t clu_result_o, // Return resulting cap
Expand Down Expand Up @@ -486,8 +488,16 @@ module cheri_unit import ariane_pkg::*; import cva6_cheri_pkg::*;#(
// Decode Cap Operands Fields
// ----------------
always_comb begin
// Decode capability operand a fields
operand_a = fu_data_i.operand_a;
operand_b = fu_data_i.operand_b;
// use the DDC as operand
if (fu_data_i.use_ddc) begin
if (fu_data_i.operation == ariane_pkg::CTO_PTR)
operand_b = ddc_i;
else if (fu_data_i.operation inside{ariane_pkg::CFROM_PTR, ariane_pkg::CTEST_SUBSET, ariane_pkg::CBUILD_CAP})
operand_a = ddc_i;
end
// Decode capability operand a fields
op_a_meta_info = get_cap_reg_meta_data(operand_a);
operand_a_address = operand_a.addr;
operand_a_base = get_cap_reg_base(operand_a, op_a_meta_info);
Expand All @@ -497,7 +507,6 @@ module cheri_unit import ariane_pkg::*; import cva6_cheri_pkg::*;#(
operand_a_is_sealed = (operand_a.otype != UNSEALED_CAP);
is_operand_a_rev_otype = operand_a.otype > OTYPE_MAX;
// Decode capability operand b fields
operand_b = fu_data_i.operand_b;
operand_b_address = operand_b.addr;
op_b_meta_info = get_cap_reg_meta_data(operand_b);
operand_b_base = get_cap_reg_base(operand_b, op_b_meta_info);
Expand Down
8 changes: 7 additions & 1 deletion core/commit_stage.sv
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright 2025 Bruno Sá and Zero-Day Labs.
// Copyright 2025 Capabilities Limited.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
Expand Down Expand Up @@ -33,6 +34,8 @@ module commit_stage
output exception_t exception_o,
// Mark the F state as dirty - CSR_REGFILE
output logic dirty_fp_state_o,
// Last committed DII ID - FRONTEND
output logic [CVA6Cfg.DIIIDLEN-1 : 0] dii_id_o,
// TO_BE_COMPLETED - CSR_REGFILE
input logic single_step_i,
// The instruction we want to commit - ISSUE_STAGE
Expand All @@ -57,6 +60,8 @@ module commit_stage
output logic [CVA6Cfg.NrCommitPorts-1:0][1:0] quarter_o,
// Result of AMO operation - CACHE
input amo_resp_t amo_resp_i,
// Current PCC - ISSUE_STAGE
input logic [CVA6Cfg.PCLEN-1:0] pcc_i,
// TO_BE_COMPLETED - FRONTEND_CSR_REGFILE
output logic [CVA6Cfg.PCLEN-1:0] pc_o,
// Decoded CSR operation - CSR_REGFILE
Expand Down Expand Up @@ -122,7 +127,8 @@ module commit_stage
assign waddr_o[i] = commit_instr_i[i].rd[4:0];
end

assign pc_o = commit_instr_i[0].pc;
assign pc_o = cva6_cheri_pkg::set_cap_reg_addr(pcc_i, commit_instr_i[0].pc);
if (CVA6Cfg.RVFI_DII) assign dii_id_o = commit_instr_i[0].dii_id;
// Dirty the FP state if we are committing anything related to the FPU
always_comb begin : dirty_fp_state
dirty_fp_state_o = 1'b0;
Expand Down
10 changes: 1 addition & 9 deletions core/csr_regfile.sv
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright 2025 Bruno Sá and Zero-Day Labs.
// Copyright 2025 Capabilities Limited.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
Expand Down Expand Up @@ -397,9 +398,6 @@ if (CVA6Cfg.CheriPresent) begin
riscv::CSR_MEPC: begin
wr_cap = mepcc_q;
wr_cap_addr = {csr_wdata[riscv::XLEN-1:1], 1'b0};
// TODO-ninolomata(cheri): fix this
if (CVA6Cfg.RVFI_DII)
wr_cap_addr = {csr_wdata[riscv::XLEN-1:2], 2'b0};
end
riscv::CSR_MTVEC: begin
wr_cap = mtcc_q;
Expand All @@ -417,9 +415,6 @@ if (CVA6Cfg.CheriPresent) begin
riscv::CSR_SEPC: begin
wr_cap = sepcc_q;
wr_cap_addr = {csr_wdata[riscv::XLEN-1:1], 1'b0};
// TODO-ninolomata(cheri): fix this
if (CVA6Cfg.RVFI_DII)
wr_cap_addr = {csr_wdata[riscv::XLEN-1:2], 2'b0};
end
riscv::CSR_STVEC: begin
wr_cap = stcc_q;
Expand Down Expand Up @@ -1218,7 +1213,6 @@ end
sscratchc_d = scr_wdata;
end
cva6_cheri_pkg::SCR_SEPCC: begin
// TODO-cheri(ninolomata):fix this it should clear bit 1 only
sepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:1], 1'b0});
end
cva6_cheri_pkg::SCR_MTCC: begin
Expand All @@ -1237,8 +1231,6 @@ end
mscratchc_d = scr_wdata;
end
cva6_cheri_pkg::SCR_MEPCC: begin
// TODO-cheri(ninolomata):fix this it should clear bit 1 only
//mepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:2], 2'b00});
mepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:1], 1'b0});
end
default: begin
Expand Down
Loading
Loading