diff --git a/.gitmodules b/.gitmodules index ec6a9a8bf..5f3a3cf25 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/core/branch_unit.sv b/core/branch_unit.sv index 4f45494ae..b65992647 100644 --- a/core/branch_unit.sv +++ b/core/branch_unit.sv @@ -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 @@ -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 @@ -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 @@ -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; @@ -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; @@ -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 @@ -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 @@ -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}; @@ -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 diff --git a/core/cache_subsystem/wt_cache_subsystem.sv b/core/cache_subsystem/wt_cache_subsystem.sv index 2cf2492b5..2ac3e549b 100644 --- a/core/cache_subsystem/wt_cache_subsystem.sv +++ b/core/cache_subsystem/wt_cache_subsystem.sv @@ -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 @@ -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 @@ -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 ); @@ -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; diff --git a/core/cheri_unit.sv b/core/cheri_unit.sv index 9027536d5..d27891c46 100644 --- a/core/cheri_unit.sv +++ b/core/cheri_unit.sv @@ -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 @@ -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 @@ -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); @@ -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); diff --git a/core/commit_stage.sv b/core/commit_stage.sv index 62c9afc26..e1b1a5ba3 100644 --- a/core/commit_stage.sv +++ b/core/commit_stage.sv @@ -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 @@ -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 @@ -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 @@ -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; diff --git a/core/csr_regfile.sv b/core/csr_regfile.sv index 57417ce12..29a79df56 100644 --- a/core/csr_regfile.sv +++ b/core/csr_regfile.sv @@ -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 @@ -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; @@ -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; @@ -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 @@ -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 diff --git a/core/cva6.sv b/core/cva6.sv index 632aace06..073d17895 100644 --- a/core/cva6.sv +++ b/core/cva6.sv @@ -1,5 +1,6 @@ // Copyright 2017-2019 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 @@ -30,7 +31,6 @@ module cva6 logic csr; rvfi_probes_instr_t instr; }, - parameter type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg), // branchpredict scoreboard entry // this is the struct which we will inject into the pipeline to guide the various @@ -66,6 +66,7 @@ module cva6 // I$ data requests localparam type icache_dreq_t = struct packed { logic req; // we request a new word + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // next requested DII ID in instruction stream logic kill_s1; // kill the current request logic kill_s2; // kill the last request logic spec; // request is speculative @@ -78,13 +79,15 @@ module cva6 logic [CVA6Cfg.FETCH_WIDTH-1:0] data; // 2+ cycle out: tag logic [CVA6Cfg.FETCH_USER_WIDTH-1:0] user; // User bits logic [CVA6Cfg.VLEN-1:0] vaddr; // virtual address out + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // First DII ID in the returned data exception_t ex; // we've encountered an exception }, // IF/ID Stage // store the decompressed instruction localparam type fetch_entry_t = struct packed { - logic [CVA6Cfg.PCLEN-1:0] address; // the address of the instructions from below + logic [CVA6Cfg.VLEN-1:0] address; // the address of the instructions from below + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // the DII ID of the instruction in the stream logic [31:0] instruction; // instruction word branchpredict_sbe_t branch_predict; // this field contains branch prediction information regarding the forward branch path exception_t ex; // this field contains exceptions which might have happened earlier, e.g.: fetch exceptions @@ -92,8 +95,8 @@ module cva6 // ID/EX/WB Stage localparam type scoreboard_entry_t = struct packed { - logic [CVA6Cfg.PCLEN-1:0] pc; // PC of instruction - logic [CVA6Cfg.REGLEN-1:0] ddc; + logic [CVA6Cfg.VLEN-1:0] pc; // PC of instruction + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // DII ID of the instruction in the stream logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id; // this can potentially be simplified, we could index the scoreboard entry // with the transaction id in any case make the width more generic fu_t fu; // functional unit to use @@ -130,6 +133,7 @@ module cva6 localparam type bp_resolve_t = struct packed { logic valid; // prediction with all its values is valid logic [CVA6Cfg.VLEN-1:0] pc; // PC of predict or mis-predict + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // dii id of branch logic [CVA6Cfg.PCLEN-1:0] target_address; // target address at which to jump, or not logic is_mispredict; // set if this was a mis-predict logic is_taken; // branch is taken @@ -311,9 +315,6 @@ module cva6 input logic debug_req_i, // Probes to build RVFI, can be left open when not used - RVFI output rvfi_probes_t rvfi_probes_o, - 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, // CVXIF request - SUBSYSTEM output cvxif_req_t cvxif_req_o, // CVXIF response - SUBSYSTEM @@ -359,6 +360,7 @@ module cva6 exception_t ex_commit; // exception from commit stage bp_resolve_t resolved_branch; logic [ CVA6Cfg.PCLEN-1:0] pc_commit; + logic [ CVA6Cfg.DIIIDLEN-1:0] dii_id_commit; logic eret; logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack; logic [CVA6Cfg.NrCommitPorts-1:0] commit_macro_ack; @@ -396,6 +398,7 @@ module cva6 fu_data_t fu_data_id_ex; logic [CVA6Cfg.PCLEN-1:0] pc_id_ex; + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_id_ex; logic is_compressed_instr_id_ex; logic [31:0] tinst_ex; // fixed latency units @@ -564,6 +567,7 @@ module cva6 logic flush_csr_ctrl; logic flush_unissued_instr_ctrl_id; logic flush_ctrl_if; + logic [CVA6Cfg.DIIIDLEN-1:0] flush_ctrl_dii_id_if; logic flush_ctrl_id; logic flush_ctrl_ex; logic flush_ctrl_bp; @@ -621,8 +625,7 @@ module cva6 .bp_resolve_t(bp_resolve_t), .fetch_entry_t(fetch_entry_t), .icache_dreq_t(icache_dreq_t), - .icache_drsp_t(icache_drsp_t), - .exception_t(exception_t) + .icache_drsp_t(icache_drsp_t) ) i_frontend ( .flush_i (flush_ctrl_if), // not entirely correct .flush_bp_i (1'b0), @@ -634,6 +637,7 @@ module cva6 .icache_dreq_o (icache_dreq_if_cache), .resolved_branch_i (resolved_branch), .pc_commit_i (pc_commit), + .dii_id_commit_i (dii_id_commit), .set_pc_commit_i (set_pc_ctrl_pcgen), .set_debug_pc_i (set_debug_pc), .epc_i (epc_commit_pcgen), @@ -690,7 +694,7 @@ module cva6 .vtw_i (vtw_csr_id), .tsr_i (tsr_csr_id), .hu_i (hu), - .ddc_i ( ddc ) + .pcc_i (pc_commit) ); logic [CVA6Cfg.NrWbPorts-1:0][CVA6Cfg.TRANS_ID_BITS-1:0] trans_id_ex_id; @@ -785,6 +789,7 @@ module cva6 .rs2_forwarding_o (rs2_forwarding_id_ex), .fu_data_o (fu_data_id_ex), .pc_o (pc_id_ex), + .dii_id_o (dii_id_id_ex), .is_compressed_instr_o (is_compressed_instr_id_ex), .tinst_o (tinst_ex), // fixed latency unit ready @@ -823,6 +828,11 @@ module cva6 .ex_ex_i (ex_ex_ex_id), .wt_valid_i (wt_valid_ex_id), .x_we_i (x_we_ex_id), + .ex_valid_i (ex_commit.valid), + .trap_vector_base_i (trap_vector_base_commit_pcgen), + // CSR + .epc_i (epc_commit_pcgen), + .eret_i (eret), .waddr_i (waddr_commit_id), .wdata_i (wdata_commit_id), @@ -833,6 +843,9 @@ module cva6 .we_fpr_i (we_fpr_commit_id), .commit_instr_o (commit_instr_id_commit), .commit_ack_i (commit_ack), + .pcc_commit_i (pc_commit), + .set_pc_commit_i (set_pc_ctrl_pcgen), + // Performance Counters .stall_issue_o (stall_issue), //RVFI @@ -866,6 +879,7 @@ module cva6 .rs2_forwarding_i(rs2_forwarding_id_ex), .fu_data_i(fu_data_id_ex), .pc_i(pc_id_ex), + .dii_id_i(dii_id_id_ex), .is_compressed_instr_i(is_compressed_instr_id_ex), .tinst_i(tinst_ex), // fixed latency units @@ -1014,7 +1028,9 @@ module cva6 .amo_valid_commit_o(amo_valid_commit), .amo_resp_i (amo_resp), .commit_csr_o (csr_commit_commit_ex), + .pcc_i (pc_id_ex), .pc_o (pc_commit), + .dii_id_o (dii_id_commit), .csr_op_o (csr_op_commit_csr), .csr_wdata_o (csr_wdata_commit_csr), .csr_rdata_i (csr_rdata_csr_commit), @@ -1248,7 +1264,6 @@ module cva6 .dcache_req_i_t(dcache_req_i_t), .dcache_req_o_t(dcache_req_o_t), .exception_t (exception_t), - .rvfi_dii_inst_pack_t(rvfi_dii_inst_pack_t), .NumPorts (NumPorts), .noc_req_t (noc_req_t), .noc_resp_t(noc_resp_t) @@ -1284,10 +1299,7 @@ module cva6 .noc_resp_i (noc_resp_i), .inval_addr_i (inval_addr), .inval_valid_i (inval_valid), - .inval_ready_o (inval_ready), - .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) + .inval_ready_o (inval_ready) ); end else if (CVA6Cfg.DCacheType == config_pkg::HPDCACHE) begin : gen_cache_hpd cva6_hpdcache_subsystem #( diff --git a/core/cva6_rvfi.sv b/core/cva6_rvfi.sv index 7ab1f1710..3d70ba0f1 100644 --- a/core/cva6_rvfi.sv +++ b/core/cva6_rvfi.sv @@ -1,5 +1,6 @@ // Copyright 2024 Thales DIS France SAS // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // // Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -270,32 +271,38 @@ module cva6_rvfi always_ff @(posedge clk_i) begin for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin + logic [31:0] instr; logic exception; + logic [4:0] rd_addr; + logic [4:0] rs2_addr; + instr = mem_q[commit_pointer[i]].instr; exception = commit_instr_valid[i][0] && ex_commit_valid; + rd_addr = commit_instr_rd[i][4:0]; + rs2_addr = (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs2[i][4:0]; rvfi_instr_o[i].valid <= (commit_ack[i] && !ex_commit_valid) || (exception && (ex_commit_cause == riscv::ENV_CALL_MMODE || ex_commit_cause == riscv::ENV_CALL_SMODE || ex_commit_cause == riscv::ENV_CALL_UMODE || ex_commit_cause == cva6_cheri_pkg::CAP_EXCEPTION)); - rvfi_instr_o[i].insn <= mem_q[commit_pointer[i]].instr; + rvfi_instr_o[i].insn <= instr; // when trap, the instruction is not executed rvfi_instr_o[i].trap <= exception; rvfi_instr_o[i].cause <= ex_commit_cause; rvfi_instr_o[i].mode <= (CVA6Cfg.DebugEn && debug_mode) ? 2'b10 : priv_lvl; rvfi_instr_o[i].ixl <= CVA6Cfg.XLEN == 64 ? 2 : 1; rvfi_instr_o[i].rs1_addr <= (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs1[i][4:0]; - rvfi_instr_o[i].rs2_addr <= (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs2[i][4:0]; - rvfi_instr_o[i].rd_addr <= commit_instr_rd[i][4:0]; - rvfi_instr_o[i].rd_wdata <= (rvfi_instr_o[i].rd_addr == 0) ? '0 : (CVA6Cfg.FpPresent && is_rd_fpr( + rvfi_instr_o[i].rs2_addr <= rs2_addr; + rvfi_instr_o[i].rd_addr <= rd_addr; + rvfi_instr_o[i].rd_wdata <= (rd_addr == 0) ? '0 : (CVA6Cfg.FpPresent && is_rd_fpr( commit_instr_op[i] )) ? commit_instr_result[i] : wdata[i]; rvfi_instr_o[i].pc_rdata <= commit_instr_pc[i]; - if (mem_q[commit_pointer[i]].instr == 32'h30200073 && !exception) begin + if (instr == 32'h30200073 && !exception) begin rvfi_instr_o[i].pc_wdata <= csr.mepcc_q[63:0]; - end else if (mem_q[commit_pointer[i]].instr == 32'h10200073 && !exception) begin + end else if (instr == 32'h10200073 && !exception) begin rvfi_instr_o[i].pc_wdata <= csr.sepcc_q[63:0]; end else begin - rvfi_instr_o[i].pc_wdata <= (exception) ? {csr.mtcc_q[63:2], 2'b00} : (commit_instr_fu[i] == CTRL_FLOW) ? commit_instr_next_pc[i] : commit_instr_pc[i] + 4; + rvfi_instr_o[i].pc_wdata <= (exception) ? {csr.mtcc_q[63:2], 2'b00} : (commit_instr_fu[i] == CTRL_FLOW) ? commit_instr_next_pc[i] : commit_instr_pc[i] + (instr[1:0] == 2'b11 ? 4 : 2); end rvfi_instr_o[i].mem_addr <= mem_q[commit_pointer[i]].lsu_addr + ((commit_instr_op[i] == ariane_pkg::CLOAD_TAGS) ? 0 : 0); // So far, only write paddr is reported. TODO: read paddr @@ -305,7 +312,7 @@ module cva6_rvfi rvfi_instr_o[i].mem_rmask <= /* (mem_q[commit_pointer[i]].lsu_wmask == 16'hFFFF) ? '0 : */mem_q[commit_pointer[i]].lsu_rmask >> mem_q[commit_pointer[i]].lsu_addr[3:0]; rvfi_instr_o[i].mem_rdata <= commit_instr_result[i]; rvfi_instr_o[i].rs1_rdata <= mem_q[commit_pointer[i]].rs1_rdata; - rvfi_instr_o[i].rs2_rdata <= (rvfi_instr_o[i].rs2_addr == 0) ? '0 : mem_q[commit_pointer[i]].rs2_rdata; + rvfi_instr_o[i].rs2_rdata <= (rs2_addr == 0) ? '0 : mem_q[commit_pointer[i]].rs2_rdata; end end @@ -422,4 +429,4 @@ module cva6_rvfi endgenerate ; -endmodule \ No newline at end of file +endmodule diff --git a/core/decoder.sv b/core/decoder.sv index bb7a4786e..8c15207d1 100644 --- a/core/decoder.sv +++ b/core/decoder.sv @@ -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 @@ -35,7 +36,8 @@ module decoder input logic debug_req_i, // PC from fetch stage - FRONTEND // TODO-cheri: make cheri optional - input logic [CVA6Cfg.PCLEN-1:0] pc_i, + input logic [CVA6Cfg.VLEN-1:0] pc_i, + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // Is a compressed instruction - compressed_decoder input logic is_compressed_i, // Compressed form of instruction - FRONTEND @@ -82,8 +84,8 @@ module decoder input logic tsr_i, // Hypervisor user mode - CSR_REGFILE input logic hu_i, - // Default Data Capability (DDC) - CSR_REGFILE - input logic [CVA6Cfg.REGLEN-1:0] ddc_i, + // CHERI program counter capability; only used for metadata - ISSUE_STAGE + input logic [CVA6Cfg.PCLEN-1:0] pcc_i, // Instruction to be added to scoreboard entry - ISSUE_STAGE output scoreboard_entry_t instruction_o, // Instruction - ISSUE_STAGE @@ -110,9 +112,10 @@ module decoder logic [31:0] tinst; // capability mode logic cap_mode; + // current pcc metadata (includes address, but not used) cva6_cheri_pkg::cap_pcc_t pcc; // cap mode is equal to PCC.flags.cap_mode - assign pcc = cva6_cheri_pkg::cap_pcc_t'(pc_i); + assign pcc = cva6_cheri_pkg::cap_pcc_t'(pcc_i); assign cap_mode = (CVA6Cfg.CheriPresent) ? pcc.flags.cap_mode : 1'b0; // -------------------- // Immediate select @@ -191,8 +194,8 @@ module decoder instruction_o.use_zimm = 1'b0; instruction_o.bp = branch_predict_i; instruction_o.vfp = 1'b0; + if (CVA6Cfg.RVFI_DII) instruction_o.dii_id = dii_id_i; if (CVA6Cfg.CheriPresent) begin - instruction_o.ddc = ddc_i; instruction_o.use_ddc = 1'b0; instruction_o.clr = 1'b0; instruction_o.mask = '0; diff --git a/core/ex_stage.sv b/core/ex_stage.sv index c1d3999fd..d9d2ac664 100644 --- a/core/ex_stage.sv +++ b/core/ex_stage.sv @@ -1,6 +1,7 @@ // 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 @@ -47,6 +48,8 @@ module ex_stage input fu_data_t fu_data_i, // PC of the current instruction - ISSUE_STAGE input logic [CVA6Cfg.PCLEN-1:0] pc_i, + // DII ID of the current instruction - ISSUE_STAGE + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // DDC of the current instruction - ISSUE_STAGE input logic [CVA6Cfg.REGLEN-1:0] ddc_i, // Report whether isntruction is compressed - ISSUE_STAGE @@ -265,11 +268,12 @@ module ex_stage logic [CVA6Cfg.XLEN-1:0] alu_result, mult_result; logic [CVA6Cfg.REGLEN-1:0] clu_result, csr_result; logic [CVA6Cfg.REGLEN-1:0] branch_result; - logic csr_ready, mult_ready; + logic lsu_ready, csr_ready, mult_ready; logic [CVA6Cfg.TRANS_ID_BITS-1:0] mult_trans_id; logic mult_valid; exception_t branch_exception, clu_exception; - assign flu_exception_o = (clu_valid_i) ? clu_exception : branch_exception; + // Conditioning this on the result of the exception is likely to have timing problems. + assign flu_exception_o = (branch_valid_i) ? branch_exception : clu_exception; cva6_cheri_pkg::cap_pcc_t pcc; assign pcc = cva6_cheri_pkg::cap_pcc_t'(pc_i); @@ -289,7 +293,6 @@ module ex_stage .result_o (alu_result), .alu_branch_res_o(alu_branch_res) ); - // 2. Branch Unit (combinatorial) // we don't silence the branch unit as this is already critical and we do // not want to add another layer of logic @@ -306,9 +309,10 @@ module ex_stage .debug_mode_i, .fu_data_i, .pc_i, + .dii_id_i, .is_compressed_instr_i, // any functional unit is valid, check that there is no accidental mis-predict - .fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i || fpu_valid_i || acc_valid_i ) , + .fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i || fpu_valid_i || acc_valid_i || clu_valid_i) , .branch_valid_i, .branch_comp_res_i(alu_branch_res), .branch_result_o(branch_result), @@ -372,6 +376,7 @@ module ex_stage // ready flags for FLU always_comb begin flu_ready_o = csr_ready & mult_ready; + lsu_ready_o = lsu_ready & csr_ready; end // 4. Multiplication (Sequential) @@ -458,7 +463,7 @@ module ex_stage .fu_data_i (lsu_data), .ddc_i, .cap_mode_i(pcc.flags.cap_mode), - .lsu_ready_o, + .lsu_ready_o(lsu_ready), .lsu_valid_i, .load_trans_id_o, .load_result_o, @@ -564,6 +569,7 @@ module ex_stage .v_i, .fu_data_i ( clu_data ), .pcc_i ( pc_i ), + .ddc_i ( ddc_i ), .clu_valid_i ( clu_valid_i ), .alu_result_i ( alu_result ), .clu_result_o ( clu_result ), diff --git a/core/frontend/frontend.sv b/core/frontend/frontend.sv index ad3058f58..7be3930d7 100644 --- a/core/frontend/frontend.sv +++ b/core/frontend/frontend.sv @@ -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 @@ -22,15 +23,14 @@ module frontend parameter type bp_resolve_t = logic, parameter type fetch_entry_t = logic, parameter type icache_dreq_t = logic, - parameter type icache_drsp_t = logic, - parameter type exception_t = logic + parameter type icache_drsp_t = logic ) ( // Subsystem Clock - SUBSYSTEM input logic clk_i, // Asynchronous reset active low - SUBSYSTEM input logic rst_ni, // Next PC when reset - SUBSYSTEM - input logic [CVA6Cfg.PCLEN-1:0] boot_addr_i, + input logic [CVA6Cfg.VLEN-1:0] boot_addr_i, // Flush branch prediction - zero input logic flush_bp_i, // Flush requested by FENCE, mis-predict and exception - CONTROLLER @@ -41,7 +41,9 @@ module frontend // Set COMMIT PC as next PC requested by FENCE, CSR side-effect and Accelerate port - CONTROLLER input logic set_pc_commit_i, // COMMIT PC - COMMIT - input logic [CVA6Cfg.PCLEN-1:0] pc_commit_i, + input logic [CVA6Cfg.VLEN-1:0] pc_commit_i, + // COMMIT DII ID - COMMIT + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_commit_i, // Exception event - COMMIT input logic ex_valid_i, // Mispredict event and next PC - EXECUTE @@ -49,9 +51,9 @@ module frontend // Return from exception event - CSR input logic eret_i, // Next PC when returning from exception - CSR - input logic [CVA6Cfg.REGLEN-1:0] epc_i, + input logic [CVA6Cfg.VLEN-1:0] epc_i, // Next PC when jumping into exception - CSR - input logic [CVA6Cfg.REGLEN-1:0] trap_vector_base_i, + input logic [CVA6Cfg.VLEN-1:0] trap_vector_base_i, // Debug event - CSR input logic set_debug_pc_i, // Debug mode state - CSR @@ -95,7 +97,7 @@ module frontend logic icache_valid_q; ariane_pkg::frontend_exception_t icache_ex_valid_q; logic [ CVA6Cfg.VLEN-1:0] icache_vaddr_q; - logic [ CVA6Cfg.XLEN-1:0] icache_tval_q; + logic [ CVA6Cfg.DIIIDLEN-1:0] icache_dii_id_q; logic [ CVA6Cfg.GPLEN-1:0] icache_gpaddr_q; logic [ 31:0] icache_tinst_q; logic icache_gva_q; @@ -106,18 +108,20 @@ module frontend bht_prediction_t bht_q; // instruction fetch is ready logic if_ready; - logic [CVA6Cfg.PCLEN-1:0] npc_d, npc_q; // next PC + logic [CVA6Cfg.VLEN-1:0] npc_d, npc_q; // next PC + logic [CVA6Cfg.DIIIDLEN-1:0] ndii_id_d, ndii_id_q; // indicates whether we come out of reset (then we need to load boot_addr_i) logic npc_rst_load_q; logic replay; logic [ CVA6Cfg.VLEN-1:0] replay_addr; + logic [ CVA6Cfg.DIIIDLEN-1:0] replay_dii_id; // shift amount logic [$clog2(CVA6Cfg.INSTR_PER_FETCH)-1:0] shamt; // address will always be 16 bit aligned, make this explicit here - if (CVA6Cfg.RVC && !CVA6Cfg.RVFI_DII) begin : gen_shamt + if (CVA6Cfg.RVC) begin : gen_shamt assign shamt = icache_dreq_i.vaddr[$clog2(CVA6Cfg.INSTR_PER_FETCH):1]; end else begin assign shamt = 1'b0; @@ -135,6 +139,7 @@ module frontend // re-aligned instruction and address (coming from cache - combinationally) logic [CVA6Cfg.INSTR_PER_FETCH-1:0][ 31:0] instr; logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr; + logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instruction_valid; // BHT, BTB and RAS prediction bht_prediction_t [CVA6Cfg.INSTR_PER_FETCH-1:0] bht_prediction; @@ -151,6 +156,7 @@ module frontend // Instruction FIFO logic [ CVA6Cfg.VLEN-1:0] predict_address; + logic [ CVA6Cfg.DIIIDLEN-1:0] predict_dii_id; cf_t [CVA6Cfg.INSTR_PER_FETCH-1:0] cf_type; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvi_cf; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvc_cf; @@ -166,9 +172,11 @@ module frontend .valid_i (icache_valid_q), .serving_unaligned_o(serving_unaligned), .address_i (icache_vaddr_q), + .dii_id_i (icache_dii_id_q), .data_i (icache_data_q), .valid_o (instruction_valid), .addr_o (addr), + .dii_id_o (dii_id), .instr_o (instr) ); // -------------------- @@ -225,6 +233,7 @@ module frontend taken_rvi_cf = '0; taken_rvc_cf = '0; predict_address = '0; + if (CVA6Cfg.RVFI_DII) predict_dii_id = '0; for (int i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) cf_type[i] = ariane_pkg::NoCF; @@ -244,6 +253,7 @@ module frontend ras_push = 1'b0; if (CVA6Cfg.BTBEntries && btb_prediction_shifted[i].valid) begin predict_address = btb_prediction_shifted[i].target_address; + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; cf_type[i] = ariane_pkg::JumpR; end end @@ -261,6 +271,7 @@ module frontend ras_pop = ras_predict.valid & instr_queue_consumed[i]; ras_push = 1'b0; predict_address = ras_predict.ra; + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; cf_type[i] = ariane_pkg::Return; end // branch prediction @@ -293,21 +304,20 @@ module frontend // calculate the jump target address if (taken_rvc_cf[i] || taken_rvi_cf[i]) begin predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; end end end // or reduce struct always_comb begin bp_valid = 1'b0; - //if (!CVA6Cfg.RVFI_DII) begin // BP cannot be valid if we have a return instruction and the RAS is not giving a valid address // Check that we encountered a control flow and that for a return the RAS // contains a valid prediction. for (int i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) bp_valid |= ((cf_type[i] != NoCF & cf_type[i] != Return) | ((cf_type[i] == Return) & ras_predict.valid)); - //end end - assign is_mispredict = resolved_branch_i.valid & (resolved_branch_i.is_mispredict | CVA6Cfg.RVFI_DII); + assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict; // Cache interface assign icache_dreq_o.req = instr_queue_ready; @@ -339,8 +349,7 @@ module frontend & resolved_branch_i.is_mispredict & (resolved_branch_i.cf_type == ariane_pkg::JumpR); assign btb_update.pc = resolved_branch_i.pc; - assign btb_update.target_address = resolved_branch_i.target_address[CVA6Cfg.XLEN-1:0]; - exception_t cheri_ex; + assign btb_update.target_address = resolved_branch_i.target_address[CVA6Cfg.VLEN-1:0]; // ------------------- // Next PC // ------------------- @@ -354,9 +363,9 @@ module frontend // Mis-predict handling is a little bit different // select PC a.k.a PC Gen logic [CVA6Cfg.VLEN-1:0] fetch_address; + logic [CVA6Cfg.DIIIDLEN-1:0] fetch_dii_id; always_comb begin : npc_select - automatic cva6_cheri_pkg::cap_pcc_t debug_pcc; //automatic logic [CVA6Cfg.VLEN-1:0] fetch_address; // check whether we come out of reset // this is a workaround. some tools have issues @@ -365,57 +374,56 @@ module frontend // boot_addr_i will be assigned a constant // on the top-level. - debug_pcc = cva6_cheri_pkg::PCC_ROOT_CAP; - debug_pcc.flags.cap_mode = 1'b0; if (npc_rst_load_q) begin npc_d = boot_addr_i; - fetch_address = boot_addr_i[CVA6Cfg.XLEN-1:0]; + fetch_address = boot_addr_i; + if (CVA6Cfg.RVFI_DII) begin + ndii_id_d = test_dii_start(); + fetch_dii_id = test_dii_start(); + end end else begin - fetch_address = npc_q[CVA6Cfg.VLEN-1:0]; + fetch_address = npc_q; // keep stable by default npc_d = npc_q; + if (CVA6Cfg.RVFI_DII) begin + fetch_dii_id = ndii_id_q; + ndii_id_d = ndii_id_q; + end end // 0. Branch Prediction if (bp_valid) begin fetch_address = predict_address; - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(npc_q, predict_address); - else - npc_d = predict_address; + npc_d = predict_address; + if (CVA6Cfg.RVFI_DII) begin + fetch_dii_id = predict_dii_id; + ndii_id_d = predict_dii_id; + end end // 1. Default assignment if (if_ready) begin - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::set_cap_pcc_cursor((npc_rst_load_q) ? boot_addr_i : npc_q, {fetch_address[CVA6Cfg.VLEN-1:CVA6Cfg.FETCH_ALIGN_BITS] + 1, {CVA6Cfg.FETCH_ALIGN_BITS{1'b0}}}); - else - npc_d = { + npc_d = { fetch_address[CVA6Cfg.VLEN-1:CVA6Cfg.FETCH_ALIGN_BITS] + 1, {CVA6Cfg.FETCH_ALIGN_BITS{1'b0}} }; end // 2. Replay instruction fetch if (replay) begin - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(npc_q, replay_addr); - else - npc_d = replay_addr; + npc_d = replay_addr; + if (CVA6Cfg.RVFI_DII) ndii_id_d = replay_dii_id; end // 3. Control flow change request if (is_mispredict) begin npc_d = resolved_branch_i.target_address; + if (CVA6Cfg.RVFI_DII) ndii_id_d = resolved_branch_i.dii_id + 1; end // 4. Return from environment call if (eret_i) begin - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::cap_reg_to_cap_pcc(epc_i); - else - npc_d = epc_i; + npc_d = epc_i; + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 5. Exception/Interrupt if (ex_valid_i) begin - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::cap_reg_to_cap_pcc(trap_vector_base_i); - else - npc_d = trap_vector_base_i; + npc_d = trap_vector_base_i; + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 6. Pipeline Flush because of CSR side effects // On a pipeline flush start fetching from the next address @@ -427,69 +435,16 @@ module frontend // instruction in the commit stage // TODO(zarubaf) This adder can at least be merged with the one in the csr_regfile stage if (set_pc_commit_i) begin - if (CVA6Cfg.CheriPresent) - npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(pc_commit_i, pc_commit_i + (halt_i ? '0 : {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100})); - else - npc_d = pc_commit_i + (halt_i ? '0 : {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100}); + npc_d = pc_commit_i + (halt_i ? '0 : {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100}); + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 7. Debug // enter debug on a hard-coded base-address if (CVA6Cfg.DebugEn && set_debug_pc_i) - if (CVA6Cfg.CheriPresent) begin - npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(debug_pcc,CVA6Cfg.DmBaseAddress[CVA6Cfg.VLEN-1:0] + CVA6Cfg.HaltAddress[CVA6Cfg.VLEN-1:0]); - end else begin - npc_d = CVA6Cfg.DmBaseAddress[CVA6Cfg.VLEN-1:0] + CVA6Cfg.HaltAddress[CVA6Cfg.VLEN-1:0]; - end + npc_d = CVA6Cfg.DmBaseAddress[CVA6Cfg.VLEN-1:0] + CVA6Cfg.HaltAddress[CVA6Cfg.VLEN-1:0]; icache_dreq_o.vaddr = fetch_address; - if (CVA6Cfg.CheriPresent) begin - icache_dreq_o.ex = cheri_ex; - end + if (CVA6Cfg.RVFI_DII) icache_dreq_o.dii_id = fetch_dii_id; end -if (CVA6Cfg.CheriPresent) begin : gen_cheri_pcc_checks -always_comb begin : cheri_pcc_checks - automatic cva6_cheri_pkg::cap_tval_t cheri_tval; - automatic cva6_cheri_pkg::cap_pcc_t npcc; - automatic cva6_cheri_pkg::addrw_t min_instr_off; - - npcc = cva6_cheri_pkg::cap_pcc_t'(npc_q); - - // 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}); - - cheri_tval = {CVA6Cfg.XLEN{1'b0}}; - cheri_ex.cause = cva6_cheri_pkg::CAP_EXCEPTION; - cheri_ex.valid = 1'b0; - cheri_ex.tval = {CVA6Cfg.XLEN{1'b0}}; - cheri_ex.tval2 = {CVA6Cfg.XLEN{1'b0}}; - cheri_ex.tinst = {CVA6Cfg.XLEN{1'b0}}; - cheri_ex.gva = v_i; - - if(!(npcc.base[0] == 1'b0)) begin - cheri_tval.cause = cva6_cheri_pkg::CAP_UNLIGNED_BASE; - cheri_ex.valid = 1'b1; - end - - if(fetch_address < npcc.base || ($unsigned(fetch_address) + min_instr_off) > npcc.top) begin - cheri_tval.cause = cva6_cheri_pkg::CAP_LENGTH_VIOLATION; - cheri_ex.valid = 1'b1; - end - - if(!npcc.hperms.permit_execute) begin - cheri_tval.cause = cva6_cheri_pkg::CAP_PERM_EXEC_VIOLATION; - cheri_ex.valid = 1'b1; - end - if((npcc.otype != cva6_cheri_pkg::UNSEALED_CAP) && npcc.tag) begin - cheri_tval.cause = cva6_cheri_pkg::CAP_SEAL_VIOLATION; - cheri_ex.valid = 1'b1; - end - if(!npcc.tag) begin - cheri_tval.cause = cva6_cheri_pkg::CAP_TAG_VIOLATION; - cheri_ex.valid = 1'b1; - end - // Update tval - cheri_ex.tval = cheri_tval; - end -end logic [CVA6Cfg.FETCH_WIDTH-1:0] icache_data; // re-align the cache line assign icache_data = icache_dreq_i.data >> {shamt, 4'b0}; @@ -497,13 +452,14 @@ end always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin npc_rst_load_q <= 1'b1; - npc_q <= (CVA6Cfg.CheriPresent) ? cva6_cheri_pkg::PCC_ROOT_CAP : '0; + npc_q <= '0; + if (CVA6Cfg.RVFI_DII) ndii_id_q <= '0; speculative_q <= '0; icache_data_q <= '0; icache_valid_q <= 1'b0; icache_vaddr_q <= 'b0; + if (CVA6Cfg.RVFI_DII) icache_dii_id_q <= 'b0; icache_gpaddr_q <= 'b0; - icache_tval_q <= 'b0; icache_tinst_q <= 'b0; icache_gva_q <= 1'b0; icache_ex_valid_q <= ariane_pkg::FE_NONE; @@ -512,12 +468,13 @@ end end else begin npc_rst_load_q <= 1'b0; npc_q <= npc_d; + if (CVA6Cfg.RVFI_DII) ndii_id_q <= ndii_id_d; speculative_q <= speculative_d; icache_valid_q <= icache_dreq_i.valid; if (icache_dreq_i.valid) begin icache_data_q <= icache_data; icache_vaddr_q <= icache_dreq_i.vaddr; - icache_tval_q <= icache_dreq_i.ex.tval; + if (CVA6Cfg.RVFI_DII) icache_dii_id_q <= icache_dreq_i.dii_id; if (CVA6Cfg.RVH) begin icache_gpaddr_q <= icache_dreq_i.ex.tval2[CVA6Cfg.GPLEN-1:0]; icache_tinst_q <= icache_dreq_i.ex.tinst; @@ -535,8 +492,6 @@ end icache_ex_valid_q <= ariane_pkg::FE_INSTR_PAGE_FAULT; end else if (icache_dreq_i.ex.cause == riscv::INSTR_ACCESS_FAULT) begin icache_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT; - end else if (icache_dreq_i.ex.cause == cva6_cheri_pkg::CAP_EXCEPTION && icache_dreq_i.ex.valid) begin - icache_ex_valid_q <= ariane_pkg::FE_INSTR_CHERI_FAULT; end else begin icache_ex_valid_q <= ariane_pkg::FE_NONE; end @@ -639,10 +594,9 @@ end .flush_i (flush_i), .instr_i (instr), // from re-aligner .addr_i (addr), // from re-aligner - .pc_i(npc_q), + .dii_id_i (dii_id), .exception_i (icache_ex_valid_q), // from I$ .exception_addr_i (icache_vaddr_q), - .exception_tval_i (icache_tval_q), .exception_gpaddr_i (icache_gpaddr_q), .exception_tinst_i (icache_tinst_q), .exception_gva_i (icache_gva_q), @@ -653,6 +607,7 @@ end .ready_o (instr_queue_ready), .replay_o (replay), .replay_addr_o (replay_addr), + .replay_dii_id_o (replay_dii_id), .fetch_entry_o (fetch_entry_o), // to back-end .fetch_entry_valid_o(fetch_entry_valid_o), // to back-end .fetch_entry_ready_i(fetch_entry_ready_i) // to back-end diff --git a/core/frontend/instr_queue.sv b/core/frontend/instr_queue.sv index d9559aade..3a631c1c2 100644 --- a/core/frontend/instr_queue.sv +++ b/core/frontend/instr_queue.sv @@ -1,4 +1,5 @@ // Copyright 2018 - 2019 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 @@ -59,8 +60,8 @@ module instr_queue input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][31:0] instr_i, // Instruction address - instr_realign input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr_i, - // Instruction Capability - instr_realign - input logic [CVA6Cfg.PCLEN-1:0] pc_i, + // Instruction DII ID - instr_realign + input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // Instruction is valid - instr_realign input logic [CVA6Cfg.INSTR_PER_FETCH-1:0] valid_i, // Handshake’s ready with CACHE - CACHE @@ -71,7 +72,6 @@ module instr_queue input ariane_pkg::frontend_exception_t exception_i, // Exception address - CACHE input logic [CVA6Cfg.VLEN-1:0] exception_addr_i, - input logic [CVA6Cfg.XLEN-1:0] exception_tval_i, input logic [CVA6Cfg.GPLEN-1:0] exception_gpaddr_i, input logic [31:0] exception_tinst_i, input logic exception_gva_i, @@ -83,6 +83,8 @@ module instr_queue output logic replay_o, // Address at which to replay the fetch - FRONTEND output logic [CVA6Cfg.VLEN-1:0] replay_addr_o, + // DII ID to restart stream from - FRONTEND + output logic [CVA6Cfg.DIIIDLEN-1:0] replay_dii_id_o, // Handshake’s data with ID_STAGE - ID_STAGE output fetch_entry_t [ariane_pkg::SUPERSCALAR:0] fetch_entry_o, // Handshake’s valid with ID_STAGE - ID_STAGE @@ -96,10 +98,10 @@ module instr_queue typedef struct packed { logic [31:0] instr; // instruction word + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // instruction DII ID ariane_pkg::cf_t cf; // branch was taken ariane_pkg::frontend_exception_t ex; // exception happened logic [CVA6Cfg.VLEN-1:0] ex_vaddr; // lower VLEN bits of tval for exception - logic [CVA6Cfg.XLEN-1:0] ex_tval; logic [CVA6Cfg.GPLEN-1:0] ex_gpaddr; // lower GPLEN bits of tval2 for exception logic [31:0] ex_tinst; // tinst of exception logic ex_gva; @@ -133,8 +135,8 @@ ariane_pkg::FETCH_FIFO_DEPTH // rotated by N logic [ariane_pkg::SUPERSCALAR+1:0][CVA6Cfg.INSTR_PER_FETCH-1:0] idx_ds; - logic [CVA6Cfg.PCLEN-1:0] pc_d, pc_q; // current PC - logic [ariane_pkg::SUPERSCALAR+1:0][CVA6Cfg.PCLEN-1:0] pc_j; + logic [CVA6Cfg.VLEN-1:0] pc_d, pc_q; // current PC + logic [ariane_pkg::SUPERSCALAR+1:0][CVA6Cfg.VLEN-1:0] pc_j; logic reset_address_d, reset_address_q; // we need to re-set the address because of a flush logic [ariane_pkg::SUPERSCALAR:0] fetch_entry_is_cf, fetch_entry_fire; @@ -152,6 +154,7 @@ ariane_pkg::FETCH_FIFO_DEPTH logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0] fifo_pos_extended; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] fifo_pos; logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0][31:0] instr; + logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id; ariane_pkg::cf_t [CVA6Cfg.INSTR_PER_FETCH*2-1:0] cf; // replay interface logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instr_overflow_fifo; @@ -218,6 +221,10 @@ ariane_pkg::FETCH_FIFO_DEPTH assign instr[i+CVA6Cfg.INSTR_PER_FETCH] = instr_i[i]; assign cf[i] = cf_type_i[i]; assign cf[i+CVA6Cfg.INSTR_PER_FETCH] = cf_type_i[i]; + if (CVA6Cfg.RVFI_DII) begin + assign dii_id[i] = dii_id_i[i]; + assign dii_id[i+CVA6Cfg.INSTR_PER_FETCH] = dii_id_i[i]; + end end // shift the inputs @@ -227,7 +234,6 @@ ariane_pkg::FETCH_FIFO_DEPTH assign instr_data_in[i].cf = cf[CVA6Cfg.INSTR_PER_FETCH+i-idx_is_q]; assign instr_data_in[i].ex = exception_i; // exceptions hold for the whole fetch packet assign instr_data_in[i].ex_vaddr = exception_addr_i; - assign instr_data_in[i].ex_tval = exception_tval_i; if (CVA6Cfg.RVH) begin : gen_hyp_ex_with_C assign instr_data_in[i].ex_gpaddr = exception_gpaddr_i; assign instr_data_in[i].ex_tinst = exception_tinst_i; @@ -237,6 +243,7 @@ ariane_pkg::FETCH_FIFO_DEPTH assign instr_data_in[i].ex_tinst = '0; assign instr_data_in[i].ex_gva = 1'b0; end + if (CVA6Cfg.RVFI_DII) assign instr_data_in[i].dii_id = dii_id[CVA6Cfg.INSTR_PER_FETCH+i-idx_is_q]; /* verilator lint_on WIDTH */ end end else begin : gen_multiple_instr_per_fetch_without_C @@ -250,6 +257,7 @@ ariane_pkg::FETCH_FIFO_DEPTH assign fifo_pos_extended = '0; assign fifo_pos = '0; assign instr = '0; + if (CVA6Cfg.RVFI_DII) assign dii_id = '0; assign popcount = '0; assign shamt = '0; assign valid = '0; @@ -263,10 +271,10 @@ ariane_pkg::FETCH_FIFO_DEPTH /* verilator lint_off WIDTH */ assign instr_data_in[0].instr = instr_i[0]; + if (CVA6Cfg.RVFI_DII) assign instr_data_in[0].dii_id = dii_id_i[0]; assign instr_data_in[0].cf = cf_type_i[0]; assign instr_data_in[0].ex = exception_i; // exceptions hold for the whole fetch packet assign instr_data_in[0].ex_vaddr = exception_addr_i; - assign instr_data_in[0].ex_tval = exception_tval_i; if (CVA6Cfg.RVH) begin : gen_hyp_ex_without_C assign instr_data_in[0].ex_gpaddr = exception_gpaddr_i; assign instr_data_in[0].ex_tinst = exception_tinst_i; @@ -302,8 +310,10 @@ ariane_pkg::FETCH_FIFO_DEPTH // if we successfully pushed some instructions we can output the next instruction // which we didn't manage to push assign replay_addr_o = (address_overflow) ? addr_i[0] : addr_i[shamt]; + if (CVA6Cfg.RVFI_DII) assign replay_dii_id_o = (address_overflow) ? dii_id_i[0] : dii_id_i[shamt]; end else begin : gen_replay_addr_o_without_C assign replay_addr_o = addr_i[0]; + if (CVA6Cfg.RVFI_DII) assign replay_dii_id_o = dii_id_i[0]; end // ---------------------- @@ -335,6 +345,7 @@ ariane_pkg::FETCH_FIFO_DEPTH // assemble fetch entry for (int unsigned i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin fetch_entry_o[i].instruction = '0; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[i].dii_id = '0; fetch_entry_o[i].address = pc_j[i]; fetch_entry_o[i].ex.valid = 1'b0; fetch_entry_o[i].ex.cause = '0; @@ -355,22 +366,16 @@ ariane_pkg::FETCH_FIFO_DEPTH fetch_entry_o[0].ex.cause = riscv::INSTR_ACCESS_FAULT; end else if (CVA6Cfg.RVH && instr_data_out[i].ex == ariane_pkg::FE_INSTR_GUEST_PAGE_FAULT) begin fetch_entry_o[0].ex.cause = riscv::INSTR_GUEST_PAGE_FAULT; - end else if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[0].ex.cause = cva6_cheri_pkg::CAP_EXCEPTION; end else begin fetch_entry_o[0].ex.cause = riscv::INSTR_PAGE_FAULT; end fetch_entry_o[0].instruction = instr_data_out[i].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[0].dii_id = instr_data_out[i].dii_id; fetch_entry_o[0].ex.valid = instr_data_out[i].ex != ariane_pkg::FE_NONE; - if (CVA6Cfg.TvalEn) begin - if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[0].ex.tval = instr_data_out[i].ex_tval; - end else begin - fetch_entry_o[0].ex.tval = { - {(CVA6Cfg.XLEN - CVA6Cfg.VLEN) {1'b0}}, instr_data_out[i].ex_vaddr - }; - end - end + if (CVA6Cfg.TvalEn) + fetch_entry_o[0].ex.tval = { + {(CVA6Cfg.XLEN - CVA6Cfg.VLEN) {1'b0}}, instr_data_out[i].ex_vaddr + }; if (CVA6Cfg.RVH) begin fetch_entry_o[0].ex.tval2 = instr_data_out[i].ex_gpaddr; fetch_entry_o[0].ex.tinst = instr_data_out[i].ex_tinst; @@ -384,22 +389,13 @@ ariane_pkg::FETCH_FIFO_DEPTH if (idx_ds[1][i]) begin if (instr_data_out[i].ex == ariane_pkg::FE_INSTR_ACCESS_FAULT) begin fetch_entry_o[NID].ex.cause = riscv::INSTR_ACCESS_FAULT; - end else if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[NID].ex.cause = cva6_cheri_pkg::CAP_EXCEPTION; end else begin fetch_entry_o[NID].ex.cause = riscv::INSTR_PAGE_FAULT; end fetch_entry_o[NID].instruction = instr_data_out[i].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[NID].dii_id = instr_data_out[i].dii_id; fetch_entry_o[NID].ex.valid = instr_data_out[i].ex != ariane_pkg::FE_NONE; - if (CVA6Cfg.TvalEn) begin - if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[NID].ex.tval = instr_data_out[i].ex_tval; - end else begin - fetch_entry_o[NID].ex.tval = { - {{64 - riscv::VLEN{1'b0}}, instr_data_out[i].ex_vaddr} - }; - end - end + fetch_entry_o[NID].ex.tval = {{64 - riscv::VLEN{1'b0}}, instr_data_out[i].ex_vaddr}; fetch_entry_o[NID].branch_predict.cf = instr_data_out[i].cf; // Cannot output two CF the same cycle. pop_instr[i] = fetch_entry_fire[NID]; @@ -420,25 +416,18 @@ ariane_pkg::FETCH_FIFO_DEPTH idx_ds_d = '0; idx_is_d = '0; fetch_entry_o[0].instruction = instr_data_out[0].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[0].dii_id = instr_data_out[0].dii_id; fetch_entry_o[0].address = pc_q; fetch_entry_o[0].ex.valid = instr_data_out[0].ex != ariane_pkg::FE_NONE; if (instr_data_out[0].ex == ariane_pkg::FE_INSTR_ACCESS_FAULT) begin fetch_entry_o[0].ex.cause = riscv::INSTR_ACCESS_FAULT; - end else if (CVA6Cfg.CheriPresent && instr_data_out[0].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[0].ex.cause = cva6_cheri_pkg::CAP_EXCEPTION; end else begin fetch_entry_o[0].ex.cause = riscv::INSTR_PAGE_FAULT; end - if (CVA6Cfg.TvalEn) begin - if (CVA6Cfg.CheriPresent && instr_data_out[0].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin - fetch_entry_o[0].ex.tval = instr_data_out[0].ex_tval; - end else begin - fetch_entry_o[0].ex.tval = { - {{64 - CVA6Cfg.VLEN{1'b0}}, instr_data_out[0].ex_vaddr} - }; - end - end else fetch_entry_o[0].ex.tval = '0; + if (CVA6Cfg.TvalEn) + fetch_entry_o[0].ex.tval = {{64 - CVA6Cfg.VLEN{1'b0}}, instr_data_out[0].ex_vaddr}; + else fetch_entry_o[0].ex.tval = '0; if (CVA6Cfg.RVH) begin fetch_entry_o[0].ex.tval2 = instr_data_out[0].ex_gpaddr; fetch_entry_o[0].ex.tinst = instr_data_out[0].ex_tinst; @@ -468,13 +457,9 @@ ariane_pkg::FETCH_FIFO_DEPTH // ---------------------- assign pc_j[0] = pc_q; for (genvar i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin - if (CVA6Cfg.CheriPresent) begin - assign pc_j[i+1] = fetch_entry_is_cf[i] ? cva6_cheri_pkg::set_cap_pcc_cursor(pc_j[i], address_out) : cva6_cheri_pkg::set_cap_pcc_cursor(pc_j[i], pc_j[i][CVA6Cfg.XLEN-1:0] + ((fetch_entry_o[i].instruction[1:0] != 2'b11) ? 'd2 : 'd4)); - end else begin - assign pc_j[i+1] = fetch_entry_is_cf[i] ? address_out : ( - pc_j[i] + ((fetch_entry_o[i].instruction[1:0] != 2'b11) ? 'd2 : 'd4) - ); - end + assign pc_j[i+1] = fetch_entry_is_cf[i] ? address_out : ( + pc_j[i] + ((fetch_entry_o[i].instruction[1:0] != 2'b11) ? 'd2 : 'd4) + ); end always_comb begin @@ -493,11 +478,7 @@ ariane_pkg::FETCH_FIFO_DEPTH // we previously flushed so we need to reset the address if (valid_i[0] && reset_address_q) begin // this is the base of the first instruction - if (CVA6Cfg.CheriPresent) begin - pc_d = cva6_cheri_pkg::set_cap_pcc_cursor(pc_i, addr_i[0]); - end else begin - pc_d = addr_i[0]; - end + pc_d = addr_i[0]; reset_address_d = 1'b0; end end diff --git a/core/id_stage.sv b/core/id_stage.sv index 13db62593..e34eee94e 100644 --- a/core/id_stage.sv +++ b/core/id_stage.sv @@ -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 @@ -77,8 +78,8 @@ module id_stage #( input logic tsr_i, // Hypervisor user mode - CSR_REGFILE input logic hu_i, - // CHERI Data Default capability - CSR_REGFILE - input logic[CVA6Cfg.REGLEN-1:0] ddc_i + // CHERI program counter capability; only used for metadata - ISSUE_STAGE + input cva6_cheri_pkg::cap_pcc_t pcc_i ); // ID/ISSUE register stage typedef struct packed { @@ -104,12 +105,6 @@ module id_stage #( logic is_last_macro_instr_o; logic is_double_rd_macro_instr_o; - cva6_cheri_pkg::cap_pcc_t [ariane_pkg::SUPERSCALAR:0] pcc; - - for (genvar i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin - assign pcc[i] = (CVA6Cfg.CheriPresent) ? (cva6_cheri_pkg::cap_pcc_t'(fetch_entry_i[i].address)) : '0; - end - if (CVA6Cfg.RVC) begin // --------------------------------------------------------- // 1. Check if they are compressed and expand in case they are @@ -119,7 +114,7 @@ module id_stage #( .CVA6Cfg(CVA6Cfg) ) compressed_decoder_i ( .instr_i (fetch_entry_i[i].instruction), - .cap_mode_i ((CVA6Cfg.CheriPresent) ? pcc[i].flags.cap_mode : 1'b0), + .cap_mode_i ((CVA6Cfg.CheriPresent) ? pcc_i.flags.cap_mode : 1'b0), .instr_o (compressed_instr[i]), .illegal_instr_o (is_illegal[i]), .is_compressed_o (is_compressed[i]), @@ -186,7 +181,8 @@ module id_stage #( .irq_ctrl_i, .irq_i, .pc_i (fetch_entry_i[i].address), - .ddc_i (ddc_i), + .dii_id_i (fetch_entry_i[i].dii_id), + .pcc_i (pcc_i), .is_compressed_i (is_compressed_cmp[i]), .is_macro_instr_i (is_macro_instr_i[i]), .is_last_macro_instr_i (is_last_macro_instr_o), diff --git a/core/include/build_config_pkg.sv b/core/include/build_config_pkg.sv index 5560001f5..87cd445bb 100644 --- a/core/include/build_config_pkg.sv +++ b/core/include/build_config_pkg.sv @@ -141,6 +141,7 @@ package build_config_pkg; cfg.CheriCapTagWidth = CVA6Cfg.CheriCapTagWidth; cfg.RVFI_DII = bit'(CVA6Cfg.RVFI_DII); + cfg.DIIIDLEN = CVA6Cfg.DIIIDLEN; cfg.DATA_USER_EN = CVA6Cfg.DataUserEn; cfg.WtDcacheWbufDepth = CVA6Cfg.WtDcacheWbufDepth; diff --git a/core/include/config_pkg.sv b/core/include/config_pkg.sv index 642047a6d..8176c7cf4 100644 --- a/core/include/config_pkg.sv +++ b/core/include/config_pkg.sv @@ -196,6 +196,8 @@ package config_pkg; int unsigned CheriCapTagWidth; // Enable RVDI_DII interface int unsigned RVFI_DII; + // DII ID Length + int unsigned DIIIDLEN; } cva6_user_cfg_t; typedef struct packed { @@ -332,6 +334,7 @@ package config_pkg; int unsigned CheriCapTagWidth; bit RVFI_DII; + int unsigned DIIIDLEN; int unsigned ModeW; int unsigned ASIDW; diff --git a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv index 42bbfeb05..3da7c73bf 100644 --- a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv +++ b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv @@ -18,7 +18,7 @@ package cva6_config_pkg; localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; - localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcbExtEn = 0; localparam CVA6ConfigZcmpExtEn = 0; localparam CVA6ConfigAExtEn = 1; localparam CVA6ConfigHExtEn = 1; @@ -30,6 +30,7 @@ package cva6_config_pkg; localparam CVA6ConfigCheriCapTagWidth = 1; localparam CVA6ConfigRVFI_DII = 1; + localparam CVA6ConfigDIIIDLEN = 6; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -152,7 +153,8 @@ package cva6_config_pkg; NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth), CheriCapTagWidth : int'(CVA6ConfigCheriCapTagWidth), - RVFI_DII : int'(CVA6ConfigRVFI_DII) + RVFI_DII : int'(CVA6ConfigRVFI_DII), + DIIIDLEN : int'(CVA6ConfigDIIIDLEN) }; endpackage diff --git a/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv b/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv index bca40bb2a..73fce0e27 100644 --- a/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv @@ -32,6 +32,7 @@ package cva6_config_pkg; localparam CVA6ConfigCheriCapTagWidth = 1; localparam CVA6ConfigRVFI_DII = 0; + localparam CVA6ConfigDIIIDLEN = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -154,7 +155,8 @@ package cva6_config_pkg; NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth), CheriCapTagWidth : int'(CVA6ConfigCheriCapTagWidth), - RVFI_DII : int'(CVA6ConfigRVFI_DII) + RVFI_DII : int'(CVA6ConfigRVFI_DII), + DIIIDLEN : int'(CVA6ConfigDIIIDLEN) }; endpackage diff --git a/core/include/cva6_cheri_pkg.sv b/core/include/cva6_cheri_pkg.sv index 2d32d055b..aee0b45a8 100644 --- a/core/include/cva6_cheri_pkg.sv +++ b/core/include/cva6_cheri_pkg.sv @@ -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 @@ -302,21 +303,7 @@ package cva6_cheri_pkg; } cap_reg_t; /* Full PCC Capability definition */ - typedef struct packed { - bool_t tag; - upermsw_t uperms; - cap_hperms_t hperms; - cap_flags_t flags; - resw_t res; - otypew_t otype; - cap_fmt_t int_e; - ew_t exp; - addrw_t base; - addrwe_t top; - mw_t addr_mid; - addrw_t addr; - } cap_pcc_t; - + typedef cap_reg_t cap_pcc_t; /* Capability set bounds return */ typedef struct packed { @@ -360,35 +347,9 @@ package cva6_cheri_pkg; bounds : DEFAULT_BOUNDS_CAP }; - localparam cap_pcc_t PCC_ROOT_CAP = '{ - tag : 1'b1, - res : '0, - addr : '{default: 0}, - addr_mid : '{default: 0}, - base : '{default: 0}, - top : (1 << 64), - uperms : '{default: '1}, - hperms : '{default: '1}, - flags : 1'b0, - otype : UNSEALED_CAP, - exp : 52, - int_e : EMBEDDED_EXP - }; + localparam cap_pcc_t PCC_ROOT_CAP = REG_ROOT_CAP; - localparam cap_pcc_t PCC_NULL_CAP = '{ - tag : 1'b0, - res : '0, - uperms : '{default: 0}, - hperms : '{default: 0}, - flags : 1'b0, - otype : UNSEALED_CAP, - int_e : EMBEDDED_EXP, - exp : 52, - base : '{default: 0}, - top : (1 << 64), - addr : '{default: 0}, - addr_mid : '{default: 0} - }; + localparam cap_pcc_t PCC_NULL_CAP = REG_NULL_CAP; localparam cap_mem_t MEM_NULL_CAP = '{ tag : 1'b0, @@ -448,22 +409,6 @@ package cva6_cheri_pkg; ret.addr = set_cap_mem_addr_unsafe(cap, addr + $signed(inc)); return ret.addr; endfunction - /** - * Capability Register Interface - */ - - /** - * @brief Function that sets the PCC capability cursor or address. - * @param cap capability in register format. - * @param cursor a [63:0] value with the cursor to be set. - * @returns capability PCC with addr set to input address. - */ - function automatic cap_pcc_t set_cap_pcc_cursor (cap_pcc_t cap, addrw_t cursor); - cap_pcc_t ret = cap; - ret.addr = cursor; - ret.addr_mid = ret.addr >> cap.exp; - return ret; - endfunction /** * Capability Register Interface @@ -1002,40 +947,11 @@ package cva6_cheri_pkg; endfunction function automatic cap_pcc_t cap_reg_to_cap_pcc(cap_reg_t cap); - cap_pcc_t cap_pcc; - cap_meta_data_t cap_meta_data = get_cap_reg_meta_data(cap); - cap_pcc.tag = cap.tag; - cap_pcc.uperms = cap.uperms; - cap_pcc.hperms = cap.hperms; - cap_pcc.flags = cap.flags; - cap_pcc.res = cap.res; - cap_pcc.otype = cap.otype; - cap_pcc.int_e = cap.int_e; - cap_pcc.exp = cap.bounds.exp; - cap_pcc.base = get_cap_reg_base(cap,cap_meta_data); - cap_pcc.top = get_cap_reg_top(cap,cap_meta_data); - cap_pcc.addr = cap.addr; - cap_pcc.addr_mid = cap.addr >> cap.bounds.exp; - return cap_pcc; + return cap; endfunction function automatic cap_reg_t cap_pcc_to_cap_reg(cap_pcc_t cap); - cap_reg_t cap_reg; - addrw_t base = cap.base >> cap.exp; - addrwe_t top = cap.top >> cap.exp; - cap_reg.tag = cap.tag; - cap_reg.uperms = cap.uperms; - cap_reg.hperms = cap.hperms; - cap_reg.flags = cap.flags; - cap_reg.res = cap.res; - cap_reg.otype = cap.otype; - cap_reg.int_e = cap.int_e; - cap_reg.bounds.exp = cap.exp; - cap_reg.bounds.top_bits = top[CAP_M_WIDTH-1:0]; - cap_reg.bounds.base_bits = base[CAP_M_WIDTH-1:0]; - cap_reg.addr_mid = cap.addr_mid; - cap_reg.addr = cap.addr; - return cap_reg; + return cap; endfunction diff --git a/core/include/rvfi_types.svh b/core/include/rvfi_types.svh index d9619130d..a0fddd121 100644 --- a/core/include/rvfi_types.svh +++ b/core/include/rvfi_types.svh @@ -28,13 +28,6 @@ logic [config_pkg::NRET*Cfg.CLEN-1:0] mem_wdata; \ } -`define RVFI_DII_INSTR_T(Cfg) struct packed { \ - logic [config_pkg::NRET*7:0] padding; \ - logic [config_pkg::NRET*7:0] rvfi_cmd; \ - logic [config_pkg::NRET*15:0] rvfi_time; \ - logic [config_pkg::NRET*31:0] rvfi_insn; \ -} - `define RVFI_CSR_ELMT_T(Cfg) struct packed { \ logic [Cfg.REGLEN-1:0] rdata; \ logic [Cfg.REGLEN-1:0] rmask; \ diff --git a/core/instr_realign.sv b/core/instr_realign.sv index 85d6d4f1c..cde054d7a 100644 --- a/core/instr_realign.sv +++ b/core/instr_realign.sv @@ -1,4 +1,5 @@ // Copyright 2018 - 2019 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 @@ -36,12 +37,16 @@ module instr_realign output logic serving_unaligned_o, // 32-bit block address - CACHE input logic [CVA6Cfg.VLEN-1:0] address_i, + // DII ID of requested instruction in block - CACHE + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // 32-bit block - CACHE input logic [CVA6Cfg.FETCH_WIDTH-1:0] data_i, // instruction is valid - FRONTEND output logic [CVA6Cfg.INSTR_PER_FETCH-1:0] valid_o, // Instruction address - FRONTEND output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr_o, + // Instruction DII ID - FRONTEND + output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Instruction - instr_scan&instr_queue output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][31:0] instr_o ); @@ -59,6 +64,7 @@ module instr_realign logic unaligned_d, unaligned_q; // register to save the unaligned address logic [CVA6Cfg.VLEN-1:0] unaligned_address_d, unaligned_address_q; + logic [CVA6Cfg.DIIIDLEN-1:0] unaligned_dii_id_d, unaligned_dii_id_q; // we have an unaligned instruction assign serving_unaligned_o = unaligned_q; @@ -72,10 +78,15 @@ module instr_realign valid_o[0] = valid_i; instr_o[0] = unaligned_q ? {data_i[15:0], unaligned_instr_q} : data_i[31:0]; addr_o[0] = unaligned_q ? unaligned_address_q : address_i; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = unaligned_q ? unaligned_dii_id_q : dii_id_i; valid_o[1] = 1'b0; instr_o[1] = '0; addr_o[1] = {address_i[CVA6Cfg.VLEN-1:2], 2'b10}; + if (CVA6Cfg.RVFI_DII) begin + dii_id_o[1] = dii_id_o[0] + 1; + unaligned_dii_id_d = dii_id_o[1]; + end // this instruction is compressed or the last instruction was unaligned if (instr_is_compressed[0] || unaligned_q) begin @@ -106,6 +117,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_address_d = {address_i[CVA6Cfg.VLEN-1:2], 2'b10}; unaligned_instr_d = data_i[15:0]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[0]; // the instruction isn't compressed but only the lower is ready end else begin valid_o = {{CVA6Cfg.INSTR_PER_FETCH - 1{1'b0}}, 1'b1}; @@ -121,6 +133,7 @@ module instr_realign valid_o = '0; instr_o[0] = '0; addr_o[0] = '0; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = '0; instr_o[1] = '0; addr_o[1] = '0; instr_o[2] = '0; @@ -128,6 +141,13 @@ module instr_realign instr_o[3] = {16'b0, data_i[63:48]}; addr_o[3] = {address_i[riscv::VLEN-1:3], 3'b110}; + if (CVA6Cfg.RVFI_DII) begin + dii_id_o[0] = unaligned_q ? unaligned_dii_id_q : dii_id_i; + dii_id_o[1] = dii_id_o[0] + 1; + dii_id_o[2] = dii_id_o[0] + 2; + dii_id_o[3] = dii_id_o[0] + 3; + end + case (address_i[2:1]) 2'b00: begin valid_o[0] = valid_i; @@ -166,6 +186,7 @@ module instr_realign end else begin unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end else begin unaligned_d = 1'b0; @@ -180,11 +201,13 @@ module instr_realign end else begin unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin instr_o[0] = data_i[31:0]; addr_o[0] = address_i; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = dii_id_i; if (instr_is_compressed[0]) begin instr_o[1] = data_i[47:16]; @@ -209,6 +232,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin @@ -221,6 +245,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin @@ -242,6 +267,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end @@ -279,6 +305,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[2]; unaligned_address_d = addr_o[2]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[2]; end end end else begin @@ -291,6 +318,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[2]; unaligned_address_d = addr_o[2]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[2]; end end end @@ -316,6 +344,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[1]; unaligned_address_d = addr_o[1]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[1]; end end end @@ -337,6 +366,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[0]; unaligned_address_d = addr_o[0]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[0]; end end endcase @@ -348,9 +378,11 @@ module instr_realign unaligned_q <= 1'b0; unaligned_address_q <= '0; unaligned_instr_q <= '0; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_q <= '0; end else begin if (valid_i) begin unaligned_address_q <= unaligned_address_d; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_q <= unaligned_dii_id_d; unaligned_instr_q <= unaligned_instr_d; end diff --git a/core/issue_read_operands.sv b/core/issue_read_operands.sv index 5589c1f29..b24053d37 100644 --- a/core/issue_read_operands.sv +++ b/core/issue_read_operands.sv @@ -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 @@ -19,7 +20,9 @@ module issue_read_operands import ariane_pkg::*; #( parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter type bp_resolve_t = logic, parameter type branchpredict_sbe_t = logic, + parameter type exception_t = logic, parameter type fu_data_t = logic, parameter type scoreboard_entry_t = logic, parameter type rs3_len_t = logic @@ -40,6 +43,10 @@ module issue_read_operands input logic issue_instr_valid_i, // Issue stage acknowledge - TO_BE_COMPLETED output logic issue_ack_o, + // PCC exception - Execute + output exception_t issue_pcc_ex_o, + // Backend Empty - scoreboard + input logic backend_empty_i, // rs1 operand address - scoreboard output logic [REG_ADDR_SIZE-1:0] rs1_o, // rs1 operand - scoreboard @@ -71,6 +78,8 @@ module issue_read_operands output logic [CVA6Cfg.REGLEN-1:0] rs2_forwarding_o, // Instruction pc - TO_BE_COMPLETED output logic [CVA6Cfg.PCLEN-1:0] pc_o, + // Instruction DII ID - TO_BE_COMPLETED + output logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Is compressed instruction - TO_BE_COMPLETED output logic is_compressed_instr_o, // Fixed Latency Unit ready to accept new request - TO_BE_COMPLETED @@ -121,6 +130,20 @@ module issue_read_operands input logic [CVA6Cfg.NrCommitPorts-1:0] we_gpr_i, // TO_BE_COMPLETED - TO_BE_COMPLETED input logic [CVA6Cfg.NrCommitPorts-1:0] we_fpr_i, + // Program counter capability last committed - TO_BE_COMPLETED + input logic [CVA6Cfg.REGLEN-1:0] pcc_commit_i, + // Set COMMIT PC as next PC requested by FENCE, CSR side-effect and Accelerate port - CONTROLLER + input logic set_pc_commit_i, + // Exception event - COMMIT + input logic ex_valid_i, + // Mispredict event and next PC - EXECUTE + input bp_resolve_t resolved_branch_i, + // Next PC when jumping into exception - CSR_FILE + input logic [CVA6Cfg.REGLEN-1:0] trap_vector_base_i, + // Exception PC - CSR_FILE + input logic [CVA6Cfg.REGLEN-1:0] epc_i, + // ERET now - CSR_FILE + input logic eret_i, // Stall signal, we do not want to fetch any more entries - TO_BE_COMPLETED output logic stall_issue_o @@ -155,6 +178,9 @@ module issue_read_operands fu_t fu_n, fu_q; // functional unit to use logic [31:0] tinst_n, tinst_q; // transformed instruction logic use_ddc_n, use_ddc_q; + logic [CVA6Cfg.PCLEN-1:0] pcc_n, pcc_q; + logic pcc_jump_change_valid_n, pcc_jump_change_valid_q; + logic [CVA6Cfg.PCLEN-1:0] pcc_jump_change_n, pcc_jump_change_q; // forwarding signals logic forward_rs1, forward_rs2, forward_rs3; @@ -194,6 +220,57 @@ module issue_read_operands // Issue Stage // --------------- +if (CVA6Cfg.CheriPresent) begin : gen_cheri_pcc_checks + // check PCC bounds + always_comb begin : pcc_bounds + automatic cva6_cheri_pkg::cap_pcc_t pcc; + automatic cva6_cheri_pkg::cap_meta_data_t pcc_meta; + automatic cva6_cheri_pkg::addrw_t pcc_base; + automatic cva6_cheri_pkg::addrwe_t pcc_top; + automatic logic [CVA6Cfg.VLEN-1:0] next_pc_off; + automatic logic [CVA6Cfg.VLEN-1:0] next_pc_addr; + automatic cva6_cheri_pkg::cap_tval_t cheri_tval; + pcc = cva6_cheri_pkg::cap_pcc_t'(pcc_q); + pcc_meta = cva6_cheri_pkg::get_cap_reg_meta_data(pcc_q); + pcc_base = cva6_cheri_pkg::get_cap_reg_base(pcc_q, pcc_meta); + pcc_top = cva6_cheri_pkg::get_cap_reg_top(pcc_q, pcc_meta); + next_pc_off = ((issue_instr_i.is_compressed) ? {{CVA6Cfg.VLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.VLEN-3{1'b0}}, 3'h4}); + next_pc_addr = issue_instr_i.pc + next_pc_off; + issue_pcc_ex_o = 0; + // Check PCC bounds every instruction + if (!issue_instr_i.ex.valid) begin + if((cva6_cheri_pkg::addrw_t'(signed'(issue_instr_i.pc)) < pcc_base) || ({0,cva6_cheri_pkg::addrw_t'(signed'(next_pc_addr))} > pcc_top)) begin + issue_pcc_ex_o.cause = cva6_cheri_pkg::CAP_EXCEPTION; + cheri_tval.cause = cva6_cheri_pkg::CAP_LENGTH_VIOLATION; + cheri_tval.cap_idx = {6'b100000}; + issue_pcc_ex_o.tval = cheri_tval; + issue_pcc_ex_o.valid = 1'b1; + end + if(!pcc.hperms.permit_execute) begin + issue_pcc_ex_o.cause = cva6_cheri_pkg::CAP_EXCEPTION; + cheri_tval.cause = cva6_cheri_pkg::CAP_PERM_EXEC_VIOLATION; + cheri_tval.cap_idx = {6'b100000}; + issue_pcc_ex_o.tval = cheri_tval; + issue_pcc_ex_o.valid = 1'b1; + end + if((pcc.otype != cva6_cheri_pkg::UNSEALED_CAP) && pcc.tag) begin + issue_pcc_ex_o.cause = cva6_cheri_pkg::CAP_EXCEPTION; + cheri_tval.cause = cva6_cheri_pkg::CAP_SEAL_VIOLATION; + cheri_tval.cap_idx = {6'b100000}; + issue_pcc_ex_o.tval = cheri_tval; + issue_pcc_ex_o.valid = 1'b1; + end + if (!pcc.tag) begin + issue_pcc_ex_o.cause = cva6_cheri_pkg::CAP_EXCEPTION; + cheri_tval.cause = cva6_cheri_pkg::CAP_TAG_VIOLATION; + cheri_tval.cap_idx = {6'b100000}; + issue_pcc_ex_o.tval = cheri_tval; + issue_pcc_ex_o.valid = 1'b1; + end + end + end +end + // select the right busy signal // this obviously depends on the functional unit we need always_comb begin : unit_busy @@ -279,6 +356,9 @@ module issue_read_operands stall = 1'b1; end end + + // Stall while there is an outstanding change to bounds. + if (CVA6Cfg.CheriPresent && pcc_jump_change_valid_q && !backend_empty_i) stall = 1'b1; end // third operand from fp regfile or gp regfile if NR_RGPR_PORTS == 3 @@ -311,6 +391,21 @@ module issue_read_operands rs1_n = issue_instr_i.rs1; rs2_n = issue_instr_i.rs2; use_ddc_n = issue_instr_i.use_ddc; + + if (eret_i) pcc_n = epc_i; + else if (set_pc_commit_i) pcc_n = pcc_commit_i; + else if (ex_valid_i) pcc_n = trap_vector_base_i; + else if (pcc_jump_change_valid_q && backend_empty_i) pcc_n = pcc_jump_change_q; + else pcc_n = pcc_q; + + if (eret_i || set_pc_commit_i || ex_valid_i) pcc_jump_change_valid_n = 1'b0; + else if (resolved_branch_i.valid && (resolved_branch_i.target_address[CVA6Cfg.REGLEN-1:CVA6Cfg.XLEN] != pcc_q[CVA6Cfg.REGLEN-1:CVA6Cfg.XLEN])) begin + pcc_jump_change_valid_n = 1'b1; + end + else if (backend_empty_i) pcc_jump_change_valid_n = 1'b0; + else pcc_jump_change_valid_n = pcc_jump_change_valid_q; + + if (resolved_branch_i.valid) pcc_jump_change_n = resolved_branch_i.target_address; end if (CVA6Cfg.RVH) begin tinst_n = issue_instr_i.ex.tinst; @@ -350,13 +445,6 @@ module issue_read_operands ))) begin operand_b_n = issue_instr_i.result; end - // use the DDC as operand - if (CVA6Cfg.CheriPresent && issue_instr_i.use_ddc) begin - if (issue_instr_i.op == ariane_pkg::CTO_PTR) - operand_b_n = issue_instr_i.ddc; - else if (issue_instr_i.op inside{ariane_pkg::CFROM_PTR, ariane_pkg::CTEST_SUBSET, ariane_pkg::CBUILD_CAP}) - operand_a_n = issue_instr_i.ddc; - end end // FU select, assert the correct valid out signal (in the next cycle) @@ -652,10 +740,13 @@ module issue_read_operands rs1_q <= '0; rs2_q <= '0; use_ddc_q <= '0; + pcc_q <= cva6_cheri_pkg::PCC_ROOT_CAP; + pcc_jump_change_valid_q <= '0; end pc_o <= '0; is_compressed_instr_o <= 1'b0; branch_predict_o <= {cf_t'(0), {CVA6Cfg.VLEN{1'b0}}}; + if (CVA6Cfg.RVFI_DII) dii_id_o <= '0; end else begin operand_a_q <= operand_a_n; operand_b_q <= operand_b_n; @@ -670,10 +761,14 @@ module issue_read_operands rs1_q <= rs1_n; rs2_q <= rs2_n; use_ddc_q <= use_ddc_n; + pcc_q <= pcc_n; + pcc_jump_change_valid_q <= pcc_jump_change_valid_n; + pcc_jump_change_q <= pcc_jump_change_n; end - pc_o <= issue_instr_i.pc; + pc_o <= cva6_cheri_pkg::set_cap_reg_address(pcc_q, issue_instr_i.pc, cva6_cheri_pkg::get_cap_reg_meta_data(pcc_q)); is_compressed_instr_o <= issue_instr_i.is_compressed; branch_predict_o <= issue_instr_i.bp; + if (CVA6Cfg.RVFI_DII) dii_id_o <= issue_instr_i.dii_id; end end diff --git a/core/issue_stage.sv b/core/issue_stage.sv index 7b492cdf0..fd12d47f7 100644 --- a/core/issue_stage.sv +++ b/core/issue_stage.sv @@ -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 @@ -54,6 +55,8 @@ module issue_stage output fu_data_t fu_data_o, // Program Counter - EX_STAGE output logic [CVA6Cfg.PCLEN-1:0] pc_o, + // DII ID - EX_STAGE + output logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Is compressed instruction - EX_STAGE output logic is_compressed_instr_o, // Transformed trap instruction - EX_STAGE @@ -126,6 +129,18 @@ module issue_stage output scoreboard_entry_t [CVA6Cfg.NrCommitPorts-1:0] commit_instr_o, // Commit acknowledge - COMMIT_STAGE input logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack_i, + // Exception event - COMMIT + input logic ex_valid_i, + // Program counter capability last committed - TO_BE_COMPLETED + input logic [CVA6Cfg.REGLEN-1:0] pcc_commit_i, + // Set COMMIT PC as next PC requested by FENCE, CSR side-effect and Accelerate port - CONTROLLER + input logic set_pc_commit_i, + // Next PC when jumping into exception - CSR_FILE + input logic [CVA6Cfg.REGLEN-1:0] trap_vector_base_i, + // Exception PC - CSR_FILE + input logic [CVA6Cfg.REGLEN-1:0] epc_i, + // ERET now - CSR_FILE + input logic eret_i, // Issue stall - PERF_COUNTERS output logic stall_issue_o, // Information dedicated to RVFI - RVFI @@ -161,10 +176,13 @@ module issue_stage logic [ CVA6Cfg.REGLEN-1:0] rs1_forwarding_xlen; logic [ CVA6Cfg.REGLEN-1:0] rs2_forwarding_xlen; + logic backend_empty; + + exception_t issue_pcc_ex; + assign rs1_forwarding_o = rs1_forwarding_xlen; assign rs2_forwarding_o = rs2_forwarding_xlen; - assign issue_instr_o = issue_instr_sb_iro[0]; assign issue_instr_hs_o = issue_instr_valid_sb_iro[0] & issue_ack_iro_sb[0]; @@ -198,6 +216,8 @@ module issue_stage .orig_instr_o (orig_instr_sb_iro), .issue_instr_valid_o (issue_instr_valid_sb_iro), .issue_ack_i (issue_ack_iro_sb), + .issue_pcc_ex_i (issue_pcc_ex), + .backend_empty_o (backend_empty), .resolved_branch_i(resolved_branch_i), .trans_id_i (trans_id_i), @@ -211,7 +231,9 @@ module issue_stage // --------------------------------------------------------- issue_read_operands #( .CVA6Cfg(CVA6Cfg), + .bp_resolve_t(bp_resolve_t), .branchpredict_sbe_t(branchpredict_sbe_t), + .exception_t(exception_t), .fu_data_t(fu_data_t), .scoreboard_entry_t(scoreboard_entry_t), .rs3_len_t(rs3_len_t) @@ -221,6 +243,8 @@ module issue_stage .orig_instr_i (orig_instr_sb_iro[0]), .issue_instr_valid_i(issue_instr_valid_sb_iro[0]), .issue_ack_o (issue_ack_iro_sb[0]), + .issue_pcc_ex_o (issue_pcc_ex), + .backend_empty_i (backend_empty), .fu_data_o (fu_data_o), .flu_ready_i (flu_ready_i), .rs1_o (rs1_iro_sb), diff --git a/core/load_unit.sv b/core/load_unit.sv index 9421ff926..f085d9dbf 100644 --- a/core/load_unit.sv +++ b/core/load_unit.sv @@ -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 diff --git a/core/rvfi_dii_generator.sv b/core/rvfi_dii_generator.sv index 3ec1fa1b6..3f9fd1f23 100644 --- a/core/rvfi_dii_generator.sv +++ b/core/rvfi_dii_generator.sv @@ -1,5 +1,6 @@ // 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 @@ -14,6 +15,11 @@ // // Date: 01.01.2025 // Description: CVA6 RVFI DII Generator +// + +import "DPI-C" function byte get_dii_cmd(int idx); +import "DPI-C" function int get_dii_insn(int idx); +import "DPI-C" function int test_dii_start(); `include "common_cells/registers.svh" @@ -24,54 +30,88 @@ module rvfi_dii_generator parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, parameter type icache_dreq_t = logic, parameter type icache_drsp_t = logic, - parameter type exception_t = logic, - parameter type rvfi_dii_inst_pack_t = logic + parameter type exception_t = logic ) ( input logic clk_i, input logic rst_ni, // data requests input icache_dreq_t dreq_i, - output icache_drsp_t dreq_o, - // refill port from Vengine - 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 icache_drsp_t dreq_o ); - logic [CVA6Cfg.VLEN-1:0] vaddr_d, vaddr_q; - exception_t ex_d, ex_q; - logic busy_q, busy_d; - assign vaddr_d = (~busy_q & dreq_i.req) ? dreq_i.vaddr : vaddr_q; - assign ex_d = (~busy_q & dreq_i.req) ? dreq_i.ex : ex_q; + logic [CVA6Cfg.FETCH_ALIGN_BITS:0] fetch_offset_q, fetch_offset_d; + logic [CVA6Cfg.FETCH_WIDTH*2-1:0] fetch_buff_q, fetch_buff_d; + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_q, dii_id_d; + logic busy; + logic flushing; + logic [CVA6Cfg.VLEN-1:0] vaddr_buff; + exception_t ex_buff; - always_comb begin : inject_instr - dreq_o.ex = ex_q; - dreq_o.vaddr = vaddr_q; - dreq_o.valid = 1'b0; - dreq_o.ready = 1'b0; - dreq_o.data = rvfi_dii_inst_pack_i.rvfi_insn; - rvfi_dii_data_ready_o = 1'b0; - busy_d = busy_q; - if (busy_q) begin - rvfi_dii_data_ready_o = 1'b1; - if (rvfi_dii_rtrn_vld_i) begin - busy_d = 1'b0; - dreq_o.valid = 1'b1; - end - // check for errors - if ((dreq_i.kill_s1 || dreq_i.kill_s2) && !ex_q.valid) begin - busy_d = 1'b0; - rvfi_dii_data_ready_o = 1'b0; - dreq_o.valid = 1'b0; + logic [CVA6Cfg.FETCH_WIDTH*2-1:0] instr; // Wider than needed to be shifted in + logic [2:0] instr_bytes; + logic test_done; + always_comb begin + dii_id_d = dii_id_q; + fetch_offset_d = fetch_offset_q; + fetch_buff_d = fetch_buff_q; + instr = '0; + instr_bytes = '0; + test_done = '0; + if (busy && !dreq_i.kill_s2) begin + // Assume the pipeline consumed the full buffer + fetch_offset_d = {1'b0, fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS-1:0]}; + fetch_buff_d = fetch_buff_d >> CVA6Cfg.FETCH_WIDTH; + // Shift the rest of the buffer into the requested slot + fetch_offset_d = fetch_offset_d + vaddr_buff[CVA6Cfg.FETCH_ALIGN_BITS-1:0]; + fetch_buff_d = fetch_buff_d << {vaddr_buff[CVA6Cfg.FETCH_ALIGN_BITS-1:0], 3'b0}; + while (~fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS] & (~fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS-1:0] != 0)) begin + test_done = get_dii_cmd(dii_id_d) == 0; + instr = test_done ? 32'h13 : get_dii_insn(dii_id_d); + instr_bytes = instr[1:0] == 2'b11 ? 3'd4 : 3'd2; + fetch_buff_d = fetch_buff_d | (instr << ({fetch_offset_d, 3'b0})); + fetch_offset_d = fetch_offset_d + instr_bytes; + dii_id_d = dii_id_d + (test_done ? 0 : 1); end + dreq_o.valid = 1'b1; end else begin - dreq_o.ready = 1'b1; - if (dreq_i.req && !dreq_i.kill_s1 && !dreq_i.kill_s2) - busy_d = 1'b1; + dreq_o.valid = 1'b0; end + dreq_o.ex = ex_buff; + dreq_o.vaddr = vaddr_buff; + dreq_o.data = fetch_buff_d; + dreq_o.user = '0; + dreq_o.ready = !dreq_i.kill_s1 && !dreq_i.kill_s2 && dreq_i.req; + dreq_o.dii_id = dii_id_q; end - `FFLARN(vaddr_q, vaddr_d, '1, '0, clk_i, rst_ni) - `FFLARN(ex_q, ex_d, '1, '0, clk_i, rst_ni) - `FFLARN(busy_q, busy_d, '1, '0, clk_i, rst_ni) - + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + dii_id_q <= test_dii_start(); + fetch_buff_q <= '0; + fetch_offset_q <= '0; + flushing <= '0; + busy <= '0; + end else begin + if (dreq_i.kill_s1 || dreq_i.kill_s2) begin + fetch_buff_q <= '0; + fetch_offset_q <= '0; + flushing <= 1; + busy <= '0; + end else begin + dii_id_q <= dii_id_d; + fetch_buff_q <= fetch_buff_d; + fetch_offset_q <= fetch_offset_d; + if (dreq_i.req) begin + busy <= 1; + vaddr_buff <= dreq_i.vaddr; + ex_buff <= dreq_i.ex; + if (flushing) begin + dii_id_q <= dreq_i.dii_id; + end + flushing <= 0; + end else begin + busy <= 0; + end + end + end + end endmodule diff --git a/core/scoreboard.sv b/core/scoreboard.sv index 9898d89d7..38397749d 100644 --- a/core/scoreboard.sv +++ b/core/scoreboard.sv @@ -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 @@ -79,8 +80,12 @@ module scoreboard #( output logic [ariane_pkg::SUPERSCALAR:0][31:0] orig_instr_o, // TO_BE_COMPLETED - TO_BE_COMPLETED output logic [ariane_pkg::SUPERSCALAR:0] issue_instr_valid_o, + // The next instruction to be issued is also the next to be committed - issue_read_operands + output logic backend_empty_o, // TO_BE_COMPLETED - TO_BE_COMPLETED input logic [ariane_pkg::SUPERSCALAR:0] issue_ack_i, + // An exception has been detected in issue_read_operands - issue_read_operands + input exception_t [ariane_pkg::SUPERSCALAR:0] issue_pcc_ex_i, // TO_BE_COMPLETED - TO_BE_COMPLETED input bp_resolve_t resolved_branch_i, @@ -124,6 +129,8 @@ module scoreboard #( assign sb_full_o = issue_full; + assign backend_empty_o = issue_pointer_q == commit_pointer_q[0]; + // output commit instruction directly always_comb begin : commit_ports for (int unsigned i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin @@ -174,6 +181,9 @@ module scoreboard #( decoded_instr_i[i] // decoded instruction record }; end + if (CVA6Cfg.CheriPresent && issue_pcc_ex_i[i].valid) begin + mem_n[issue_pointer[i]].sbe.ex = issue_pcc_ex_i[i]; + end end // ------------ @@ -210,10 +220,12 @@ module scoreboard #( mem_n[trans_id_i[i]].sbe.rd = 5'b0; end // write the exception back if it is valid - if (ex_i[i].valid) mem_n[trans_id_i[i]].sbe.ex = ex_i[i]; - // write the fflags back from the FPU (exception valid is never set), leave tval intact - else if(CVA6Cfg.FpPresent && (mem_q[trans_id_i[i]].sbe.fu == ariane_pkg::FPU || mem_q[trans_id_i[i]].sbe.fu == ariane_pkg::FPU_VEC)) begin - mem_n[trans_id_i[i]].sbe.ex.cause = ex_i[i].cause; + if (!mem_n[trans_id_i[i]].sbe.ex.valid) begin + if (ex_i[i].valid) mem_n[trans_id_i[i]].sbe.ex = ex_i[i]; + // write the fflags back from the FPU (exception valid is never set), leave tval intact + else if(CVA6Cfg.FpPresent && (mem_q[trans_id_i[i]].sbe.fu == ariane_pkg::FPU || mem_q[trans_id_i[i]].sbe.fu == ariane_pkg::FPU_VEC)) begin + mem_n[trans_id_i[i]].sbe.ex.cause = ex_i[i].cause; + end end end end diff --git a/corev_apu/fpga/src/ariane_xilinx.sv b/corev_apu/fpga/src/ariane_xilinx.sv index 05f2609f2..599c72048 100644 --- a/corev_apu/fpga/src/ariane_xilinx.sv +++ b/corev_apu/fpga/src/ariane_xilinx.sv @@ -786,9 +786,6 @@ ariane #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o( /* open */ ), - .rvfi_dii_rtrn_vld_i ('0), - .rvfi_dii_inst_pack_i ('0), - .rvfi_dii_data_ready_o (/* open */ ), .debug_req_i ( debug_req_irq ), .noc_req_o ( axi_ariane_req ), .noc_resp_i ( axi_ariane_resp ) diff --git a/corev_apu/src/ariane.sv b/corev_apu/src/ariane.sv index 37085ecce..9ccf9f930 100644 --- a/corev_apu/src/ariane.sv +++ b/corev_apu/src/ariane.sv @@ -21,7 +21,6 @@ module ariane import ariane_pkg::*; #( logic csr; logic instr; }, - parameter type rvfi_dii_inst_pack_t = logic, parameter int unsigned AxiAddrWidth = ariane_axi::AddrWidth, parameter int unsigned AxiDataWidth = ariane_axi::DataWidth, parameter int unsigned AxiIdWidth = ariane_axi::IdWidth, @@ -46,9 +45,6 @@ module ariane import ariane_pkg::*; #( // RISC-V formal interface port (`rvfi`): // Can be left open when formal tracing is not needed. output rvfi_probes_t rvfi_probes_o, - 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, // memory side output noc_req_t noc_req_o, input noc_resp_t noc_resp_i @@ -77,9 +73,6 @@ module ariane import ariane_pkg::*; #( .time_irq_i ( time_irq_i ), .debug_req_i ( debug_req_i ), .rvfi_probes_o ( rvfi_probes_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 ), .cvxif_req_o ( cvxif_req ), .cvxif_resp_i ( cvxif_resp ), .noc_req_o ( noc_req_o ), diff --git a/corev_apu/tb/ariane_testharness.sv b/corev_apu/tb/ariane_testharness.sv index 5adfd4093..13c129ddb 100644 --- a/corev_apu/tb/ariane_testharness.sv +++ b/corev_apu/tb/ariane_testharness.sv @@ -58,7 +58,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( rvfi_probes_csr_t csr; rvfi_probes_instr_t instr; }; - localparam type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg); // disable test-enable logic test_en; @@ -744,7 +743,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( .rvfi_probes_instr_t ( rvfi_probes_instr_t ), .rvfi_probes_csr_t ( rvfi_probes_csr_t ), .rvfi_probes_t ( rvfi_probes_t ), - .rvfi_dii_inst_pack_t ( rvfi_dii_inst_pack_t ), .noc_req_t ( ariane_axi::req_t ), .noc_resp_t ( ariane_axi::resp_t ) ) i_ariane ( @@ -756,9 +754,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o ( rvfi_probes ), - .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), // Disable Debug when simulating with Spike `ifdef SPIKE_TANDEM .debug_req_i ( 1'b0 ), diff --git a/corev_apu/tb/common/SimDTM.sv b/corev_apu/tb/common/SimDTM.sv index 293e7841b..e0613e418 100644 --- a/corev_apu/tb/common/SimDTM.sv +++ b/corev_apu/tb/common/SimDTM.sv @@ -1,6 +1,7 @@ // See LICENSE.SiFive for license details. //VCS coverage exclude_file +`ifndef DII import "DPI-C" function int debug_tick ( output bit debug_req_valid, @@ -14,6 +15,7 @@ import "DPI-C" function int debug_tick input int debug_resp_bits_resp, input int debug_resp_bits_data ); +`endif module SimDTM( input clk, @@ -65,6 +67,7 @@ module SimDTM( end else begin + `ifndef DII __exit = debug_tick( __debug_req_valid, __debug_req_ready, @@ -76,6 +79,7 @@ module SimDTM( __debug_resp_bits_resp, __debug_resp_bits_data ); + `endif end end endmodule diff --git a/corev_apu/tb/common/SimJTAG.sv b/corev_apu/tb/common/SimJTAG.sv index 473d892ec..0be1a3693 100644 --- a/corev_apu/tb/common/SimJTAG.sv +++ b/corev_apu/tb/common/SimJTAG.sv @@ -1,5 +1,6 @@ // See LICENSE.SiFive for license details. //VCS coverage exclude_file +`ifndef DII import "DPI-C" function int jtag_tick ( output bit jtag_TCK, @@ -9,6 +10,7 @@ import "DPI-C" function int jtag_tick input bit jtag_TDO ); +`endif module SimJTAG #( parameter TICK_DELAY = 50 @@ -69,12 +71,14 @@ module SimJTAG #( if (enable && init_done_sticky) begin tickCounterReg <= tickCounterNxt; if (tickCounterReg == 0) begin + `ifndef DII __exit = jtag_tick( __jtag_TCK, __jtag_TMS, __jtag_TDI, __jtag_TRSTn, __jtag_TDO); + `endif end end // if (enable && init_done_sticky) end // else: !if(reset || r_reset) diff --git a/corev_apu/tb/rvfi_tracer.sv b/corev_apu/tb/rvfi_tracer.sv index 004edaedd..92ae7d15f 100644 --- a/corev_apu/tb/rvfi_tracer.sv +++ b/corev_apu/tb/rvfi_tracer.sv @@ -7,6 +7,7 @@ // // Original Author: Jean-Roch COULON - Thales // +`ifndef DII `ifndef READ_SYMBOL_T `define READ_SYMBOL_T import "DPI-C" function byte read_symbol (input string symbol_name, inout longint unsigned address); @@ -18,6 +19,7 @@ import "DPI-C" function void read_elf(input string filename); import "DPI-C" function byte get_section(output longint address, output longint len); import "DPI-C" context function read_section_sv(input longint address, inout byte buffer[]); `endif +`endif module rvfi_tracer #( @@ -45,6 +47,7 @@ module rvfi_tracer #( f = $fopen($sformatf("trace_rvfi_hart_%h.dasm", HART_ID), "w"); if (!$value$plusargs("time_out=%d", SIM_FINISH)) SIM_FINISH = 2000000; if (!$value$plusargs("tohost_addr=%h", TOHOST_ADDR)) TOHOST_ADDR = '0; +`ifndef DII if (TOHOST_ADDR == '0) begin if (!$value$plusargs("elf_file=%s", binary)) binary = ""; if (binary != "") begin @@ -58,6 +61,7 @@ module rvfi_tracer #( $fwrite(f, "*** [rvfi_tracer] WARNING No valid address of 'tohost' (tohost == 0x%h), termination possible only by timeout or Ctrl-C!\n", TOHOST_ADDR); end end +`endif end final $fclose(f); diff --git a/corev_apu/tb/tb_testRig_cheri/Makefile b/corev_apu/tb/tb_testRig_cheri/Makefile index 338f27575..f2a39e5ad 100644 --- a/corev_apu/tb/tb_testRig_cheri/Makefile +++ b/corev_apu/tb/tb_testRig_cheri/Makefile @@ -1,4 +1,5 @@ # Copyright 2025 Bruno Sá and Zero-Day Labs. +# Copyright 2025 Capabilities Limited. # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -16,25 +17,24 @@ # specific language governing permissions and limitations # under the License. +# root path +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +root-dir := $(abspath $(dir $(mkfile_path))../../..)/ + # questa library library ?= work # verilator lib ver-library ?= work-ver -# library for DPI -dpi-library ?= work-dpi # Top level module to compile top_level ?= ariane_tb # Maximum amount of cycles for a successful simulation run max_cycles ?= 10000000 # verilator version -verilator ?= /media/ninolomata/Nino1/CHERI/TestRIG/riscv-implementations/cva6/tools/verilator/bin/verilator +verilator ?= $(root-dir)/tools/verilator-v5.015/bin/verilator # traget option target-options ?= # additional definess defines ?= WT_DCACHE -# root path -mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) -root-dir := $(abspath $(dir $(mkfile_path))../../..)/ ifndef CVA6_REPO_DIR $(warning must set CVA6_REPO_DIR to point at the root of CVA6 sources -- doing it for you...) @@ -50,8 +50,6 @@ ifndef RISCV $(error RISCV not set - please point your RISCV variable to your RISCV installation) endif -SPIKE_INSTALL_DIR ?= $(root-dir)/tools/spike - target ?= cv64a6_imafdch_sv39_rvfi_dii ifeq ($(target), cv64a6_imafdch_sv39_rvfi_dii) XLEN ?= 64 @@ -95,28 +93,14 @@ util := $(addprefix $(root-dir), $(util)) test_pkg := $(wildcard tb/test/*/*sequence_pkg.sv*) \ $(wildcard tb/test/*/*_pkg.sv*) -# DPI - dpi := $(patsubst $(root-dir)/corev_apu/tb/dpi/%.cc, ${dpi-library}/%.o, $(wildcard $(root-dir)/corev_apu/tb/dpi/*.cc)) - -dpi_hdr := $(wildcard $(root-dir)/corev_apu/tb/dpi/*.h) -# dpi_hdr := $(addprefix $(root-dir), $(dpi_hdr)) - CFLAGS := -I$(QUESTASIM_HOME)/include \ -I$(VCS_HOME)/include \ -I$(RISCV)/include \ - -I$(SPIKE_ROOT)/include \ - -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/inc \ - -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils \ - -std=c++11 -I$(root-dir)/corev_apu/tb/dpi -O3 + -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils \ + -I$(root-dir)/corev_apu/tb/dpi -O3 # this list contains the standalone components src := $(root-dir)/core/include/$(target)_config_pkg.sv \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_core_cntrl_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_cva6pkg_utils_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_rvfi_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvmc_rvfi_reference_model_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvmc_rvfi_scoreboard_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/corev_apu/tb/common/spike.sv) \ $(root-dir)/corev_apu/src/ariane.sv \ $(wildcard $(root-dir)/corev_apu/bootrom/*.sv) \ $(wildcard $(root-dir)/corev_apu/clint/*.sv) \ @@ -130,8 +114,6 @@ src := $(root-dir)/core/include/$(target)_config_pkg.sv $(root-dir)/corev_apu/rv_plic/rtl/plic_regmap.sv \ $(root-dir)/corev_apu/rv_plic/rtl/plic_top.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dmi_cdc.sv \ - $(root-dir)/corev_apu/riscv-dbg/src/dmi_jtag.sv \ - $(root-dir)/corev_apu/riscv-dbg/src/dmi_jtag_tap.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_csrs.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_mem.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_sba.sv \ @@ -199,13 +181,10 @@ src := $(root-dir)/core/include/$(target)_config_pkg.sv $(root-dir)/vendor/zero-day/axi_tagcontroller/src/axi_tagctrl_top.sv \ $(root-dir)/vendor/zero-day/axi_tagcontroller/src/axi_tagctrl_reg_wrap.sv \ $(root-dir)/corev_apu/tb/ariane_testharness.sv \ - $(root-dir)/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv \ $(root-dir)/corev_apu/tb/cva6_cheri_tag_mem.sv \ $(root-dir)/corev_apu/tb/ariane_peripherals.sv \ $(root-dir)/corev_apu/tb/rvfi_tracer.sv \ $(root-dir)/corev_apu/tb/common/uart.sv \ - $(root-dir)/corev_apu/tb/common/SimDTM.sv \ - $(root-dir)/corev_apu/tb/common/SimJTAG.sv \ $(root-dir)/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv copro_src := core/cvxif_example/include/cvxif_instr_pkg.sv \ @@ -260,14 +239,14 @@ verilate_command := $(verilator) --no-timing $(root-dir)/verilator_config.vlt -Wno-BLKANDNBLK \ -Wno-style \ $(if $(DEBUG), --trace --trace-structs ) \ - -LDFLAGS "-L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -L../corev_apu/tb/dromajo/src -ldromajo_cosim,) -lpthread" \ + -LDFLAGS "-L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -L../corev_apu/tb/dromajo/src -ldromajo_cosim,) -lpthread" \ -CFLAGS "$(CFLAGS)$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -DDROMAJO=1,) -DVL_DEBUG" \ -Wall --cc --vpi \ $(list_incdir) --top-module ariane_testharness_dii \ --threads-dpi none \ --Mdir $(ver-library) -O3 \ - --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils/socket_packet_utils.c ${root-dir}/corev_apu/tb/dpi/SimDTM.cc ${root-dir}/corev_apu/tb/dpi/SimJTAG.cc \ - ${root-dir}/corev_apu/tb/dpi/remote_bitbang.cc ${root-dir}/corev_apu/tb/dpi/msim_helper.cc + --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils/rvfi_dii_utils.c \ + ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils/SocketPacketUtils/socket_packet_utils.c # User Verilator, at some point in the future this will be auto-generated verilate: @@ -278,7 +257,7 @@ verilate: clean: rm -rf $(riscv-torture-dir)/output/test* - rm -rf $(library)/ $(dpi-library)/ $(ver-library)/ + rm -rf $(library)/ $(ver-library)/ rm -f tmp/*.ucdb tmp/*.log *.wlf *vstf wlft* *.ucdb .PHONY: diff --git a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv index 9dc411f26..4bef0f04d 100644 --- a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv +++ b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv @@ -1,4 +1,5 @@ // 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 @@ -31,7 +32,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( parameter int unsigned AXI_USER_EN = CVA6Cfg.AXI_USER_EN, parameter int unsigned AXI_ADDRESS_WIDTH = 64, parameter int unsigned AXI_DATA_WIDTH = 64, - parameter bit InclSimDTM = 1'b1, parameter int unsigned NUM_WORDS = 2**25, // memory size parameter bit StallRandomOutput = 1'b0, parameter bit StallRandomInput = 1'b0 @@ -49,12 +49,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( output logic [ 1:0] rvfi_mode_o, output logic [ 4:0] rvfi_rs1_addr_o, output logic [ 4:0] rvfi_rs2_addr_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rs1_rdata_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rs2_rdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rs1_rdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rs2_rdata_o, output logic [ 4:0] rvfi_rd_addr_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rd_wdata_o, - output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_rdata_o, - output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_wdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rd_wdata_o, + output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_rdata_o, + output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_wdata_o, output logic [CVA6Cfg.XLEN-1:0] rvfi_mem_addr_o, output logic [(CVA6Cfg.CLEN/8)-1:0] rvfi_mem_rmask_o, output logic [(CVA6Cfg.CLEN/8)-1:0] rvfi_mem_wmask_o, @@ -62,11 +62,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( output logic [CVA6Cfg.XLEN-1:0] rvfi_mem_wdata_o, `endif -`ifdef DII - input logic [31:0] dii_insn_i, - output logic dii_ready_o, - input logic dii_valid_i, -`endif output logic [31:0] exit_o ); @@ -84,51 +79,19 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( rvfi_probes_csr_t csr; rvfi_probes_instr_t instr; }; - localparam type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg); // disable test-enable logic test_en; logic ndmreset; logic ndmreset_n; - logic debug_req_core; - int jtag_enable; logic init_done; - logic [31:0] jtag_exit, dmi_exit; logic [31:0] rvfi_exit; - logic jtag_TCK; - logic jtag_TMS; - logic jtag_TDI; - logic jtag_TRSTn; - logic jtag_TDO_data; - logic jtag_TDO_driven; - - logic debug_req_valid; logic debug_req_ready; logic debug_resp_valid; logic debug_resp_ready; - logic jtag_req_valid; - logic [6:0] jtag_req_bits_addr; - logic [1:0] jtag_req_bits_op; - logic [31:0] jtag_req_bits_data; - logic jtag_resp_ready; - logic jtag_resp_valid; - - logic dmi_req_valid; - logic dmi_resp_ready; - logic dmi_resp_valid; - - dm::dmi_req_t jtag_dmi_req; - dm::dmi_req_t dmi_req; - - dm::dmi_req_t debug_req; - dm::dmi_resp_t debug_resp; - - logic [31:0] dii_insn; - logic dii_ready; - assign test_en = 1'b0; AXI_BUS #( @@ -160,106 +123,9 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( logic debug_enable; initial begin - if (!$value$plusargs("jtag_rbb_enable=%b", jtag_enable)) jtag_enable = 'h0; - if ($test$plusargs("debug_disable")) debug_enable = 'h0; else debug_enable = 'h1; if (CVA6Cfg.XLEN != 32 & CVA6Cfg.XLEN != 64) $error("CVA6Cfg.XLEN different from 32 and 64"); end - // debug if MUX - assign debug_req_valid = (jtag_enable[0]) ? jtag_req_valid : dmi_req_valid; - assign debug_resp_ready = (jtag_enable[0]) ? jtag_resp_ready : dmi_resp_ready; - assign debug_req = (jtag_enable[0]) ? jtag_dmi_req : dmi_req; - if (ariane_pkg::RVFI) begin - assign exit_o = (jtag_enable[0]) ? jtag_exit : rvfi_exit; - end else begin - assign exit_o = (jtag_enable[0]) ? jtag_exit : dmi_exit; - end - assign jtag_resp_valid = (jtag_enable[0]) ? debug_resp_valid : 1'b0; - assign dmi_resp_valid = (jtag_enable[0]) ? 1'b0 : debug_resp_valid; - - // SiFive's SimJTAG Module - // Converts to DPI calls - SimJTAG i_SimJTAG ( - .clock ( clk_i ), - .reset ( ~rst_ni ), - .enable ( jtag_enable[0] ), - .init_done ( init_done ), - .jtag_TCK ( jtag_TCK ), - .jtag_TMS ( jtag_TMS ), - .jtag_TDI ( jtag_TDI ), - .jtag_TRSTn ( jtag_TRSTn ), - .jtag_TDO_data ( jtag_TDO_data ), - .jtag_TDO_driven ( jtag_TDO_driven ), - .exit ( jtag_exit ) - ); - - dmi_jtag i_dmi_jtag ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( test_en ), - .dmi_req_o ( jtag_dmi_req ), - .dmi_req_valid_o ( jtag_req_valid ), - .dmi_req_ready_i ( debug_req_ready ), - .dmi_resp_i ( debug_resp ), - .dmi_resp_ready_o ( jtag_resp_ready ), - .dmi_resp_valid_i ( jtag_resp_valid ), - .dmi_rst_no ( ), // not connected - .tck_i ( jtag_TCK ), - .tms_i ( jtag_TMS ), - .trst_ni ( jtag_TRSTn ), - .td_i ( jtag_TDI ), - .td_o ( jtag_TDO_data ), - .tdo_oe_o ( jtag_TDO_driven ) - ); - - // SiFive's SimDTM Module - // Converts to DPI calls - logic [1:0] debug_req_bits_op; - assign dmi_req.op = dm::dtm_op_e'(debug_req_bits_op); - - if (InclSimDTM) begin - SimDTM i_SimDTM ( - .clk ( clk_i ), - .reset ( ~rst_ni ), - .debug_req_valid ( dmi_req_valid ), - .debug_req_ready ( debug_req_ready ), - .debug_req_bits_addr ( dmi_req.addr ), - .debug_req_bits_op ( debug_req_bits_op ), - .debug_req_bits_data ( dmi_req.data ), - .debug_resp_valid ( dmi_resp_valid ), - .debug_resp_ready ( dmi_resp_ready ), - .debug_resp_bits_resp ( debug_resp.resp ), - .debug_resp_bits_data ( debug_resp.data ), - .exit ( dmi_exit ) - ); - end else begin - assign dmi_req_valid = '0; - assign debug_req_bits_op = '0; - assign dmi_exit = 1'b0; - end - - // this delay window allows the core to read and execute init code - // from the bootrom before the first debug request can interrupt - // core. this is needed in cases where an fsbl is involved that - // expects a0 and a1 to be initialized with the hart id and a - // pointer to the dev tree, respectively. - localparam int unsigned DmiDelCycles = 500; - - logic debug_req_core_ungtd; - int dmi_del_cnt_d, dmi_del_cnt_q; - - assign dmi_del_cnt_d = (dmi_del_cnt_q) ? dmi_del_cnt_q - 1 : 0; - assign debug_req_core = (dmi_del_cnt_q) ? 1'b0 : - (!debug_enable) ? 1'b0 : debug_req_core_ungtd; - - always_ff @(posedge clk_i or negedge rst_ni) begin : p_dmi_del_cnt - if(!rst_ni) begin - dmi_del_cnt_q <= DmiDelCycles; - end else begin - dmi_del_cnt_q <= dmi_del_cnt_d; - end - end - ariane_axi::req_t dm_axi_m_req; ariane_axi::resp_t dm_axi_m_resp; @@ -290,7 +156,7 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .testmode_i ( test_en ), .ndmreset_o ( ndmreset ), .dmactive_o ( ), // active debug session - .debug_req_o ( debug_req_core_ungtd ), + .debug_req_o ( /* NC */ ), .unavailable_i ( '0 ), .hartinfo_i ( {ariane_pkg::DebugHartInfo} ), .slave_req_i ( dm_slave_req ), @@ -308,12 +174,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .master_r_valid_i ( dm_master_r_valid ), .master_r_rdata_i ( dm_master_r_rdata ), .dmi_rst_ni ( rst_ni ), - .dmi_req_valid_i ( debug_req_valid ), - .dmi_req_ready_o ( debug_req_ready ), - .dmi_req_i ( debug_req ), - .dmi_resp_valid_o ( debug_resp_valid ), - .dmi_resp_ready_i ( debug_resp_ready ), - .dmi_resp_o ( debug_resp ) + .dmi_req_valid_i ( 1'b0 ), + .dmi_req_ready_o ( /* NC */ ), + .dmi_req_i ( /* NC */ ), + .dmi_resp_valid_o ( /* NC */ ), + .dmi_resp_ready_i ( 1'b0 ), + .dmi_resp_o ( /* NC */ ) ); @@ -769,19 +635,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( else boot_cap.addr = ariane_soc::ROMBase; end - rvfi_dii_inst_pack_t rvfi_dii_inst_pack; - - always_comb begin : gen_rvfi_dii - rvfi_dii_inst_pack = '0; - rvfi_dii_inst_pack.rvfi_insn = dii_insn; - end ariane #( .CVA6Cfg ( CVA6Cfg ), .rvfi_probes_instr_t ( rvfi_probes_instr_t ), .rvfi_probes_csr_t ( rvfi_probes_csr_t ), .rvfi_probes_t ( rvfi_probes_t ), - .rvfi_dii_inst_pack_t ( rvfi_dii_inst_pack_t ), .noc_req_t ( ariane_axi::req_t ), .noc_resp_t ( ariane_axi::resp_t ) ) i_ariane ( @@ -793,9 +652,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o ( rvfi_probes ), - .rvfi_dii_rtrn_vld_i ( dii_valid_i ), - .rvfi_dii_inst_pack_i ( dii_insn_i ), - .rvfi_dii_data_ready_o ( dii_ready_o ), // Disable Debug when simulating with Spike `ifdef SPIKE_TANDEM .debug_req_i ( 1'b0 ), diff --git a/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils b/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils new file mode 160000 index 000000000..69a06c7cf --- /dev/null +++ b/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils @@ -0,0 +1 @@ +Subproject commit 69a06c7cf45bb7735ad483b355b8378f7bab7b21 diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index ff4977045..799100259 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -1,5 +1,6 @@ // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -16,6 +17,8 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. +// +// Copyright 2025 Capabilities Limited #include "verilator.h" #include "verilated.h" @@ -36,117 +39,34 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include "remote_bitbang.h" -#include +//Exclude DII getters as they are defined in a verilator header for DPI +#define exclude_dii_getters +#include + +#define DII_ID_WIDTH 6 +#define DII_ID_COUNT (1 << DII_ID_WIDTH) // This software is heavily based on Rocket Chip // Checkout this awesome project: // https://github.com/freechipsproject/rocket-chip/ -#define DII 1 // This is a 64-bit integer to reduce wrap over issues and // allow modulus. You can also use a double, if you wish. static vluint64_t main_time = 0; -static const char *verilog_plusargs[] = {"jtag_rbb_enable", "time_out", "debug_disable"}; - -#ifndef DROMAJO -extern dtm_t* dtm; -extern remote_bitbang_t * jtag; - -void handle_sigterm(int sig) { - dtm->stop(); -} -#endif - -#ifdef DII - struct RVFI_DII_Execution_Packet { - std::uint64_t rvfi_order : 64; // [00 - 07] Instruction number: INSTRET value after completion. - std::uint64_t rvfi_pc_rdata : 64; // [08 - 15] PC before instr: PC for current instruction - std::uint64_t rvfi_pc_wdata : 64; // [16 - 23] PC after instr: Following PC - either PC + 4 or jump/trap target. - std::uint64_t rvfi_insn : 64; // [24 - 31] Instruction word: 32-bit command value. - std::uint64_t rvfi_rs1_data : 64; // [32 - 39] Read register values: Values as read from registers named - std::uint64_t rvfi_rs2_data : 64; // [40 - 47] above. Must be 0 if register ID is 0. - std::uint64_t rvfi_rd_wdata : 64; // [48 - 55] Write register value: MUST be 0 if rd_ is 0. - std::uint64_t rvfi_mem_addr : 64; // [56 - 63] Memory access addr: Points to byte address (aligned if define - // is set). *Should* be straightforward. - // 0 if unused. - std::uint64_t rvfi_mem_rdata : 64; // [64 - 71] Read data: Data read from mem_addr (i.e. before write) - std::uint64_t rvfi_mem_wdata : 64; // [72 - 79] Write data: Data written to memory by this command. - std::uint8_t rvfi_mem_rmask : 8; // [80] Read mask: Indicates valid bytes read. 0 if unused. - std::uint8_t rvfi_mem_wmask : 8; // [81] Write mask: Indicates valid bytes written. 0 if unused. - std::uint8_t rvfi_rs1_addr : 8; // [82] Read register addresses: Can be arbitrary when not used, - std::uint8_t rvfi_rs2_addr : 8; // [83] otherwise set as decoded. - std::uint8_t rvfi_rd_addr : 8; // [84] Write register address: MUST be 0 if not used. - std::uint8_t rvfi_trap : 8; // [85] Trap indicator: Invalid decode, misaligned access or - // jump command to misaligned address. - std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired - // before halting execution. - std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. -}; - -struct RVFI_DII_Instruction_Packet { - std::uint32_t dii_insn : 32; // [0 - 3] Instruction word: 32-bit instruction or command. The lower 16-bits - // may decode to a 16-bit compressed instruction. - std::uint16_t dii_time : 16; // [5 - 4] Time to inject token. The difference between this and the previous - // instruction time gives a delay before injecting this instruction. - // This can be ignored for models but gives repeatability for implementations - // while shortening counterexamples. - std::uint8_t dii_cmd : 8; // [6] This token is a trace command. For example, reset device under test. - std::uint8_t padding : 8; // [7] -}; - -#endif - -extern "C" void read_elf(const char* filename); -extern "C" char get_section (long long* address, long long* len); -extern "C" void read_section_void(long long address, void * buffer, uint64_t size = 0); +static const char *verilog_plusargs[] = {"time_out"}; -void PrintInstTrace(RVFI_DII_Instruction_Packet* packet){ - std::cout << "<------Start instruction trace------>" << std::endl; - std::cout << "cmd: " << ((packet->dii_cmd == 0) ? "End of Trace" : "Instruction") << std::endl; - std::cout << "time: " << (int) packet->dii_time << std::endl; - std::cout << "insn: " << std::hex << packet->dii_insn << std::endl; - std::cout << "<------Finish instruction trace------>" << std::endl; -} - -void PrintExecTrace(RVFI_DII_Execution_Packet* packet){ - std::cout << "<------Start execution trace------>" << std::endl; - std::cout << "order: " << (int) packet->rvfi_order << std::endl; - std::cout << "pc_rdata: " << std::hex << (int) packet->rvfi_pc_rdata << std::endl; - std::cout << "pc_wdata: " << std::hex << (int) packet->rvfi_pc_wdata << std::endl; - std::cout << "insn: " << std::hex << (int) packet->rvfi_insn << std::endl; - std::cout << "rs1_data: " << std::hex << (int) packet->rvfi_rs1_data << std::endl; - std::cout << "rs2_data: " << std::hex << (int) packet->rvfi_rs2_data << std::endl; - std::cout << "rd_wdata: " << std::hex << (int) packet->rvfi_rd_wdata << std::endl; - std::cout << "mem_addr: " << std::hex << (int) packet->rvfi_mem_addr << std::endl; - std::cout << "mem_rdatal: " << std::hex << (int)packet->rvfi_mem_rdata << std::endl; - std::cout << "mem_wdatal: " << std::hex << (int) packet->rvfi_mem_wdata << std::endl; - std::cout << "mem_rmask: " << std::hex << (int) packet->rvfi_mem_rmask << std::endl; - std::cout << "mem_wmask: " << std::hex << (int) packet->rvfi_mem_wmask << std::endl; - std::cout << "rs1_addr: " << std::hex << (int) packet->rvfi_rs1_addr << std::endl; - std::cout << "rs2_addr: " << std::hex << (int) packet->rvfi_rs2_addr << std::endl; - std::cout << "rd_addr: " << std::hex << (int) packet->rvfi_rd_addr << std::endl; - std::cout << "trap: " << (int) packet->rvfi_trap << std::endl; - std::cout << "halt: " << (int) packet->rvfi_halt << std::endl; - std::cout << "instr: " << std::hex << (int) packet->rvfi_intr << std::endl; - std::cout << "<------Finish execution trace------>" << std::endl; -} +static int current_test_dii_start = 0; // Routine to fetch intructions from the Vengine -void fetchInstructions(std::vector &instructions, unsigned int &cnt_rec, unsigned long long socket); -RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top); -void returnTrace(std::vector &returntrace, unsigned long long socket); -bool readTrace(std::vector &returntrace, Variane_testharness_dii *top); +rvfi_pkt_t readRVFI(Variane_testharness_dii *top); +bool readTrace(Variane_testharness_dii *top, unsigned int rvfi_id); +void sendReset(unsigned int rvfi_id); // Called by $time in Verilog converts to double, to match what SystemC does double sc_time_stamp () { @@ -175,10 +95,8 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", fputs("\ -v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\ -f, --fst=FILE, Write fst trace to FILE\n\ - -p, Print performance statistic at end of test\n\ ", stdout); // fputs("\n" PLUSARG_USAGE_OPTIONS, stdout); - fputs("\n" HTIF_USAGE_OPTIONS, stdout); printf("\n" "EXAMPLES\n" " - run a bare metal test:\n" @@ -194,87 +112,50 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", , program_name, program_name); } -// In case we use the DTM we do not want to use the JTAG -// to preload the data but only use the DTM to host fesvr functionality. -class preload_aware_dtm_t : public dtm_t { - public: - preload_aware_dtm_t(int argc, char **argv) : dtm_t(argc, argv) {} - bool is_address_preloaded(addr_t taddr, size_t len) override { return true; } - // We do not want to reset the hart here as the reset function in `dtm_t` seems to disregard - // the privilege level and in general does not perform propper reset (despite the name). - // As all our binaries in preloading will always start at the base of DRAM this should not - // be such a big problem. - void reset() {} -}; - int main(int argc, char **argv) { - std::clock_t c_start = std::clock(); - auto t_start = std::chrono::high_resolution_clock::now(); bool verbose; - bool perf; - unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); - uint64_t max_cycles = -1; int ret = 0; - bool print_cycles = false; - // Port numbers are 16 bit unsigned integers. - uint16_t rbb_port = 0; #if VM_TRACE FILE * vcdfile = NULL; char * fst_fname = NULL; uint64_t start = 0; #endif - char ** htif_argv = NULL; int verilog_plusargs_legal = 1; -#if DII + char* socket_name = NULL; int socket_default_port = -1; -#endif while (1) { static struct option long_options[] = { - {"cycle-count", no_argument, 0, 'c' }, {"help", no_argument, 0, 'h' }, - {"max-cycles", required_argument, 0, 'm' }, - {"seed", required_argument, 0, 's' }, - {"rbb-port", required_argument, 0, 'r' }, {"verbose", no_argument, 0, 'V' }, #if VM_TRACE {"vcd", required_argument, 0, 'v' }, {"dump-start", required_argument, 0, 'x' }, {"fst", required_argument, 0, 'f' }, #endif -#if DII {"socket-name", required_argument, 0, 'q' }, {"socket-default-port", required_argument, 0, 'w' }, -#endif - HTIF_LONG_OPTIONS }; int option_index = 0; #if VM_TRACE - int c = getopt_long(argc, argv, "-chpm:s:r:v:f:Vx:", long_options, &option_index); + int c = getopt_long(argc, argv, "-hv:f:Vx:q:w:", long_options, &option_index); #else - int c = getopt_long(argc, argv, "-chpm:s:r:V", long_options, &option_index); + int c = getopt_long(argc, argv, "-hV:q:w:", long_options, &option_index); #endif if (c == -1) break; retry: switch (c) { // Process long and short EMULATOR options case '?': usage(argv[0]); return 1; - case 'c': print_cycles = true; break; case 'h': usage(argv[0]); return 0; - case 'm': max_cycles = atoll(optarg); break; - case 's': random_seed = atoi(optarg); break; - case 'r': rbb_port = atoi(optarg); break; case 'V': verbose = true; break; - case 'p': perf = true; break; -#ifdef DII case 'q': { socket_name = (char*) malloc(strlen(optarg)); strcpy(socket_name,optarg); break; } case 'w': socket_default_port = atoi(optarg); break; -#endif #if VM_TRACE case 'v': { vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w"); @@ -300,18 +181,12 @@ int main(int argc, char **argv) { } if (arg == "+verbose") c = 'V'; - else if (arg.substr(0, 12) == "+max-cycles=") { - c = 'm'; - optarg = optarg+12; - } #if VM_TRACE else if (arg.substr(0, 12) == "+dump-start=") { c = 'x'; optarg = optarg+12; } #endif - else if (arg.substr(0, 12) == "+cycle-count") - c = 'c'; // If we don't find a legacy '+' EMULATOR argument, it still could be // a VERILOG_PLUSARG and not an error. else if (verilog_plusargs_legal) { @@ -330,19 +205,7 @@ int main(int argc, char **argv) { } goto retry; } - // If we STILL don't find a legacy '+' argument, it still could be - // an HTIF (HOST) argument and not an error. If this is the case, then - // we're done processing EMULATOR and VERILOG arguments. else { - static struct option htif_long_options [] = { HTIF_LONG_OPTIONS }; - struct option * htif_option = &htif_long_options[0]; - while (htif_option->name) { - if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) { - optind--; - goto done_processing; - } - htif_option++; - } std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \"" << arg << "\"\n"; c = '?'; @@ -350,38 +213,17 @@ int main(int argc, char **argv) { goto retry; } case 'P': break; // Nothing to do here, Verilog PlusArg - // Realize that we've hit HTIF (HOST) arguments or error out default: - if (c >= HTIF_LONG_OPTIONS_OPTIND) { - optind--; - goto done_processing; - } c = '?'; goto retry; } } done_processing: - /* if (optind == argc) { - std::cerr << "No binary specified for emulator\n"; - usage(argv[0]); - return 1; - } */ - int htif_argc = 1 + argc - optind; - htif_argv = (char **) malloc((htif_argc) * sizeof (char *)); - htif_argv[0] = argv[0]; - for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++]; - std::cout << "start" << std::endl; - const char *vcd_file = NULL; Verilated::commandArgs(argc, argv); - jtag = new remote_bitbang_t(rbb_port); - dtm = new preload_aware_dtm_t(htif_argc, htif_argv); - signal(SIGTERM, handle_sigterm); - Variane_testharness_dii* top(new Variane_testharness_dii); - //read_elf(htif_argv[1]); #if VM_TRACE Verilated::traceEverOn(true); // Verilator must compute traced signals @@ -407,17 +249,22 @@ int main(int argc, char **argv) { #endif #endif + + rvfi_dii_bridge_rst(DII_ID_WIDTH); + for (int i = 0; i < 10; i++) { top->rst_ni = 0; top->clk_i = 0; top->rtc_i = 0; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2)); #endif top->clk_i = 1; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2 + 1)); @@ -436,83 +283,28 @@ int main(int argc, char **argv) { long long addr; long long len; -#ifdef DII size_t mem_size = 0x900000; -#else - size_t mem_size = 0xFFFFFF; - while(get_section(&addr, &len)) - { - if (addr == 0x80000000) - read_section_void(addr, (void *) MEM , mem_size); - } -#endif -#ifdef DII - unsigned long long socket = serv_socket_create(socket_name, socket_default_port); - serv_socket_init(socket); - unsigned int received = 0; - unsigned int insn_count = 0; unsigned int traces_count = 0; - unsigned int num_insn = 0; - // instruction - bool busy = false; - bool inflight = false; + // instruction bool eof_trace = false; - RVFI_DII_Instruction_Packet next_instruction; - char recbuf[sizeof(RVFI_DII_Instruction_Packet) + 1] = {0}; - std::vector instructions; - std::vector returntrace; -#endif -#if !defined(DROMAJO) || !defined(DII) - while (!dtm->done() && !jtag->done() && !(top->exit_o & 0x1)) { -#else - // the simulation gets killed by dromajo while (true) { -#endif - -#ifdef DII - // Routine to fetch a batch of intructions from the Vengine - if (num_insn == 0) { - fetchInstructions(instructions, received, socket); - busy = true; - num_insn = instructions.size(); + if (readTrace(top, traces_count)) { + traces_count++; + traces_count %= DII_ID_COUNT; + } + if (get_dii_cmd(traces_count) == 0) { + eof_trace = true; } - - while (busy) { - if (readTrace(returntrace, top)){ - traces_count++; - } - // Routine to inject instructions into the core via RVFIDII interface - if (!instructions.empty() /* && !inflight */){ - if ((traces_count != num_insn-1) && (top->rvfi_trap_o || (top->rvfi_valid_o && (top->rvfi_insn_o & 0x7F) == 0xF))) { - insn_count = traces_count; - } - next_instruction = instructions.at(insn_count); - if (next_instruction.dii_cmd && insn_count == traces_count) { - top->dii_valid_i = 1; - } else { - top->dii_valid_i = 0; - } - top->dii_insn_i = next_instruction.dii_insn; - if (top->dii_ready_o && next_instruction.dii_cmd && insn_count == traces_count){ - inflight = true; - insn_count++; - } else if (!next_instruction.dii_cmd && traces_count == num_insn-1) { - insn_count++; - eof_trace = true; - top->dii_valid_i = 0; - inflight = false; - } - } -#endif top->clk_i = 0; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2)); #endif - top->clk_i = 1; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2 + 1)); @@ -523,46 +315,37 @@ int main(int argc, char **argv) { } main_time++; - // Reset Routine - if (eof_trace){ - for (int i = 0; i < 10; i++) { - top->rst_ni = 0; - top->clk_i = 0; - top->rtc_i = 0; - top->eval(); - #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2)); + // Reset Routine + if (eof_trace){ + sendReset(traces_count); + for (int i = 0; i < 10; i++) { + top->rst_ni = 0; + top->clk_i = 0; + top->rtc_i = 0; + top->eval(); + fflush(stdout); + #if VM_TRACE + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2)); + #endif + top->clk_i = 1; + top->eval(); + fflush(stdout); + #if VM_TRACE + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2 + 1)); #endif - top->clk_i = 1; - top->eval(); - #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2 + 1)); - #endif - main_time++; - } - top->rst_ni = 1; - eof_trace = false; - inflight = false; - busy = false; - traces_count = 0; - insn_count = 0; - num_insn = 0; - // Clear memory - for (int i = 0; i < (sizeof(MEM)/sizeof(MEM[0])); i++) { - MEM[i] = 0; - } - RVFI_DII_Execution_Packet rstpack = { - .rvfi_halt = 1 - }; - returntrace.push_back(rstpack); - instructions.clear(); + main_time++; + } + top->rst_ni = 1; + eof_trace = false; + traces_count++; + traces_count %= DII_ID_COUNT; + current_test_dii_start = traces_count; + // Clear memory + for (int i = 0; i < (sizeof(MEM)/sizeof(MEM[0])); i++) { + MEM[i] = 0; } - } - // Routine to return trace to Vengine - while (!returntrace.empty()) { - returnTrace(returntrace, socket); } } @@ -573,61 +356,37 @@ int main(int argc, char **argv) { fclose(vcdfile); #endif - /* if (dtm->exit_code()) { - fprintf(stderr, "%s *** FAILED *** (tohost = %d) after %ld cycles\n", htif_argv[1], dtm->exit_code(), main_time); - ret = dtm->exit_code(); - } else if (jtag->exit_code()) { - fprintf(stderr, "%s *** FAILED *** (tohost = %d, seed %d) after %ld cycles\n", htif_argv[1], jtag->exit_code(), random_seed, main_time); - ret = jtag->exit_code(); - } else if (top->exit_o & 0xFFFFFFFE) { - int exitcode = ((unsigned int) top->exit_o) >> 1; - fprintf(stderr, "%s *** FAILED *** (tohost = %d) after %ld cycles\n", htif_argv[1], exitcode, main_time); - ret = exitcode; - } else { - fprintf(stderr, "%s *** SUCCESS *** (tohost = 0) after %ld cycles\n", htif_argv[1], main_time); - } */ - - if (dtm) delete dtm; - if (jtag) delete jtag; + return ret; +} - std::clock_t c_end = std::clock(); - auto t_end = std::chrono::high_resolution_clock::now(); +int test_dii_start() { + return current_test_dii_start; +} - if (perf) { - std::cout << std::fixed << std::setprecision(2) << "CPU time used: " - << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n" - << "Wall clock time passed: " - << std::chrono::duration(t_end-t_start).count() - << " ms\n"; +bool readTrace(Variane_testharness_dii *top, unsigned int rvfi_id) { + // read rvfi data and add packet to list of packets to send + // the condition to read data here is that there is an rvfi valid signal + // this deals with counting instructions that the core has finished executing + if (top->rvfi_valid_o || top->rvfi_trap_o) { + rvfi_pkt_t execpacket = readRVFI(top); + print_rvfi_pkt(&execpacket); + put_rvfi_pkt_wrap(rvfi_id, &execpacket); + return true; } - - return ret; + return false; } -// Routine to fetch intructions from the Vengine -void fetchInstructions(std::vector &instructions, unsigned int &cnt_rec, unsigned long long socket){ - RVFI_DII_Instruction_Packet *ins_packet; - bool eof_rec = false; - char recbuf[sizeof(RVFI_DII_Instruction_Packet) + 1] = {0}; - // try to receive a packet - do { - serv_socket_getN((unsigned int *) recbuf, socket, sizeof(RVFI_DII_Instruction_Packet)); - // the last byte received will be 0 if our attempt to receive a packet was successful - if (recbuf[sizeof(RVFI_DII_Instruction_Packet)] == 0) { - ins_packet = (RVFI_DII_Instruction_Packet *) recbuf; - instructions.push_back(*ins_packet); - PrintInstTrace(ins_packet); - cnt_rec++; - if (ins_packet->dii_cmd == 0) eof_rec = true; - } else { - // sleep for 1ms before retrying - usleep(1000); - } - } while(!eof_rec); +void sendReset(unsigned int rvfi_id) { + rvfi_pkt_t execpacket; + #define rvfi_field(name, type) execpacket.name = 0; + for_all_rvfi_fields + #undef rvfi_field + execpacket.rvfi_halt = 1; + put_rvfi_pkt_wrap(rvfi_id, &execpacket); } -RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top) { - RVFI_DII_Execution_Packet execpacket = { +rvfi_pkt_t readRVFI(Variane_testharness_dii *top) { + rvfi_pkt_t execpacket = { .rvfi_order = top->rvfi_order_o, .rvfi_pc_rdata = top->rvfi_pc_rdata_o , .rvfi_pc_wdata = top->rvfi_pc_wdata_o , @@ -649,43 +408,3 @@ RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top) { }; return execpacket; } - -void returnTrace(std::vector &returntrace, unsigned long long socket) { - const int BULK_SEND = 50; - if (returntrace.size() > 0) { - int tosend = 1; - for (int i = 0; i < returntrace.size(); i+=tosend) { - tosend = 1; - RVFI_DII_Execution_Packet sendarr[BULK_SEND]; - sendarr[0] = returntrace.front(); - // bulk send if possible - if (returntrace.size() - i > BULK_SEND) { - tosend = BULK_SEND; - for (int j = 0; j < tosend; j++) { - RVFI_DII_Execution_Packet execpacket = returntrace.front(); - sendarr[j] = returntrace.front(); - returntrace.erase(returntrace.begin()); - } - } else { - returntrace.erase(returntrace.begin()); - } - for (int i = 0; i < tosend; i++) { - PrintExecTrace(&sendarr[i]); - } - // loop to make sure that the packet has been properly sent - while(!serv_socket_putN(socket, sizeof(RVFI_DII_Execution_Packet) * tosend, (unsigned int *) sendarr)); - } - } -} - -bool readTrace(std::vector &returntrace, Variane_testharness_dii *top) { - // read rvfi data and add packet to list of packets to send - // the condition to read data here is that there is an rvfi valid signal - // this deals with counting instructions that the core has finished executing - if (top->rvfi_valid_o || top->rvfi_trap_o) { - RVFI_DII_Execution_Packet execpacket = readRVFI(top); - returntrace.push_back(execpacket); - return true; - } - return false; -} diff --git a/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h b/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h deleted file mode 100644 index 860e4f76f..000000000 --- a/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __SOCKET_H__ -#define __SOCKET_H__ - -#ifdef __cplusplus -extern "C" { -#endif - #include - #include - #include - #define SOCKET_NAME_STR_SIZE 256 - #define SOCKET_INIT_FD -1 - #define SOCKET_INIT_CONNECTION -1 - #define SOCKET_MAX_CONNECTIONS 3 - - typedef struct sock_serv_state_t{ - char name[SOCKET_NAME_STR_SIZE]; - int port; - int fd; - int conn; - struct sockaddr_in address; - socklen_t addrlen; - } sock_serv_state_t; - - sock_serv_state_t* initSocketServ(const char * socket_name, unsigned int default_socket_port); - uint32_t get8SocketServ(sock_serv_state_t* sock_serv); - uint8_t put8SocketServ(sock_serv_state_t* sock_serv, uint8_t byte); - void getNSocketServ(unsigned int* result, sock_serv_state_t* sock_serv, int nbytes); - uint8_t putNSocketServ(sock_serv_state_t* sock_serv, int nbytes, unsigned int* data); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/corev_apu/tb/tb_testRig_cheri/src/socket.c b/corev_apu/tb/tb_testRig_cheri/src/socket.c deleted file mode 100644 index 1bdb7b49b..000000000 --- a/corev_apu/tb/tb_testRig_cheri/src/socket.c +++ /dev/null @@ -1,267 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SOCKET_NAME_STR_SIZE 256 -#define SOCKET_INIT_FD -1 -#define SOCKET_INIT_CONNECTION -1 -#define SOCKET_MAX_CONNECTIONS 3 - -/** Returns true on success, or false if there was an error */ -int setSocketBlockingMode(int fd, int blocking) -{ - int ret = -1; - int flags = 0; - if (fd < 0) return -1; - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) return -1; - flags = (blocking == 1) ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - ret = fcntl(fd, F_SETFL, flags); - return ret; -} - -static inline int acceptSocketServConnection(sock_serv_state_t* sock_state_ptr) { - // Check if socket created - if (sock_state_ptr == NULL) - return -1; - // Check connection and fd - if (sock_state_ptr->fd < 0 || sock_state_ptr->conn > 0) - return -1; - // Accept connection - sock_state_ptr->conn = accept(sock_state_ptr->fd, NULL, NULL); - // Make connection non-blocking - // if (sock_state_ptr->conn != -1) { - // setSocketBlockingMode(sock_state_ptr->conn, 0); - // return 0; - // } - if (sock_state_ptr->conn == -1) - return -1; - else - return 0; -} - -sock_serv_state_t* initSocketServ(const char * socket_name, unsigned int default_socket_port) { - struct sockaddr_in sock_address; - sock_serv_state_t* sock_state_ptr = NULL; - int sock_addrlen = sizeof(sock_address); - int ret = 0; - int opt = 1; - // Fail if socket already initialized - if (sock_state_ptr != NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - // Initiliaze the socket - sock_state_ptr = (sock_serv_state_t *) malloc(sizeof(sock_serv_state_t)); - if (strncpy(sock_state_ptr->name, socket_name, SOCKET_NAME_STR_SIZE) == NULL) { - fprintf(stderr, "ERROR: Failed to copy socket name \n"); - exit(EXIT_FAILURE); - } - sock_state_ptr->port = default_socket_port; - sock_state_ptr->fd = SOCKET_INIT_FD; - sock_state_ptr->conn = SOCKET_INIT_CONNECTION; - - // Create socket file descriptor - sock_state_ptr->fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_state_ptr->fd < 0) { - perror("ERROR: Failed to create socket! \r\n"); - exit(EXIT_FAILURE); - } - - // Forcefully attaching socket to the port - if (setsockopt(sock_state_ptr->fd, SOL_SOCKET, SO_REUSEADDR, &opt,sizeof(opt)) < 0) { - perror("ERROR: Unable to set reuseaddr on socket!"); - exit(EXIT_FAILURE); - } - // Operation Bind - sock_state_ptr->addrlen = sizeof(sock_address); - memset(&sock_state_ptr->address, 0, sock_state_ptr->addrlen); - sock_state_ptr->address.sin_family = AF_INET; - sock_state_ptr->address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sock_state_ptr->address.sin_port = htons(sock_state_ptr->port); - ret = bind(sock_state_ptr->fd, (struct sockaddr*)&sock_state_ptr->address, sizeof(sock_state_ptr->address)); - if (ret < 0) { - perror("ERROR: bind failed ! \r\n"); - exit(EXIT_FAILURE); - } - // Start listen for connections - if (listen(sock_state_ptr->fd, 1) < 0) { - perror("ERROR: Listen failed ! \r\n"); - exit(EXIT_FAILURE); - } - - sock_state_ptr->conn = accept(sock_state_ptr->fd, NULL, NULL); - if (sock_state_ptr->conn == -1) - { - perror("ERROR: Accept connection failed ! \r\n"); - exit(EXIT_FAILURE); - } - // Set socket in non-blocking mode - // ret = setSocketBlockingMode(sock_state_ptr->fd, 0); - // assume always true - // if (ret < 0) { - // perror("ERROR: Setting socket in non-blocking mode"); - // exit(EXIT_FAILURE); - // } - return sock_state_ptr; -} - -// Non-blocking read of 8 bits -uint32_t get8SocketServ(sock_serv_state_t* sock_serv) -{ - uint8_t byte; - if (sock_serv == NULL) - return -1; - - if (acceptSocketServConnection(sock_serv) == -1) { - perror("ERROR: Connection failed ! \r\n"); - exit(EXIT_FAILURE); - } - - if (sock_serv->conn == -1) return -1; - int n = read(sock_serv->conn, &byte, 1); - if (n == 1) - return (uint32_t) byte; - else if (!(n == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return -1; -} - -// Non-blocking write of 8 bits -uint8_t put8SocketServ(sock_serv_state_t* sock_serv, uint8_t byte) -{ - if (sock_serv == NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - - //if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - //} - - if (sock_serv->conn == -1) return 0; - int n = write(sock_serv->conn, &byte, 1); - if (n == 1) - return 1; - //else if (!(n == -1 && errno == EAGAIN)) { - // close(sock_serv->conn); - // sock_serv->conn = -1; - //} - return 0; -} - -// Try to read N bytes from socket, giving N+1 byte result. Bottom N -// bytes contain data and MSB is 0 if data is valid or non-zero if no -// data is available. Non-blocking on N-byte boundaries. -void getNSocketServ(unsigned int* result, sock_serv_state_t* sock_serv, int nbytes) -{ - printf("trying to read 1\r\n"); - uint8_t* bytes = (uint8_t*) result; - if (sock_serv == NULL) { - perror("ERROR: socket not provided ! \r\n"); - exit(EXIT_FAILURE); - return; - } - printf("trying to read \r\n"); - // if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - // } - // printf(" Accept connection socket: %d conn %d port %d \r\n", sock_serv->fd, sock_serv->conn, sock_serv->port); - // if (sock_serv->conn == -1) { - // bytes[nbytes] = 0xff; - // return; - // } - int count = read(sock_serv->conn, bytes, nbytes); - printf("count %d \r\n",count); - printf("nbytes %d \r\n",nbytes); - if (count == nbytes) { - bytes[nbytes] = 0; - return; - } - else if (count > 0) { - // Use blocking reads to get remaining data - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock_serv->conn, &fds); - while (count < nbytes) { - int res = select(sock_serv->conn+1, &fds, NULL, NULL, NULL); - assert(res >= 0); - res = read(sock_serv->conn, &bytes[count], nbytes-count); - assert(res >= 0); - count += res; - printf("count 1 %d \r\n",count); - } - bytes[nbytes] = 0; - return; - } - else { - bytes[nbytes] = 0xff; - if (!(count == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return; - } -} - -// Try to write N bytes to socket. Non-blocking on N-bytes boundaries, -// returning 0 when no write performed. -uint8_t putNSocketServ(sock_serv_state_t* sock_serv, int nbytes, unsigned int* data) -{ - if (sock_serv == NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - - // if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - // } - //if (sock_serv->conn == -1) return 0; - uint8_t* bytes = (uint8_t*) data; - int count = write(sock_serv->conn, bytes, nbytes); - if (count == nbytes) - return 1; - else if (count > 0) { - // Use blocking writes to put remaining data - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock_serv->conn, &fds); - while (count < nbytes) { - fflush(stdout); - int res = select(sock_serv->conn+1, &fds, NULL, NULL, NULL); - assert(res >= 0); - res = write(sock_serv->conn, &bytes[count], nbytes-count); - assert(res >= 0); - count += res; - } - return 1; - } - else { - if (!(count == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return 0; - } -} \ No newline at end of file diff --git a/verif/regress/install-verilator.sh b/verif/regress/install-verilator.sh index a70fc145f..66cf9f472 100755 --- a/verif/regress/install-verilator.sh +++ b/verif/regress/install-verilator.sh @@ -18,7 +18,7 @@ fi VERILATOR_REPO="https://github.com/verilator/verilator.git" VERILATOR_BRANCH="master" # Use the release tag instead of a full SHA1 hash. -VERILATOR_HASH="v5.008" +VERILATOR_HASH="v5.015" VERILATOR_PATCH="$ROOT_PROJECT/verif/regress/verilator-v5.patch" # Unset historical variable VERILATOR_ROOT as it collides with the build process.