From cc0d4204ec166117125bfc75382fd07f24f8af05 Mon Sep 17 00:00:00 2001 From: Pascal Gouedo Date: Thu, 30 May 2024 17:06:23 +0200 Subject: [PATCH 1/4] RISC-V ISA Formal Verification files for SiemensEDA OneSpin tool. Signed-off-by: Pascal Gouedo --- scripts/riscv_isa_formal/Makefile | 59 + scripts/riscv_isa_formal/README.md | 55 + .../riscv_isa_formal/common/basics.tcl.obf | 2 + .../riscv_isa_formal/common/constraints.sv | 119 ++ .../riscv_isa_formal/common/core_checker.sv | 1108 +++++++++++++++++ scripts/riscv_isa_formal/common/io.sv | 72 ++ .../riscv_isa_formal/common/other_bindings.sv | 72 ++ scripts/riscv_isa_formal/common/setup.tcl | 564 +++++++++ scripts/riscv_isa_formal/common/setup_mv.tcl | 8 + scripts/riscv_isa_formal/common/t.sh | 12 + .../riscv_isa_formal/common/vips/obi_dmem.sv | 60 + .../riscv_isa_formal/common/vips/obi_imem.sv | 59 + .../riscv_isa_formal/launch_command example | 58 + 13 files changed, 2248 insertions(+) create mode 100755 scripts/riscv_isa_formal/Makefile create mode 100755 scripts/riscv_isa_formal/README.md create mode 100755 scripts/riscv_isa_formal/common/basics.tcl.obf create mode 100755 scripts/riscv_isa_formal/common/constraints.sv create mode 100755 scripts/riscv_isa_formal/common/core_checker.sv create mode 100755 scripts/riscv_isa_formal/common/io.sv create mode 100755 scripts/riscv_isa_formal/common/other_bindings.sv create mode 100755 scripts/riscv_isa_formal/common/setup.tcl create mode 100755 scripts/riscv_isa_formal/common/setup_mv.tcl create mode 100755 scripts/riscv_isa_formal/common/t.sh create mode 100755 scripts/riscv_isa_formal/common/vips/obi_dmem.sv create mode 100755 scripts/riscv_isa_formal/common/vips/obi_imem.sv create mode 100755 scripts/riscv_isa_formal/launch_command example diff --git a/scripts/riscv_isa_formal/Makefile b/scripts/riscv_isa_formal/Makefile new file mode 100755 index 000000000..f344b819b --- /dev/null +++ b/scripts/riscv_isa_formal/Makefile @@ -0,0 +1,59 @@ +commonPath=../../common +PREPARE?=0 +RTL?=../../cv32e40p/ +GUI?=0 +NAME?=noname + +ifeq ($(APP),) + $(error APP is empty) +endif +ifeq ($(CONF),) + $(error CONF is empty) +endif +ifeq ($(MODE),) + $(error MODE is empty) +endif + +$(info APP=$(APP)) +$(info CONF=$(CONF)) +$(info MODE=$(MODE)) + +ifeq ($(GUI), 1) + flag="-i" +else + flag= +endif + +dirname=$(NAME) + +ifeq ($(PREPARE), 1) + script_name=ones_prepare_run +else + script_name=ones_run +endif + +define ones_prepare_run + @echo "====================================================" + @echo "Preparing working area $(dirname)" + @echo "====================================================" + \mkdir -p cfgs/$(dirname)/logs + \cd cfgs/$(dirname) && \cp -pf $(commonPath)/{other_bindings.sv,core_checker.sv,io.sv,setup.tcl,setup_mv.tcl,*.json,constraints.sv,t.sh,basics.tcl.obf} . && \cp -prfL $(commonPath)/vips . && \cp -prfL $(RTL) . + @echo "====================================================" + @echo "Running mode $(MODE) on configuration $(CONF) in $(dirname)" + @echo "====================================================" + \cd cfgs/$(dirname) && onespin -Q -l logs/$(APP)-cfg_$(CONF)-mode_$(MODE).log $(flag) setup.tcl $(CONF) $(MODE) $(APP) +endef + +define ones_run + @echo "====================================================" + @echo "Running mode $(MODE) on configuration $(CONF) in $(dirname)" + @echo "====================================================" + \cd cfgs/$(dirname) && onespin -Q -l logs/$(APP)-cfg_$(CONF)-mode_$(MODE).log $(flag) setup.tcl $(CONF) $(MODE) $(APP) +endef + +all: + $(call $(script_name)) + +clean: + rm -rf cfgs/$(dirname) + diff --git a/scripts/riscv_isa_formal/README.md b/scripts/riscv_isa_formal/README.md new file mode 100755 index 000000000..3786eebef --- /dev/null +++ b/scripts/riscv_isa_formal/README.md @@ -0,0 +1,55 @@ +# RISC-V ISA Formal Verification + +RISC-V ISA Formal Verification methodology has been used with Siemens EDA Onespin tool and its RISC-V ISA Processor Verification app. + +## Configurations + + +--------------------+-----------------------------------------------------------------------------+ + | | **Verified Configurations** | + +====================+========+==========+==========+==========+===========+===========+===========+ + | **Top Parameters** | **XP** | **XPF0** | **XPF1** | **XPF2** | **XPZF0** | **XPZF1** | **XPZF2** | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | COREV_PULP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | COREV_CLUSTER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | FPU | 0 | 1 | 1 | 1 | 1 | 1 | 1 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | ZFINX | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | FPU_ADDMUL_LAT | 0 | 0 | 1 | 2 | 0 | 1 | 2 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + | FPU_OTHERS_LAT | 0 | 0 | 1 | 2 | 0 | 1 | 2 | + +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + +## Tool apps + +- PRC : Property Checking +- QTF : Quantify +- VCI : Verification Coverage Integration + +## Prove modes + +- DEF : Control path verification of all instructions and datapath verification of all instructions except multiplication, division or floating point ones +- DPM : Data path verification of multiplication/ division instructions +- DPF : Data path verification of floating-point instructions + +## Directory Structure of this Repo + +- Makefile +- launch_command_example + +### common +Contains all files to create assertions and to launch different tool apps on different configurations and using different modes. + +## How to launch a run + +- Locally clone cv32e40p github repository or make a symbolic link to an existing repo. +- launch following command: make GUI=1 APP=PRC CONF=XP MODE=DEF NAME=v1_8_0 VERBOSE=1 PREPARE=1 all >&! run_gui-PRC-cfg_XP-mode_DEF-v1_8_0.log & +- or use launch_command_example to launch different runs in parallel. + +## Commands to launch for each configuration + +- XP : PRC app with DEF and DPM modes +- XPF[0,1,2] and XPZF[0,1,2] : PRC app with DEF, DPM and DPF modes + diff --git a/scripts/riscv_isa_formal/common/basics.tcl.obf b/scripts/riscv_isa_formal/common/basics.tcl.obf new file mode 100755 index 000000000..b97ac2b1e --- /dev/null +++ b/scripts/riscv_isa_formal/common/basics.tcl.obf @@ -0,0 +1,2 @@ +OneSpin obfuscated tcl file v1.2 +{"crypted_data_base64":"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","crypted_key_base64":"ae4swfzavOkxqDsJudKbX9pzOUkmtH3lghKeUgBvRwMQ/v/ohDNTomF29+UP/D6xla54T0a5\r\ncO//7aAvERGzzXcMK5Lhs20jZ9PPJz5RfppXjpquoW8adKhcEsUttU/J/k5dZxldwqtoLocp\r\nOQmJOzSoJ1nTQhaDmnQ99UvI6rej5wXUXerN6jcAyJYAfVacZMtzyVf5WZY8MANcZ+cTuJ40\r\nT6aFkpIO+s4epEyjAPPRY3aqvRqtRZd6iJRwtAYxGTyAz9Xc8yDxgvdJG7z5nfmJZ57ZUDCS\r\nqIL/WTIjg/9q9T2fxAUsnA0vBEaSQ1tZYTcelgzRQTgsVXuPcl6CkA==","crypted_sign_version_base64":"KL+4hMqJXz+2qrBnOcBWqQQhV9A4FAyyoIxcvRMJbhqDZVuNlrI6eN4y0+pWeBowxW91avwn\r\nCxpUnfO2fJpnUSDiMaEbfz5kCFuBxEMK1HYk8A6SQe+62B3Sb3ArmOTrfnZbTTVuNYFveKIC\r\n7k1PcwrD3z7NxiwyDEOuhVh3/+rD2PFrxtHtzu0Mars00hW/NZCAI6N1kC87lFgzMRwWpVCU\r\n19WIag8AEyzAy6g9WnL/sLVlj8CxiJh1C6uLPxHa6L4e/8GSu92fZgwO0363P/8Pf5fR+8O/\r\nSUxSEiMJdq6+05Pq8UtHLSTkBvgjXlVKD9DXV+USkL5twuwNUHMxKw==","crypted_signature_base64":"OGcBm7GN/6ibKuLWSdXzp2uBayu3UKZPDSMYDKOrPfJe8J/QPP3YiS0fWlAKgIp7LDsMZeiu\r\n+d0m8R2Y8jfff+sxMsApauBQ1e453cwbcZeN8BFyBoxYzkXF/NTYzFTe+U2nWuxHT9E8m572\r\nipH+Y38KVQ0UOAkPE2oZHxn9C3cnJ5VGKAwRK+PYxVyTkc0c7/EIbcE5VEObwUiGD8AJWWpF\r\n2TgDFi+AtCqoAlsGWjr+cN0w5NoaNXOav7LMQJNq20JGxN83fbywGEgjBHvr+3OBtp/7QNuZ\r\n20Lnyqer83j3uEGwUCQJ1fAiG5H3F/p3DHiQhvz2L+LTTvdS/j5tYg==","key_name":"onespin_002","key_vendor":"OneSpin","method":"aes-256-cbc"} \ No newline at end of file diff --git a/scripts/riscv_isa_formal/common/constraints.sv b/scripts/riscv_isa_formal/common/constraints.sv new file mode 100755 index 000000000..02bf694d0 --- /dev/null +++ b/scripts/riscv_isa_formal/common/constraints.sv @@ -0,0 +1,119 @@ +/*********************/ +// CONSTRAINTS +/*********************/ + +// MAIN CONSTRAINTS // + +const_addrs_c : assume property (##1 $stable({boot_addr,`core.dm_halt_addr_i,`core.dm_exception_addr_i,`core.mtvec_addr_i,`core.hart_id_i})); +const_dm_addr_c : assume property (`core.dm_halt_addr_i==32'h800 && `core.dm_exception_addr_i==32'h808); // **I** To meet app expectations + +`ifdef CFG_XP +`ifdef CV_LOOP + // raising of hwloop illegal currently not modeled + no_hwloop_illegal_c : assume property (!id_stage_i.controller_i.is_hwlp_illegal); + + // hwloop must contain 3+ instructions + hwloop_min_size_c : assume property (!(id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[0]>0&&id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[0]-id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[0] inside {32'h0,32'h4,32'h8}) && !(id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[1]>0&&id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[1]-id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[1] inside {32'h0,32'h4,32'h8})); + + // hwloop must be word-aligned + hwloop_aligned_c : assume property (id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[0][1:0]==0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[0][1:0]==0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[1][1:0]==0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[1][1:0]==0); + + // we must not create loop 0 in the middle of itself (setting count to non-zero at a PC location that would qualify as inside the loop). Also, setting up the registers and then jumping to a location inside loop 0 will likely not work + loop0_setup_c : assume property (id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[0]==0 ##1 id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[0]!=0 |-> id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[0]==$past(pc_id)+32'd4); + + // we must not create loop 1 in the middle of itself (setting count to non-zero at a PC location that would qualify as inside the loop). Also, setting up the registers and then jumping to a location inside loop 1 will likely not work + loop1_setup_c : assume property (id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[1]==0 ##1 id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[1]!=0 |-> id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[1]==$past(pc_id)+32'd4); + + // let's not wrap + lopp_no_wrap_c : assume property (!(id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[0]>0&&id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[0]0&&id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[1]0 && pc_id>=id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[0] && pc_id0 && pc_id>=id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_start_q[1] && pc_id0 && id_stage_i.hwlp_regid==1 && id_stage_i.hwlp_we)); + + // end addresses 8 apart + loop_end_min_sitance_c : assume property (!(id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[0]>0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_counter_q[1]>0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[1]0 && id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_we_i[1] && !id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_regid_i &&id_stage_i.gen_hwloop_regs.hwloop_regs_i.hwlp_end_q[1]0|->`core.data_rvalid_i); +`else + no_hwloop_c : assume property (!id_stage_i.controller_i.is_hwlp_body); +`endif +`endif + +`ifdef CFG_XC + clk_en_c: assume property (`core.pulp_clock_en_i); +`endif + +// MEMORY INTERFACE CONSTRAINTS // + +// +// The following set of constraints could be used to constrain memory interfaces in case bus protocols implemented are not tool supported. +// **W** Use only in case bus protocols implemented are not tool supported +// + +`ifdef CUSTOM_MEM_INTERFACES + `include "mem_constraints.sv" + localparam MAX_WAIT=DMEM_MAX_WAIT; +`else + localparam MAX_WAIT=obi_dmem_checker.MAX_WAIT; +`endif + +// PERFORMANCE ENHANCEMENT CONSTRAINTS // + +// +// The following set of constraints could be used to enhance properties' runtime. +// **W** If ever used, these constraints have to be removed totally afterwards to achieve full verification. +// + +// +// "restrict_regs" restricts instruction source and destination indices to a subset of registers. +// By default, the following register indices are chosen: 0 to 3, and 8 to 9 in presence of compressed extensions. +// +function automatic restrict_regs(input dec_t dec); + restrict_regs=1'b1; + foreach (dec.RS[i]) + if (dec.RS[i].valid) +// restrict_regs&=dec.RS[i].idx<4 || (MISA.C|Zca) && dec.RS[i].idx inside {5'd8,5'd9}; + restrict_regs&=dec.RS[i].idx inside {5'd0, 5'd1, 5'd2, 5'd4, 5'd8, 5'd12, 5'd16}; + foreach (dec.RD[i]) + if (dec.RD[i].valid) +// restrict_regs&=dec.RD[i].idx<4 || (MISA.C|Zca) && dec.RD[i].idx inside {5'd8,5'd9}; + restrict_regs&=dec.RD[i].idx inside {5'd0, 5'd1, 5'd2, 5'd4, 5'd8, 5'd12, 5'd16}; +endfunction + +`ifdef RESTRICT_REGS + // Restrict instruction decoding & register file verification to a subset of registers + restrict_regs_c: assume property (disable iff (~rst_n) + restrict_regs(execute.dec) + `ifndef COMPLETENESS + `ifndef RESTRICT_REGISTER_INDEX +// && (reg_idx<4 || (MISA.C|Zca) && reg_idx inside {5'd8,5'd9}) + && (reg_idx inside {5'd0, 5'd1, 5'd2, 5'd4, 5'd8, 5'd12, 5'd16}) + `endif + `endif + ); +`endif + +// GRADUAL VERIFICATION CONSTRAINTS // + +// +// The following set of constraints could be used for a gradual setup of a new core. +// **W** If ever used, these constraints have to be removed totally afterwards to achieve full verification. +// + +`ifdef LIMIT_TOTAL_INSTR_COUNT + // Limit total number of instructions allowed in the pipeline + limit_total_instr_count_c : assume property (disable iff (~rst_n) full[0] -> id_instr_cnt<`LIMIT_TOTAL_INSTR_COUNT); +`endif diff --git a/scripts/riscv_isa_formal/common/core_checker.sv b/scripts/riscv_isa_formal/common/core_checker.sv new file mode 100755 index 000000000..4cbd14507 --- /dev/null +++ b/scripts/riscv_isa_formal/common/core_checker.sv @@ -0,0 +1,1108 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// RISC-V Checker // +// // +// This material contains trade secrets or otherwise confidential // +// information owned by Siemens Industry Software Inc. or its affiliates // +// (collectively, "SISW"), or its licensors. Access to and use of this // +// information is strictly limited as set forth in the Customer's applicable // +// agreements with SISW. // +// // +// This material may not be copied, distributed, or otherwise disclosed // +// outside of the Customer's facilities without the express written // +// permission of SISW, and may not be used in any way not expressly // +// authorized by SISW. // +// // +/////////////////////////////////////////////////////////////////////////////// + +`include "tidal.sv" +`include "RISCV_ISA.sv" +import RISCV_ISA::*; + +/*********************/ +// DEBUG GROUPS +/*********************/ + +(* ONESPIN_APP = "Processor" *) +(* ONESPIN_VIP_NAME = "RISC-V" *) +(* ONESPIN_VIP_TYPE = "cpu" *) +(* ONESPIN_VIP_TRANSACTION= "instr" *) +(* ONESPIN_VIP_GROUP_1 = "{{IF} if_valid}" *) +(* ONESPIN_VIP_GROUP_1_X = "/instr_addr_o /instr_req_o /instr_gnt_i /instr_rvalid_i /instr_rdata_i /pc_if /if_stage_i.fetch_valid /if_stage_i.fetch_rdata /if_stage_i.fetch_ready /if_stage_i.instr_valid /if_stage_i.instr_aligned /if_stage_i.if_ready /halt_if " *) +(* ONESPIN_VIP_GROUP_2 = "{{ID} id_valid}" *) +(* ONESPIN_VIP_GROUP_2_X = "/pc_id /instr_valid_id /instr_rdata_id /is_compressed_id /is_fetch_failed_id /clear_instr_valid /id_stage_i.controller_i.ctrl_fsm_cs /id_stage_i.controller_i.ctrl_fsm_ns /id_stage_i.misaligned_stall /id_stage_i.jr_stall /id_stage_i.load_stall /id_stage_i.apu_stall /id_stage_i.csr_apu_stall /id_stage_i.branch_taken_ex /id_ready /id_stage_i.halt_id" *) +(* ONESPIN_VIP_GROUP_3 = "{{EX} ex_valid}" *) +(* ONESPIN_VIP_GROUP_3_X = "/pc_ex /alu_en_ex /id_stage_i.decoder_i.alu_operator_o /alu_operand_a_ex /alu_operand_b_ex /ex_stage_i.alu_result /ex_stage_i.alu_ready /ex_stage_i.mult_ready mul_op_a mul_op_b mul_op_c mul_result /ex_stage_i.alu_i.div_valid div_result_valid /ex_stage_i.alu_i.result_div div_op_a div_op_b div_result_valid div_result /lsu_ready_ex /ex_ready" *) +(* ONESPIN_VIP_GROUP_4 = "{{MEM} mem_valid}" *) +(* ONESPIN_VIP_GROUP_4_X = "/data_we_o /data_addr_o /data_req_o /data_be_o /data_sign_ext_ex /data_type_ex /data_wdata_o /data_gnt_i /data_rvalid_i /data_rdata_i /lsu_rdata rf_we_lsu rf_waddr_lsu lsu_data_type lsu_data_sign lsu_data_offset" *) +(* ONESPIN_VIP_GROUP_5 = "{{WB} wb_valid}" *) +(* ONESPIN_VIP_GROUP_5_X = "/id_stage_i.register_file_i.we_b_i /id_stage_i.register_file_i.waddr_b_i /id_stage_i.register_file_i.wdata_b_i /id_stage_i.register_file_i.we_b_dec /id_stage_i.register_file_i.we_a_i /id_stage_i.register_file_i.waddr_a_i /id_stage_i.register_file_i.wdata_a_i /id_stage_i.register_file_i.we_a_dec /id_stage_i.register_file_i.mem /lsu_ready_wb /ex_stage_i.wb_ready_i" *) +(* ONESPIN_VIP_GROUP_6 = "CSRs" *) +(* ONESPIN_VIP_GROUP_6_X = "/csr_access_ex /csr_op /csr_addr /csr_wdata /csr_rdata /csr_cause /cs_registers_i.mepc_q /cs_registers_i.mcause_q /cs_registers_i.mstatus_q /cs_registers_i.mie_q /cs_registers_i.mtvec_q /cs_registers_i.fflags_q /cs_registers_i.frm_q" *) +(* ONESPIN_VIP_GROUP_7 = "XCPTs" *) +(* ONESPIN_VIP_GROUP_7_X = "/current_priv_lvl /pc_set /exc_cause /cs_registers_i.exception_pc /if_stage_i.exc_pc /if_stage_i.fetch_failed /instr_err_pmp /data_err_pmp /data_err_ack /id_stage_i.illegal_insn_dec /illegal_c_insn_id /id_stage_i.fencei_insn_dec /id_stage_i.ebrk_insn_dec /id_stage_i.ecall_insn_dec /id_stage_i.mret_insn_dec /id_stage_i.uret_insn_dec /id_stage_i.dret_insn_dec" *) +(* ONESPIN_VIP_GROUP_8 = "INTRs" *) +(* ONESPIN_VIP_GROUP_8_X = "/irq_i /irq_id_o /irq_ack_o" *) +(* ONESPIN_VIP_GROUP_9 = "DBG" *) +(* ONESPIN_VIP_GROUP_9_X = "/debug_mode /debug_req_i /debug_cause /debug_ebreakm /debug_ebreaku /debug_single_step /debug_csr_save /cs_registers_i.dcsr_q /cs_registers_i.depc_q" *) +(* ONESPIN_VIP_GROUP_A = "FPU" *) +(* ONESPIN_VIP_GROUP_A_X = "fpu_op_valid fpu_op_a fpu_op_b fpu_op_c fpu_op_ex fpu_lat_ex fpu_waddr_ex fpu_result_valid fpu_s_cycle fpu_m_cycle ex_stage_i.gen_apu.apu_disp_i.apu_lat fpu_waddr fpu_result fpu_flags" *) + +/*********************/ +// VIP's MODULE +/*********************/ + +module RISCV_checker #( + localparam logic[5:0] ALENX=ALEN ~(fpu_waddr_ex==fpu_waddr && (MISA.F|Zfinx -> fpu_lat_ex==ex_stage_i.gen_apu.apu_disp_i.apu_lat)))) + if (fpu_waddr[5]) + sboard_FR[fpu_waddr[4:0]] <= 1'b0; + else + sboard_XR[fpu_waddr[4:0]] <= 1'b0; + end + +/*********************/ +// DEBUG SIGNALS +/*********************/ + +(* OSS_TCL_VALUE_PRINTER = "PVE_disass" *) logic[32:0] instr; +assign instr = $past({full[0],iword_id}); + +wire if_valid = if_stage_i.if_valid; +wire id_valid = `core.id_valid; +wire ex_valid = `core.ex_valid; +wire mem_valid = `core.data_req_o; +wire wb_valid = `core.wb_valid; + +/*********************/ +// ARCHITECTURE STATE +/*********************/ + +Arch_state_t Arch; +always_comb begin + foreach (Arch.X[i]) + if (i==0) + Arch.X[i] <= '{valid: 1'b1, data: '0}; + else + Arch.X[i] <= '{valid: ~((rf_we_lsu&rf_waddr_lsu==i)|sboard_XR[i]), data: pipe_XR[i]}; + if (MISA.F && ~Zfinx) + foreach (Arch.F[i]) + Arch.F[i] <= '{valid: ~((rf_we_lsu&rf_waddr_lsu==(i+6'd32))|sboard_FR[i]), data: pipe_FR[i]}; + + Arch.CSR <= CSR; +`ifdef CFG_XP + Arch.CSR.lpstart <= $past(CSR.lpstart); + Arch.CSR.lpend <= $past(CSR.lpend); + Arch.CSR.lpcount <= $past(CSR.lpcount); +`endif + Arch.PC <= $past(full[0]?pc_id:pc_if); +end + +/*********************/ +// MODEL +/*********************/ + +prio_interrupt_t prio_interrupt; +assign prio_interrupt = prioritize_interrupt($past(interrupt_in,WB_OFFSET),Arch.CSR); + +execute_t execute; +assign execute = ISA_exe($past(iword_id), + $past(is_sstep,WB_OFFSET), + prio_interrupt, + '{Fetch_Access_Fault:{xcpt_af_instr_2nd,xcpt_af_instr_1st}, + BreakpointF: xcpt_bp_if, + BreakpointL: xcpt_bp_ld, + BreakpointS: xcpt_bp_samo, + DBGBreakpointF: $past(Arch.CSR.tdata1[0].typ==2 && Arch.CSR.tdata1[0].execute,WB_OFFSET) && Arch.PC==CSR.tdata2[0] && $past(~Arch.CSR.curDebug,WB_OFFSET), + DBGBreakpointL: xcpt_dbg_bp_ld, + DBGBreakpointS: xcpt_dbg_bp_samo, + Load_Addr_Align: xcpt_ma_ld, + Load_Access_Fault: {xcpt_af_ld_2nd,xcpt_af_ld_1st}, + SAMO_Addr_Align: xcpt_ma_samo, + SAMO_Access_Fault: {xcpt_af_samo_2nd,xcpt_af_samo_1st}, + Fetch_Page_Fault: {xcpt_pf_instr_2nd,xcpt_pf_instr_1st}, + Load_Page_Fault: {xcpt_pf_ld_2nd,xcpt_pf_ld_1st}, + SAMO_Page_Fault: {xcpt_pf_samo_2nd,xcpt_pf_samo_1st}}, + Arch); + +/*********************/ +// FUNCTIONS +/*********************/ + +function automatic [1:NUM_RS][1:0] compose_selection(logic[1:0] op_a_sl='0, logic[1:0] op_b_sl='0, logic[1:0] op_c_sl='0); + compose_selection = '{1: op_a_sl, 2: op_b_sl, default: op_c_sl}; +endfunction + +function automatic CSR_struct_t CSR_hw_update(input CSR_struct_t cur_CSR, input CSR_struct_t next_CSR, input logic is_retired=1'b0, input fflags_t fflags='{default:'0}); +`ifdef SKIP_CSR_CHECK + CSR_hw_update=next_CSR; +`else + CSR_hw_update=skip_CSR_update(cur_CSR,next_CSR); + if (MISA.F|Zfinx) begin + CSR_hw_update.fflags=next_CSR.fflags; // **I** Skip checking fflags updates + if (MISA.F) + CSR_hw_update.mstatus.FS=next_CSR.mstatus.FS; // **I** Skip checking mstatus.FS updates + end + if (NUM_COUNTERS>0) + CSR_hw_update.mcycle=next_CSR.mcycle; + if (NUM_COUNTERS>2 && is_retired) + CSR_hw_update.minstret={CSR_hw_update.minstret+64'h1}[63:0]; + if (NUM_COUNTERS>3) + CSR_hw_update.mhpmcounter=next_CSR.mhpmcounter; +`ifdef CFG_XP + CSR_hw_update.lpcount=next_CSR.lpcount; // **I** Skip checking lpcount updates +`endif +`endif +endfunction + +function automatic pc_check(input logic[XLEN-1:0] expected_pc); + pc_check=1'b1; +`ifndef SKIP_PC_CHECK + pc_check&=expected_pc==Arch.PC; +`endif +endfunction + +function automatic op_check(input execute_t exe, input op_t rtl_op='0, input [1:NUM_RS][1:0] sl='0); + op_check=1'b1; +`ifndef SKIP_RF_CHECK + foreach (rtl_op[i]) + op_check&=(exe.dec.RS[i].valid -> expected_op_data(exe.op[i][XLEN-1:0],sl[i])==rtl_op[i]); +`endif +endfunction + +function logic[1:0] data_size_enc(input logic[1:0] data_size); + case(data_size) + ms_byte: data_size_enc = ms_word; + ms_half: data_size_enc = ms_half; + ms_word: data_size_enc = ms_byte; + default: data_size_enc = ms_double; + endcase +endfunction + +function reg_t expected_op_data(input reg_t op, input logic[1:0] sl='0); + case(sl) + 2'h0: expected_op_data = op; + 2'h1: expected_op_data = {op[XLEN/2-1:0],op[XLEN/2-1:0]}; + 2'h2: expected_op_data = {op[XLEN/4-1:0],op[XLEN/4-1:0],op[XLEN/4-1:0],op[XLEN/4-1:0]}; + 2'h3: expected_op_data = op< check_wdata(exe.mem,dmem_req_data)); +`endif +endsequence + +sequence pipe_dmem_2nd_req(t_req, execute_t exe); +`ifdef SKIP_DMEM_CHECK + t##0 1'b1; +`else + t_req##0 dmem_req_valid==exe.mem.valid and + t_req##0 dmem_req_addr=={encVA({exe.mem.addr[XLEN-1:2],2'b00})+32'd4}[ALENX-1:0] and + t_req##0 dmem_req_we==(exe.mem.cmd inside {mc_store,mc_sc}) and + t_req##0 dmem_req_be==exe.mem.byte_enable[7:4] and + t_req##0 (exe.mem.cmd inside {mc_store,mc_sc} -> check_wdata(exe.mem,dmem_req_data,1'b1)); +`endif +endsequence + +sequence pipe_reset(t_wb, Arch_state_t cur_Arch=Arch); + t_wb##0 all_regs_valid(cur_Arch) && cur_Arch.X[0].data=='0 and + t_wb##0 no_rf_update($past(cur_Arch),cur_Arch) and + t_wb##0 RISCV_CSR_reset_state(cur_Arch.CSR) and + t_wb##0 CSR_hw_update($past(cur_Arch.CSR),cur_Arch.CSR)==cur_Arch.CSR and + t_wb##0 pc_check(boot_addr); +endsequence + +sequence pipe_bubble(t_wb, Arch_state_t cur_Arch, Arch_state_t next_Arch=Arch); + t_wb##1 no_rf_update(cur_Arch,next_Arch) and + t_wb##1 CSR_hw_update(cur_Arch.CSR,next_Arch.CSR)==next_Arch.CSR and + t_wb##1 pc_check(cur_Arch.PC); +endsequence + +sequence pipe_ret(t_wb, Arch_state_t cur_Arch, execute_t exe, Arch_state_t next_Arch=Arch); + t_wb##1 no_rf_update(cur_Arch,next_Arch) and + t_wb##1 CSR_hw_update(exe.next_CSR,next_Arch.CSR,~exe.csr.count_inhibit.IR)==next_Arch.CSR and + t_wb##1 pc_check(exe.next_pc.ret_PC); +endsequence + +sequence pipe_xcpt(t_wb, Arch_state_t cur_Arch, xcpt_t xcpt, Arch_state_t next_Arch=Arch); + t_wb##1 no_rf_update(cur_Arch,next_Arch) and + t_wb##1 CSR_hw_update(CSR_xcpt_update(cur_Arch.CSR,xcpt),next_Arch.CSR)==next_Arch.CSR and + t_wb##1 pc_check(CSR_xcpt_pc(cur_Arch.CSR,xcpt)); +endsequence + +sequence pipe_instr(t_wb, Arch_state_t cur_Arch, execute_t exe, result_t result='0, logic[1:NUM_RD] check_result='1, Arch_state_t next_Arch=Arch); + t_wb##1 (~exe.mem.valid & ~exe.fpu.valid) -> no_pending_results_used(exe.dec,cur_Arch) and // **I** don't check registers validity for memory or FPU instructions + t_wb##1 pipe_rf_check(exe.dec.RD,result,cur_Arch,check_result,next_Arch) and + t_wb##1 CSR_hw_update(CSR_instr_update(exe.csr,exe.next_CSR,CSR),next_Arch.CSR,~exe.csr.count_inhibit.IR,result.flags)==next_Arch.CSR and + t_wb##1 pc_check(exe.next_pc.PC); +endsequence + +sequence pipe_result(t_ex, execute_t exe, result_t result='0, logic[XLEN-1:0] rtl_result='0); + t_ex##0 ~((exe.dec.RD[1].idx==0) & (exe.fpu.valid -> Zfinx)) -> result.data[1]==rtl_result and + t_ex##0 (exe.fpu.valid & exe.fpu.flags_update) -> result.flags==fpu_flags; +endsequence + +sequence pipe_operands(t_ex, execute_t exe, op_t rtl_op='0, logic[1:NUM_RS][1:0] select_op_data='0); + t_ex##0 op_check(exe,rtl_op,select_op_data) and + t_ex##0 exe.fpu.valid -> exe.fpu.frm==fpu_rm; +endsequence + +property pipe_env(t_wb, logic env_cond='1, logic[PIPE_STAGES-1:0] prevent_stage_flush='0, logic[PIPE_STAGES-1:0] prevent_stage_stall='0); + t_id##0 (prevent_stage_flush[0] -> ~flush[0]) && (prevent_stage_stall[0] -> ~stall[0]) and + t_wb##0 (prevent_stage_flush[1] -> ~flush[1]) && (prevent_stage_stall[1] -> ~stall[1]) and + during(t_id,t_wb,env_cond); +endproperty + +/*********************/ +// CONCEPTUAL STATE +/*********************/ + +sequence Ready2Execute; + ~stall[1] && ~id_stage_i.misaligned_stall && id_stage_i.controller_i.ctrl_fsm_cs inside {DECODE,DECODE_HWLOOP} && ~id_stage_i.branch_taken_ex +`ifndef SKIP_PC_CHECK + && (id_stage_i.controller_i.jump_done_q -> (full[0] & id_stage_i.controller_i.jump_in_dec & (id_stage_i.controller_i.pc_mux_o==PC_JUMP) & ~$past(fpu_result_valid) & (~fpu_m_cycle) -> (~id_stage_i.controller_i.jr_stall_o & (pc_if==if_stage_i.aligner_i.branch_addr_i)))) + && ((full[0] & ~id_stage_i.controller_i.jump_done_q & ~id_stage_i.controller_i.is_hwlp_body & id_stage_i.controller_i.ctrl_fsm_cs==DECODE) -> (pc_if=={pc_id+(iword_id[1:0]==2'b11 ?3'd4: 3'd2)}[31:0])) +`endif +; +endsequence + +/*********************/ +// TIMEPOINTS +/*********************/ + +// RESET PROPERTY TIMEPOINTS // + +sequence t_if_rst; nxt(t,2); endsequence; +sequence t_id_rst; nxt(t_if_rst,2); endsequence; + +// PIPELINE STAGE TIMEPOINTS // + +sequence t_id; t; endsequence; +sequence t_ex; nxt(t_id,1); endsequence; +sequence t_wb; t_ex; endsequence; +sequence t_ex_ready; await(t_ex,~stall[1]&&id_stage_i.controller_i.ctrl_fsm_cs inside {DECODE,DECODE_HWLOOP,ELW_EXE},MAX_WAIT+4); endsequence; +sequence t_wb_ready; t_ex_ready; endsequence; + +// MEMORY PROPERTY TIMEPOINTS // + +sequence t_dmem_req; t_ex; endsequence; +sequence t_dmem_gnt; await(t_dmem_req,dmem_req_ready,MAX_WAIT); endsequence; +sequence t_dmem_2nd_req; await(nxt(t_dmem_gnt,1),obi_dmem_checker.new_req_allowed,MAX_WAIT); endsequence; +sequence t_dmem_2nd_gnt; await(t_dmem_2nd_req,dmem_req_ready,MAX_WAIT); endsequence; +sequence t_wb_ready_mem; t_wb_ready; endsequence; +sequence t_ex_ready_mem_ma; await(t_dmem_2nd_req,~stall[1],MAX_WAIT); endsequence; +sequence t_wb_ready_mem_ma; t_ex_ready_mem_ma; endsequence; + +// OTHER PROPERTY TIMEPOINTS // + +sequence t_ex_ready_branch; await(nxt(t_ex_ready,1),~stall[1],MAX_WAIT); endsequence; +sequence t_ex_ready_wfi; await(t_ex,~stall[1]&&id_stage_i.controller_i.ctrl_fsm_cs==DECODE,MAX_WAIT+6); endsequence; +sequence t_ex_ready_div; await(nxt(t_ex,2),~stall[1]&&id_stage_i.controller_i.ctrl_fsm_cs inside {DECODE},32); endsequence; +sequence t_wb_ready_branch; t_ex_ready_branch; endsequence; +sequence t_wb_ready_wfi; t_ex_ready_wfi; endsequence; +sequence t_wb_ready_div; t_ex_ready_div; endsequence; + +// MODEL CAPTURING TIMEPOINTS // + +sequence t_model; t_wb; endsequence; +sequence t_arch; t_wb; endsequence; + +// ARCHITECTURE UPDATE TIMEPOINTS // + +sequence t_arch_update; t_wb_ready; endsequence; +sequence t_arch_update_mem; t_wb_ready_mem; endsequence; +sequence t_arch_update_mem_ma; t_wb_ready_mem_ma; endsequence; +sequence t_arch_update_branch; t_wb_ready_branch; endsequence; +sequence t_arch_update_wfi; t_wb_ready_wfi; endsequence; +sequence t_arch_update_div; t_wb_ready_div; endsequence; +sequence t_arch_update_fpu; await(nxt(t_ex_ready,FPU_LATENCY),fpu_result_valid,MAX_WAIT); endsequence; + +// CONCEPTUAL STATE TIMEPOINTS // + +sequence t_rd2ex_rst; t_id_rst; endsequence; +sequence t_rd2ex; t_ex_ready; endsequence; +sequence t_rd2ex_mem_ma; t_ex_ready_mem_ma; endsequence; +sequence t_rd2ex_branch; t_ex_ready_branch; endsequence; +sequence t_rd2ex_wfi; t_ex_ready_wfi; endsequence; +sequence t_rd2ex_div; t_ex_ready_div; endsequence; + +/*********************/ +// PROPERTIES +/*********************/ + +// RESET PROPERTY // + +property RESET_p; +reset_sequence |=> + t##0 `core.fetch_enable_i and + during(t,nxt(t_id_rst,WB_OFFSET-1),~interrupt_in.DBGI) and + during(t,nxt(t_id_rst,WB_OFFSET),rst_n) // [t##0 --> first WB] +implies + t_rd2ex_rst##0 Ready2Execute and // first ID + pipe_fetch_req(t,t_if_rst) and // [t##0 --> first IF] + pipe_reset(nxt(t_id_rst,WB_OFFSET)) and // first WB + pipe_dmem_no_req(t,t_id_rst) and // [t##0 --> first ID] + t_rd2ex_rst##0 right_hook; +endproperty + +// BUBBLE & PIPELINE SPECIFIC PROPERTIES // + +property BUBBLE_p; + Arch_state_t cur_Arch; + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 Ready2Execute and + t_id##0 ~full[0] | stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) +implies + t_rd2ex##0 Ready2Execute and + pipe_bubble(t_arch_update,cur_Arch) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +// I, E, C, X PROPERTIES // + +property RV_INSTR(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && (exe.next_pc.conditional -> ~exe.next_pc.non_linear) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + during(nxt(t_wb,1),nxt(t_wb_ready,1),pc_check(exe.next_pc.PC)) and + pipe_instr(t_arch_update,cur_Arch,exe,exe.result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_Branch(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && (exe.next_pc.conditional -> exe.next_pc.non_linear) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready_branch,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex_branch##0 Ready2Execute and + pipe_instr(t_arch_update_branch,cur_Arch,exe,exe.result) and + pipe_dmem_no_req(t_ex,t_ex_ready_branch) and + t_rd2ex_branch##0 right_hook; +endproperty + +property RV_INSTR_MEM(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && exe.mem.byte_enable<=4'hf and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready_mem,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + pipe_instr(t_arch_update_mem,cur_Arch,exe,exe.result,NUM_RD==2?2'b01:1'b0) and + pipe_dmem_1st_req(t_dmem_gnt,exe) and + during_excl(nxt(t_dmem_gnt,1),t_wb_ready_mem,~dmem_req_valid) and + t_arch_update_mem##1 exe.mem.cmd==mc_load -> rf_we_lsu && rf_waddr_lsu=={(exe.dec.RD[1].RF==rf_F)?1'b1:1'b0,exe.dec.RD[1].idx} and + t_arch_update_mem##1 exe.mem.cmd==mc_load -> lsu_data_type==data_size_enc(exe.mem.size) && lsu_data_sign[0]==((exe.dec.RD[1].RF==rf_X)&exe.mem.signed_data) && lsu_data_offset==exe.mem.addr[1:0] and + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_MEM_MA(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && exe.mem.byte_enable>4'hf and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready_mem_ma,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex_mem_ma##0 Ready2Execute and + pipe_instr(t_arch_update_mem_ma,cur_Arch,exe,exe.result,NUM_RD==2?2'b01:1'b0) and + pipe_dmem_1st_req(t_dmem_gnt,exe) and + pipe_dmem_2nd_req(t_dmem_2nd_gnt,exe) and + during_excl(nxt(t_dmem_gnt,1),t_dmem_2nd_req,~dmem_req_valid) and + t_arch_update_mem_ma##1 exe.mem.cmd==mc_load -> rf_we_lsu && rf_waddr_lsu=={(exe.dec.RD[1].RF==rf_F)?1'b1:1'b0,exe.dec.RD[1].idx} and + t_arch_update_mem_ma##1 exe.mem.cmd==mc_load -> lsu_data_type==data_size_enc(exe.mem.size) && lsu_data_sign[0]==((exe.dec.RD[1].RF==rf_X)&exe.mem.signed_data) && lsu_data_offset==exe.mem.addr[1:0] and + t_rd2ex_mem_ma##0 right_hook; +endproperty + +// SYSTEM PROPERTIES // + +property FENCE_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + pipe_instr(t_arch_update,cur_Arch,exe) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property WFI_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready_wfi,~(is_interrupt|is_debug)) and + during(nxt(t_ex,3),nxt(t_ex,6), id_stage_i.controller_i.ctrl_fsm_cs==SLEEP -> `core.wake_from_sleep) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex_wfi##0 Ready2Execute and + pipe_instr(t_arch_update_wfi,cur_Arch,exe) and + pipe_dmem_no_req(t_ex,t_ex_ready_wfi) and + t_rd2ex_wfi##0 right_hook; +endproperty + +property xRET_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] & ((exe.dec.instr==DRET) | ~cur_Arch.CSR.curDebug) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + pipe_ret(t_arch_update,cur_Arch,exe) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property ECALL_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + during(t_id,t_wb_ready,~is_interrupt&~is_debug) and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & exe.xcpt.xcpt_code inside {xcpt_UEnvCall,xcpt_SEnvCall,xcpt_MEnvCall} & ~cur_Arch.CSR.curDebug +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property EBREAK_BreakPoint_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & ~exe.xcpt.dbg & exe.xcpt.xcpt_code==xcpt_Breakpoint & exe.xcpt.brk inside {brk_instr} & ~cur_Arch.CSR.curDebug +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property EBREAK_HaltReq_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & exe.xcpt.xcpt_code==xcpt_Breakpoint & exe.xcpt.brk inside {brk_instr} & cur_Arch.CSR.curDebug +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property EBREAK_ForcedEntry_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt)) and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & exe.xcpt.dbg & exe.xcpt.xcpt_code==xcpt_Breakpoint & exe.xcpt.brk inside {brk_instr} & ~cur_Arch.CSR.curDebug +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +// Zicsr PROPERTIES // + +property CSRx_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_ex##0 set_freeze(result,compose_result(csr_rdata)) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and +`ifndef ISSUE_32_FIXED + t_wb_ready##0 `core.COREV_PULP -> (~id_stage_i.controller_i.hwlp_end1_eq_pc & ~id_stage_i.controller_i.hwlp_end0_eq_pc) and // **Potential ISSUE_32** In case the hwlp end pc is same as next pc expected (pc+4) the next pc is set to a different value than expected +`endif + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + pipe_instr(t_arch_update,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_ex##0 exe.csr.addr==csr_addr and + t_ex##0 ~((exe.dec.RD[1].idx==0)|(`core.COREV_PULP?(exe.csr.csr inside {csr_lpcount0, csr_lpcount1}):'0)) -> CSR_read(csr_rdata,exe.csr,cur_Arch.CSR,$past(interrupt_in,1)) and // **I** Skip checking lpcount read + t_rd2ex##0 right_hook; +endproperty + +// Zifencei PROPERTIES // + +property FENCE_I_p(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and + pipe_instr(t_arch_update,cur_Arch,exe) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +// M PROPERTIES // + +property RV_INSTR_MUL(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_M_SUPPORT + t_ex_ready##0 set_freeze(result,exe.result) and + t_ex_ready##0 restrict_ops(compose_operands(exe.op[1],exe.op[2]),'{default:'h1}) and +`else + t_ex_ready##0 set_freeze(result,compose_result(mul_result)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and +`ifdef PVE_M_SUPPORT + pipe_result(t_ex_ready,exe,result,mul_result) and +`else + pipe_instr(t_arch_update,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + pipe_operands(t_ex_ready,exe,compose_operands(mul_op_a,mul_op_b,mul_op_c)) and +`endif + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_DIV(insn_set insns, cycles); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_M_SUPPORT + t_ex##0 set_freeze(result,exe.result) and + t_ex##0 restrict_ops(exe.op,'{default:'h1}) and +`else + t_ex##cycles set_freeze(result,compose_result(div_result)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready_div,~(is_interrupt|is_debug)) and + during_excl(nxt(t_ex,2),nxt(t_ex,cycles),~div_result_valid) and + t_ex##cycles div_result_valid and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex_div##0 Ready2Execute and +`ifdef PVE_M_SUPPORT + pipe_result(t_ex_ready_div,exe,result,div_result) and +`else + pipe_instr(t_arch_update_div,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready_div) and + pipe_operands(t_ex_ready_div,exe,compose_operands(div_op_a,div_op_b),compose_selection('h0,'h3)) and +`endif + t_rd2ex_div##0 right_hook; +endproperty + +// F, D PROPERTIES // + +property RV_INSTR_F(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_FPU_SUPPORT + t_ex_ready##FPU_LATENCY set_freeze(result,exe.result) and + t_ex_ready##FPU_LATENCY exe.dec.instr inside {FMUL_S,FMADD_S,FNMADD_S,FMSUB_S,FNMSUB_S} -> restrict_fpu_ops(compose_operands(exe.op[1],exe.op[2])) and +`else + t_ex_ready##FPU_LATENCY set_freeze(result,compose_result(fpu_result,fpu_flags)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_arch_update_fpu,~(is_interrupt|is_debug)) and + t_arch_update_fpu##0 (FPU_LATENCY>0) -> fpu_result_valid and // **I** Otherwise we wait forever in case FPU_LATENCY==2 + t_ex_ready##0 ~stall[1] and // **I** No preceding FDIV/ FSQRT instruction, could use instead t_id##0 ~(fpu_lat_ex=='h3 && (fpu_op_ex=='h4 || fpu_op_ex=='h5)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and +`ifdef PVE_FPU_SUPPORT + pipe_result(nxt(t_ex_ready,FPU_LATENCY),exe,result,fpu_result) and +`else + pipe_instr(t_arch_update,cur_Arch,exe,result,(FPU_LATENCY>0)?'0:'1) and + pipe_dmem_no_req(t_ex,t_ex_ready) and +`ifdef CFG_F + t_arch_update_fpu##1 (FPU_LATENCY>0) -> (exe.dec.RD[1].RF==rf_X?((exe.dec.RD[1].idx!=0 -> result.data[1]==Arch.X[exe.dec.RD[1].idx].data)):(result.data[1]==Arch.F[exe.dec.RD[1].idx].data)) and +`else + t_arch_update_fpu##1 (FPU_LATENCY>0) -> (exe.dec.RD[1].idx!=0 -> result.data[1]==Arch.X[exe.dec.RD[1].idx].data) and +`endif + t_arch_update_fpu##1 (FPU_LATENCY>0) -> (Arch.CSR.fflags==($past(Arch.CSR.fflags)|result.flags)) and +`endif + t_rd2ex##0 right_hook; +endproperty + +// X PROPERTIES // + +property RV_INSTR_DOT(insn_set insns, select); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_M_SUPPORT + t_ex_ready##0 set_freeze(result,exe.result) and + t_ex_ready##0 restrict_ops(compose_operands(exe.op[1],exe.op[2]),'{default:select}) and +`else + t_ex_ready##0 set_freeze(result,compose_result(mul_result)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and +`ifdef PVE_M_SUPPORT + pipe_result(t_ex_ready,exe,result,mul_result) and +`else + pipe_instr(t_arch_update,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + pipe_operands(t_ex_ready,exe,compose_operands(dot_mul_op_a,dot_mul_op_b,dot_mul_op_c)) and +`endif + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_DOT_SC(insn_set insns, select); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_M_SUPPORT + t_ex_ready##0 set_freeze(result,exe.result) and + t_ex_ready##0 restrict_ops(compose_operands(exe.op[1],exe.op[2]),'{default:select}) and +`else + t_ex_ready##0 set_freeze(result,compose_result(mul_result)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and +`ifdef PVE_M_SUPPORT + pipe_result(t_ex_ready,exe,result,mul_result) and +`else + pipe_instr(t_arch_update,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + pipe_operands(t_ex_ready,exe,compose_operands(dot_mul_op_a,dot_mul_op_b,dot_mul_op_c),compose_selection('h0,select)) and +`endif + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_DOT_SCI(insn_set insns, select); + execute_t exe; + Arch_state_t cur_Arch; + result_t result; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and +`ifdef PVE_M_SUPPORT + t_ex##0 set_freeze(result,exe.result) and + t_ex##0 restrict_ops(compose_operands(exe.op[1],dot_mul_op_b),'{default:select}) and +`else + t_ex_ready##0 set_freeze(result,compose_result(mul_result)) and +`endif + t_id##0 insns[exe.dec.instr] and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies + t_rd2ex##0 Ready2Execute and +`ifdef PVE_M_SUPPORT + pipe_result(t_ex_ready,exe,result,mul_result) and +`else + pipe_instr(t_arch_update,cur_Arch,exe,result) and + pipe_dmem_no_req(t_ex,t_ex_ready) and +// pipe_operands(t_ex_ready,exe,compose_operands(dot_mul_op_a,dot_mul_op_b,dot_mul_op_c),compose_selection('h0,select)) and // operand b manipulation is based on the immediate value +`endif + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_MEM_ELW(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && exe.mem.byte_enable<=4'hf and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(nxt(t_wb_ready_mem,2),~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies +// t_rd2ex##0 Ready2Execute and + pipe_instr(t_arch_update_mem,cur_Arch,exe,exe.result,NUM_RD==2?2'b01:1'b0) and + pipe_dmem_1st_req(t_dmem_gnt,exe) and + during_excl(nxt(t_dmem_gnt,1),t_wb_ready_mem,~dmem_req_valid) and + t_arch_update_mem##1 exe.mem.cmd==mc_load -> rf_we_lsu && rf_waddr_lsu=={(exe.dec.RD[1].RF==rf_F)?1'b1:1'b0,exe.dec.RD[1].idx} and + t_arch_update_mem##1 exe.mem.cmd==mc_load -> lsu_data_type==data_size_enc(exe.mem.size) && lsu_data_sign[0]==((exe.dec.RD[1].RF==rf_X)&exe.mem.signed_data) && lsu_data_offset==exe.mem.addr[1:0] and + t_rd2ex##0 right_hook; +endproperty + +property RV_INSTR_MEM_MA_ELW(insn_set insns); + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 insns[exe.dec.instr] && exe.mem.byte_enable>4'hf and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(nxt(t_wb_ready_mem_ma,2),~(is_interrupt|is_debug)) and + t_id##0 ~exe.xcpt.valid +implies +// t_rd2ex_mem_ma##0 Ready2Execute and + pipe_instr(t_arch_update_mem_ma,cur_Arch,exe,exe.result,NUM_RD==2?2'b01:1'b0) and + pipe_dmem_1st_req(t_dmem_gnt,exe) and + pipe_dmem_2nd_req(t_dmem_2nd_req,exe) and + during_excl(nxt(t_dmem_gnt,1),t_dmem_2nd_req,~dmem_req_valid) and + t_arch_update_mem_ma##1 exe.mem.cmd==mc_load -> rf_we_lsu && rf_waddr_lsu=={(exe.dec.RD[1].RF==rf_F)?1'b1:1'b0,exe.dec.RD[1].idx} and + t_arch_update_mem_ma##1 exe.mem.cmd==mc_load -> lsu_data_type==data_size_enc(exe.mem.size) && lsu_data_sign[0]==((exe.dec.RD[1].RF==rf_X)&exe.mem.signed_data) && lsu_data_offset==exe.mem.addr[1:0] and + t_rd2ex_mem_ma##0 right_hook; +endproperty + +// EXCEPTION PROPERTIES // + +property XCPT_IF_ID_p; + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + pipe_env(t_wb_ready,~(is_interrupt|(is_debug & exe.xcpt.xcpt_code inside {xcpt_Illegal_Instr}))) and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & exe.xcpt.xcpt_code inside {xcpt_Breakpoint,xcpt_Fetch_Page_Fault,xcpt_Fetch_Access_Fault,xcpt_Illegal_Instr,xcpt_Fetch_Addr_Align} & exe.xcpt.brk inside {brk_none,brk_fetch} +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +property XCPT_WB_p; + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + t_id##0 exe.xcpt.valid & ~exe.xcpt.interrupt & (exe.xcpt.xcpt_code inside {xcpt_Breakpoint,xcpt_SAMO_Addr_Align,xcpt_Load_Addr_Align,xcpt_SAMO_Page_Fault,xcpt_Load_Page_Fault,xcpt_SAMO_Access_Fault,xcpt_Load_Access_Fault}) & exe.xcpt.brk inside {brk_none,brk_dmem} +implies + t_rd2ex##0 Ready2Execute and + t_wb_ready##0 no_pending_results_used(exe.dec) and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +// INTERRUPT HANDLING PROPERTIES // + +property INTR_Handle_p; + execute_t exe; + Arch_state_t cur_Arch; + t_model##0 set_freeze(exe,execute) and + t_arch##0 set_freeze(cur_Arch,Arch) and + t_id##0 Ready2Execute and + t_id##0 full[0] && ~stall[0] and + t_id##0 exe.xcpt.valid & exe.xcpt.interrupt +implies + t_rd2ex##0 Ready2Execute and + pipe_xcpt(t_arch_update,cur_Arch,exe.xcpt) and + pipe_dmem_no_req(t_ex,t_ex_ready) and + t_rd2ex##0 right_hook; +endproperty + +/*********************/ +// NON-TIDAL ASSERTIONs +/*********************/ + +// COUNTERS // + +property mcycle_increment_p; + Ready2Execute ##1 ~execute.csr.count_inhibit.CY&~execute.xcpt.interrupt |=> + Arch.CSR.mcycle==$past(Arch.CSR.mcycle+64'h1); +endproperty +mcycle_increment_a : assert property (disable iff(~rst_n) mcycle_increment_p); + +property mcycle_no_increment_p; + Ready2Execute ##1 execute.csr.count_inhibit.CY&Arch.CSR.mcountinhibit.CY&((execute.csr.cmd == cc_none)|(execute.csr.cmd == cc_r)) |=> + Arch.CSR.mcycle==$past(Arch.CSR.mcycle); +endproperty +mcycle_no_increment_a : assert property (disable iff(~rst_n) mcycle_no_increment_p); + +property mhpmcounter3_increment_p; + Ready2Execute ##1 ~execute.csr.count_inhibit.HPM[3]&~execute.xcpt.interrupt |=> + Arch.CSR.mhpmcounter[3]==$past(|(Arch.CSR.mhpmevent[3][15:0]&cs_registers_i.hpm_events) ? Arch.CSR.mhpmcounter[3]+64'h1 : Arch.CSR.mhpmcounter[3]); +endproperty +mhpmcounter3_increment_a : assert property (disable iff(~rst_n) mhpmcounter3_increment_p); + +property mhpmcounter3_no_increment_p; + Ready2Execute ##1 execute.csr.count_inhibit.HPM[3]&Arch.CSR.mcountinhibit.HPM[3]&((execute.csr.cmd == cc_none)|(execute.csr.cmd == cc_r)) |=> + Arch.CSR.mhpmcounter[3]==$past(Arch.CSR.mhpmcounter[3]); +endproperty +mhpmcounter3_no_increment_a : assert property (disable iff(~rst_n) mhpmcounter3_no_increment_p); + +// LSU // + +property stable_lsu_signals_p; + rf_we_lsu&~obi_dmem_checker.rvalid |=> $stable({rf_we_lsu,rf_waddr_lsu,lsu_data_type,lsu_data_offset,lsu_data_sign}); +endproperty +stable_lsu_signals_a : assert property (disable iff(~rst_n) stable_lsu_signals_p); + +property lsu_write_p; + ~rf_waddr_lsu[5]&&rf_we_lsu&&obi_dmem_checker.rvalid && + ~(fpu_result_valid && fpu_waddr[4:0]==rf_waddr_lsu[4:0]) && // A write on ALU port by next F instruction to same RD overtake LSU port write + ~((data_size_enc(lsu_data_type)==2'h2&&lsu_data_offset>0) || // lw + (data_size_enc(lsu_data_type)==2'h1&&lsu_data_offset==2'h3)) // lh + |=> + (obi_dmem_checker.cnt!=$past(obi_dmem_checker.cnt) && rf_waddr_lsu!=$past(rf_waddr_lsu) -> Arch.X[$past(rf_waddr_lsu[4:0])].valid) && + ($past(rf_waddr_lsu[4:0])!='0 -> Arch.X[$past(rf_waddr_lsu[4:0])].data== + $unsigned(align_rdata('{size: data_size_enc($past(lsu_data_type)), signed_data: $past(lsu_data_sign[0]), + addr: $past({30'h0,lsu_data_offset}), default: '0},{32'h0,$past(dmem_resp_data)}))); +endproperty +lsu_write_a : assert property (disable iff(~rst_n) lsu_write_p); + +property lsu_ma_write_p; + ~rf_waddr_lsu[5]&&rf_we_lsu&&obi_dmem_checker.rvalid&&id_stage_i.register_file_i.we_a_i && + ~(fpu_result_valid && fpu_waddr[4:0]==rf_waddr_lsu[4:0])&& + ((data_size_enc(lsu_data_type)==2'h2&&lsu_data_offset>0) || (data_size_enc(lsu_data_type)==2'h1&&lsu_data_offset==2'h3)) + |=> +// Arch.X[$past(rf_waddr_lsu[4:0])].valid && + $past(rf_waddr_lsu[4:0])!='0 -> Arch.X[$past(rf_waddr_lsu[4:0])].data== + $unsigned(align_rdata('{size: data_size_enc($past(lsu_data_type)), signed_data: $past(lsu_data_sign[0]), + addr: $past({30'h0,lsu_data_offset}), default: '0},{$past(dmem_resp_data),$past(load_store_unit_i.rdata_q)})); +endproperty +lsu_ma_write_a : assert property (disable iff(~rst_n) lsu_ma_write_p); + +property lsu_ma_rdata_q_p; + rf_we_lsu&&obi_dmem_checker.rvalid&&cv32e40p_core.data_misaligned_ex&& + ((data_size_enc(lsu_data_type)==2'h2&&lsu_data_offset>0) || (data_size_enc(lsu_data_type)==2'h1&&lsu_data_offset==2'h3)) + |=> + load_store_unit_i.rdata_q==$past(dmem_resp_data); +endproperty +lsu_ma_rdata_q_a : assert property (disable iff(~rst_n) lsu_ma_rdata_q_p); + +`ifdef CFG_F +property lsu_write_f_p; + rf_waddr_lsu[5]&&rf_we_lsu&&obi_dmem_checker.rvalid && + ~(fpu_result_valid && fpu_waddr[4:0]==rf_waddr_lsu[4:0])&& + ~((data_size_enc(lsu_data_type)==2'h2&&lsu_data_offset>0) || (data_size_enc(lsu_data_type)==2'h1&&lsu_data_offset==2'h3)) + |=> + (obi_dmem_checker.cnt!=$past(obi_dmem_checker.cnt) && rf_waddr_lsu!=$past(rf_waddr_lsu) -> Arch.F[$past(rf_waddr_lsu[4:0])].valid) && + (Arch.F[$past(rf_waddr_lsu[4:0])].data== + $unsigned(align_rdata('{size: data_size_enc($past(lsu_data_type)), signed_data: $past(lsu_data_sign[0]), + addr: $past({30'h0,lsu_data_offset}), default: '0},{32'h0,$past(dmem_resp_data)}))); +endproperty +lsu_write_f_a : assert property (disable iff(~rst_n) lsu_write_f_p); + +property lsu_ma_write_f_p; + rf_waddr_lsu[5]&&rf_we_lsu&&obi_dmem_checker.rvalid&&id_stage_i.register_file_i.we_a_i && + ~(fpu_result_valid && fpu_waddr[4:0]==rf_waddr_lsu[4:0])&& + ((data_size_enc(lsu_data_type)==2'h2&&lsu_data_offset>0) || (data_size_enc(lsu_data_type)==2'h1&&lsu_data_offset==2'h3)) + |=> +// Arch.F[$past(rf_waddr_lsu[4:0])].valid && + Arch.F[$past(rf_waddr_lsu[4:0])].data== + $unsigned(align_rdata('{size: data_size_enc($past(lsu_data_type)), signed_data: $past(lsu_data_sign[0]), + addr: $past({30'h0,lsu_data_offset}), default: '0},{$past(dmem_resp_data),$past(load_store_unit_i.rdata_q)})); +endproperty +lsu_ma_write_f_a : assert property (disable iff(~rst_n) lsu_ma_write_f_p); +`endif + +`include `GENERATED_ASSERTIONS_FILE +`include "constraints.sv" + +endmodule diff --git a/scripts/riscv_isa_formal/common/io.sv b/scripts/riscv_isa_formal/common/io.sv new file mode 100755 index 000000000..cb7c9c1e2 --- /dev/null +++ b/scripts/riscv_isa_formal/common/io.sv @@ -0,0 +1,72 @@ + // Data memory interface + input dmem_req_we ='0, // Data memory request type + input[3:0] dmem_req_be ='0, // Data memory request byte enable + input[1:0] dmem_req_size ='0, // Data memory request size + input dmem_req_sign ='0, // Data memory request sign + + // Exceptions & Debug + input is_sstep ='0, // Single stepping of debug mode + input xcpt_bp_if ='0, // Instruction address breakpoint exception + input xcpt_bp_ld ='0, // Load address breakpoint exception + input xcpt_bp_samo ='0, // Store/ AMO address breakpoint exception + input xcpt_dbg_bp_if ='0, // Debug instruction address breakpoint exception + input xcpt_dbg_bp_ld ='0, // Debug load address breakpoint exception + input xcpt_dbg_bp_samo ='0, // Debug Store/ AMO address breakpoint exception + input xcpt_af_instr_1st ='0, // Instruction access fault exception + input xcpt_af_instr_2nd ='0, // Instruction second access fault exception + input xcpt_af_ld_1st ='0, // Load access fault exception + input xcpt_af_ld_2nd ='0, // Load second access fault exception + input xcpt_af_samo_1st ='0, // Store/ AMO access fault exception + input xcpt_af_samo_2nd ='0, // Store/ AMO second access fault exception + input xcpt_pf_instr_1st ='0, // Instruction page fault exception + input xcpt_pf_instr_2nd ='0, // Instruction second access page fault exception + input xcpt_pf_ld_1st ='0, // Load page fault exception + input xcpt_pf_ld_2nd ='0, // Load second access page fault exception + input xcpt_pf_samo_1st ='0, // Store/ AMO page fault exception + input xcpt_pf_samo_2nd ='0, // Store/ AMO second access page fault exception + input xcpt_ma_ld ='0, // Load address misaligned exception + input xcpt_ma_samo ='0, // Store/AMO address misaligned exception + + // Multiplication & Division + input mul_op_valid ='0, // Multiplication operation validity + input[XLEN-1:0] mul_op_a ='0, // Multiplication first source operand + input[XLEN-1:0] mul_op_b ='0, // Multiplication second source operand + input[XLEN-1:0] mul_op_c ='0, // Multiplication third source operand + input[XLEN-1:0] mul_result ='0, // Multiplication operation result + input mul_result_valid ='0, // Multiplication operation result validity + input div_op_valid ='0, // Division operation validity + input[XLEN-1:0] div_op_a ='0, // Division first source operand + input[XLEN-1:0] div_op_b ='0, // Division second source operand + input[$clog2(XLEN):0] div_op_b_shift ='0, // Division second source operand shift amount + input[XLEN-1:0] div_result ='0, // Division operation result + input div_result_valid ='0, // Division operation result validity + + // Floating point + input fpu_op_valid ='0, // FPU operation validity + input[XLEN-1:0] fpu_op_a ='0, // FPU first source operand + input[XLEN-1:0] fpu_op_b ='0, // FPU second source operand + input[XLEN-1:0] fpu_op_c ='0, // FPU third source operand + input Frm fpu_rm ='0, // FPU rounding mode + input Fflags fpu_flags ='0, // FPU flags + input[XLEN-1:0] fpu_result ='0, // FPU operation result + input fpu_result_valid ='0, // FPU operation result validity + + // Design specific + input is_debug ='0, // Core is about to enter debug mode + input is_interrupt ='0, // Core is about to encounter an interrupt + input[XLEN-1:0] boot_addr ='0, // Boot address + + input rf_we_lsu ='0, + input[5:0] rf_waddr_lsu ='0, + input[1:0] lsu_data_type ='0, + input[1:0] lsu_data_sign ='0, + input[1:0] lsu_data_offset ='0, + input fpu_s_cycle ='0, + input fpu_m_cycle ='0, + input[5:0] fpu_waddr ='0, + input[5:0] fpu_waddr_ex ='0, + input[1:0] fpu_lat_ex ='0, + input[5:0] fpu_op_ex ='0, + input[XLEN-1:0] dot_mul_op_a ='0, + input[XLEN-1:0] dot_mul_op_b ='0, + input[XLEN-1:0] dot_mul_op_c ='0 diff --git a/scripts/riscv_isa_formal/common/other_bindings.sv b/scripts/riscv_isa_formal/common/other_bindings.sv new file mode 100755 index 000000000..41c929d20 --- /dev/null +++ b/scripts/riscv_isa_formal/common/other_bindings.sv @@ -0,0 +1,72 @@ + // Data memory interface + .dmem_req_we (data_we_o), + .dmem_req_be (data_be_o), + .dmem_req_size (), + .dmem_req_sign (), + + // Exceptions & Debug + .is_sstep (debug_single_step), + .xcpt_bp_if (), + .xcpt_bp_ld (), + .xcpt_bp_samo (), + .xcpt_dbg_bp_if (), + .xcpt_dbg_bp_ld (), + .xcpt_dbg_bp_samo (), + .xcpt_af_instr_1st (), + .xcpt_af_instr_2nd (), + .xcpt_af_ld_1st (), + .xcpt_af_ld_2nd (), + .xcpt_af_samo_1st (), + .xcpt_af_samo_2nd (), + .xcpt_pf_instr_1st (), + .xcpt_pf_instr_2nd (), + .xcpt_pf_ld_1st (), + .xcpt_pf_ld_2nd (), + .xcpt_pf_samo_1st (), + .xcpt_pf_samo_2nd (), + .xcpt_ma_ld (), + .xcpt_ma_samo (), + + // Multiplication & Division + .mul_op_valid (), + .mul_op_a (ex_stage_i.mult_i.op_a_i), + .mul_op_b (ex_stage_i.mult_i.op_b_i), + .mul_op_c (ex_stage_i.mult_i.op_c_i), + .mul_result (ex_stage_i.mult_i.result_o), + .mul_result_valid (), + .div_op_valid (), + .div_op_a (ex_stage_i.alu_i.alu_div_i.OpA_DI), + .div_op_b (ex_stage_i.alu_i.alu_div_i.OpB_DI), + .div_op_b_shift (ex_stage_i.alu_i.alu_div_i.OpBShift_DI), + .div_result (ex_stage_i.alu_i.alu_div_i.Res_DO), + .div_result_valid (ex_stage_i.alu_i.div_ready), + + // Floating point + .fpu_op_valid (ex_stage_i.apu_req), + .fpu_op_a (ex_stage_i.apu_operands_o[0]), + .fpu_op_b (ex_stage_i.apu_operands_o[1]), + .fpu_op_c (ex_stage_i.apu_operands_o[2]), + .fpu_rm (), + .fpu_flags (ex_stage_i.fpu_fflags_o), + .fpu_result (ex_stage_i.apu_result), + .fpu_result_valid (ex_stage_i.apu_valid), + + // Design specific + .is_debug (id_stage_i.controller_i.ctrl_fsm_cs inside {DBG_TAKEN_ID,DBG_TAKEN_IF,DBG_FLUSH}), + .is_interrupt (id_stage_i.int_controller_i.irq_req_ctrl_o), + .boot_addr ({boot_addr_i[31:2],2'b00}), + + .rf_we_lsu (ex_stage_i.regfile_we_lsu), + .rf_waddr_lsu (ex_stage_i.regfile_waddr_lsu), + .lsu_data_type (load_store_unit_i.data_type_q), + .lsu_data_sign (load_store_unit_i.data_sign_ext_q), + .lsu_data_offset (load_store_unit_i.rdata_offset_q), + .fpu_s_cycle (ex_stage_i.apu_singlecycle), + .fpu_m_cycle (ex_stage_i.apu_multicycle), + .fpu_waddr (ex_stage_i.apu_waddr), + .fpu_waddr_ex (apu_waddr_ex), + .fpu_lat_ex (apu_lat_ex), + .fpu_op_ex (apu_op_ex), + .dot_mul_op_a (ex_stage_i.mult_dot_op_a_i), + .dot_mul_op_b (ex_stage_i.mult_dot_op_b_i), + .dot_mul_op_c (ex_stage_i.mult_dot_op_c_i) diff --git a/scripts/riscv_isa_formal/common/setup.tcl b/scripts/riscv_isa_formal/common/setup.tcl new file mode 100755 index 000000000..0bcce5472 --- /dev/null +++ b/scripts/riscv_isa_formal/common/setup.tcl @@ -0,0 +1,564 @@ +proc duration {int_time} { + set timeList [list] + if {$int_time == 0} { + return "0 Sec" + } else { + foreach div {86400 3600 60 1} mod {0 24 60 60} name {Day Hour Min Sec} { + set n [expr {$int_time / $div}] + if {$mod > 0} {set n [expr {$n % $mod}]} + if {$n > 1} { + lappend timeList "$n ${name}s" + } elseif {$n == 1} { + lappend timeList "$n $name" + } + } + return [join $timeList] + } +} + +proc quantify_run {{cmd_limit 0} {run 0} {no_cuts {}} {limit_scale 2.0} {effort 4} {skip_effort_level 0} {html_dir {}} {result_file {}} {checks {}} {prev_run_result {}} {skip_files {}}} { + + puts "\n-INFO- Start of Quantify Run ($run)::\n\nChecks Included::\n\n$checks" + + set_limit -command_real_time $cmd_limit + set run_start_t [clock seconds] + puts "\n-INFO- Launching Quantify Command::\n\nquantify -assume_hold -additional_args \[list $no_cuts -limit_scale $limit_scale -use_single_prover\] -effort $effort -skip_effort_level $skip_effort_level -html $html_dir -save $result_file -checks $checks -incremental $prev_run_result -skip_files $skip_files\n" + catch {quantify -assume_hold -additional_args [list $no_cuts -limit_scale $limit_scale -use_single_prover] -effort $effort -skip_effort_level $skip_effort_level -html $html_dir -save $result_file -checks $checks -incremental $prev_run_result -skip_files $skip_files} + set run_end_t [expr [clock seconds] - $run_start_t] + set_limit -default + + puts "\n-INFO- End of Quantify Run ($run) | Time spent:: [duration $run_end_t]\n" +} + +## 0. DESIGN SETUP ## + +### SETTING UP THE DESIRED CONFIGURATION, RUN & APP ### +## source the setup.inc as the following: [onespin -i setup.inc ] +## arg1: what configuration to set . +## arg2: what processor verification mode to set . +## arg3: what app to launch on top of the processor app. +## ------------------------------------------------------------------------------------------------------------------ + +set configs [dict create \ + "DEF" [dict create \ + description "RV32IMCZicsr_Zifencei" \ + elab "-verilog_parameter {}" \ + define "" \ + json "" \ + ] \ + "F0" [dict create \ + description "RV32IMFCZicsr_Zifencei with FPU latency params set to 0" \ + elab "-verilog_parameter {FPU=1 FPU_ADDMUL_LAT=0 FPU_OTHERS_LAT=0}" \ + define "CFG_F" \ + json "" \ + ] \ + "ZF0" [dict create \ + description "RV32IMCZicsr_Zifencei_Zfinx with FPU latency params set to 0" \ + elab "-verilog_parameter {FPU=1 ZFINX=1 FPU_ADDMUL_LAT=0 FPU_OTHERS_LAT=0}" \ + define "CFG_ZFINX" \ + json "" \ + ] \ + "XP" [dict create \ + description "RV32IMCZicsr_Zifencei_Xpulp" \ + elab "-verilog_parameter {COREV_PULP=1}" \ + define "CFG_XP" \ + json "Xpulp.json Zfinx.json" \ + ] \ + "XPF0" [dict create \ + description "RV32IMFCZicsr_Zifencei_Xpulp with FPU latency params set to 0" \ + elab "-verilog_parameter {FPU=1 COREV_PULP=1 FPU_ADDMUL_LAT=0 FPU_OTHERS_LAT=0}" \ + define "CFG_XP CFG_F" \ + json "Xpulp.json" \ + ] \ + "XPF1" [dict create \ + description "RV32IMFCZicsr_Zifencei_Xpulp with FPU latency params set to 1" \ + elab "-verilog_parameter {FPU=1 COREV_PULP=1 FPU_ADDMUL_LAT=1 FPU_OTHERS_LAT=1}" \ + define "CFG_XP CFG_F" \ + json "Xpulp.json" \ + ] \ + "XPF2" [dict create \ + description "RV32IMFCZicsr_Zifencei_Xpulp with FPU latency params set to 2" \ + elab "-verilog_parameter {FPU=1 COREV_PULP=1 FPU_ADDMUL_LAT=2 FPU_OTHERS_LAT=2}" \ + define "CFG_XP CFG_F" \ + json "Xpulp.json" \ + ] \ + "XPZF0" [dict create \ + description "RV32IMCZicsr_Zifencei_Zfinx_Xpulp with FPU latency params set to 0" \ + elab "-verilog_parameter {FPU=1 ZFINX=1 COREV_PULP=1 FPU_ADDMUL_LAT=0 FPU_OTHERS_LAT=0}" \ + define "CFG_XP CFG_ZFINX" \ + json "Xpulp.json Zfinx.json" \ + ] \ + "XPZF1" [dict create \ + description "RV32IMCZicsr_Zifencei_Zfinx_Xpulp with FPU latency params set to 1" \ + elab "-verilog_parameter {FPU=1 ZFINX=1 COREV_PULP=1 FPU_ADDMUL_LAT=1 FPU_OTHERS_LAT=1}" \ + define "CFG_XP CFG_ZFINX" \ + json "Xpulp.json Zfinx.json" \ + ] \ + "XPZF2" [dict create \ + description "RV32IMCZicsr_Zifencei_Zfinx_Xpulp with FPU latency params set to 2" \ + elab "-verilog_parameter {FPU=1 ZFINX=1 COREV_PULP=1 FPU_ADDMUL_LAT=2 FPU_OTHERS_LAT=2}" \ + define "CFG_XP CFG_ZFINX" \ + json "Xpulp.json Zfinx.json" \ + ] \ + "XPXC" [dict create \ + description "RV32IMCZicsr_Zifencei_Xpulp_Xcluster" \ + elab "-verilog_parameter {COREV_PULP=1 COREV_CLUSTER=1}" \ + define "CFG_XP CFG_XC" \ + json "Xpulp.json Xcluster.json Zfinx.json" \ + ] \ + "XPXCZF2" [dict create \ + description "RV32IMCZicsr_Zifencei_Zfinx_Xpulp_Xcluster with FPU latency params set to 2" \ + elab "-verilog_parameter {FPU=1 ZFINX=1 COREV_PULP=1 COREV_CLUSTER=1 FPU_ADDMUL_LAT=2 FPU_OTHERS_LAT=2}" \ + define "CFG_XP CFG_XC CFG_ZFINX" \ + json "Xpulp.json Xcluster.json Zfinx.json" \ + ] \ +] + +set pve_modes [dict create \ + "DEF" [dict create \ + description "DEF: Control path verification of all instructions and datapath verification of all instructions except multiplication, division or floating point ones" \ + define "" \ + ] \ + "DPM" [dict create \ + description "DPM: Data path verification of multiplication/ division instructions" \ + define "PVE_M_SUPPORT RESTRICT_MUL_OPS_FREE_BITS=1" \ + ] \ + "DPF" [dict create \ + description "DPF: Data path verification of floating-point instructions" \ + define "PVE_FPU_SUPPORT RESTRICT_MUL_OPS_FREE_BITS=1" \ + ] \ +] + +set apps [dict create \ + "PRC" [dict create \ + description "PRC: Property Checking" \ + compile "-dontcare_handling any -signal_domain {{scan_cg_en_i} 0}" \ + ] \ + "QTF" [dict create \ + description "QTF: Quantify" \ + compile "-dontcare_handling any -signal_domain {{scan_cg_en_i} 0} -constant [list [list core_i.id_stage_i.register_file_i.rst_n 1] ]" \ + ] \ + "VCI" [dict create \ + description "VCI: Verification Coverage Integration" \ + compile "-dontcare_handling any -signal_domain {{scan_cg_en_i} 0}" \ + ] \ +] + +if {$::argc>0} { + lassign $::argv cfg pve_mode app + if {$cfg ni [dict keys $configs]} { + onespin::message -error "Only configurations [join [dict keys $configs] ,] are supported!" + return -code error + } + if {$pve_mode ni [dict keys $pve_modes]} { + onespin::message -error "Only processor verification modes [join [dict keys $pve_modes] ,] are supported!" + return -code error + } elseif {$pve_mode eq "DPF" && $cfg in {"DEF" "XP" "XPXC"} } { + onespin::message -error "Floating-point configuration must be selected in order to perform data path verification!" + return -code error + } + if {$app ni [dict keys $apps]} { + onespin::message -error "Only apps [join [dict keys $apps] ,] are supported!" + return -code error + } +} else { + if {[get_tool_info -gui]} { + set cfg [string index [onespin::ask_user -default 0 -alternatives [lmap {k d} $configs {string cat "$k - " [dict get $d description]}] "Select which RISC-V configuration to set up:"] 0] + set pve_mode [string index [onespin::ask_user -default "DEF" -alternatives [lmap {k d} $pve_modes {string cat "$k - " [dict get $d description]}] "Select which processor verification mode to set:"] 0] + set app [string index [onespin::ask_user -default "PRC" -alternatives [lmap {k d} $apps {string cat "$k - " [dict get $d description]}] "Select which app to launch:"] 0] + } else { + set cfg "DEF" + set pve_mode "DEF" + set app "PRC" + } +} +set target cv32e40p_top +set core_inst core_i +set prefix ${core_inst}. +## + +### ADJUST TO READ-IN THE NEW DESIGN ### +onespin::set_parameter disable_intermediate_arithmetic_signals 1 +set cwd [pwd] +set_session_option -naming_style sv +set_compile_option {*}[dict get $apps $app compile] +set_elaborate_option {*}[dict get $configs $cfg elab] -top $target +cd cv32e40p +source $cwd/setup_mv.tcl +set_reset_sequence -low rst_ni +cd $cwd + +set cfg_dir $cwd/$cfg +set pve_mode_dir $cwd/$cfg/$pve_mode +set app_dir $cwd/$cfg/$pve_mode/$app +file mkdir $cfg_dir +file mkdir $pve_mode_dir +file mkdir $app_dir +## + +### PROCESSOR APP FLOW ### + +## --------------------------------------------------------------------------------------------------------------------------------- +## 1 > 2 > 3 > 4 > 5 > 6 > 7 +## --------------------------------------------------------------------------------------------------------------------------------- +## PRE-ANALYSIS | DESIGN | POST-ANALYSIS | ASSERTION | ASSERTION | PERFORMANCE | ASSERTION +## CONFIGURATION | ANALYSIS | CONFIGURATION | GENERATION | READING & RETUNING | ENHANCEMENT | RUNNING & DEBUGGING +## --------------------------------------------------------------------------------------------------------------------------------- + +## --------------------------------------------------------------------------------------------------------------------------------- +## processor_integrity:: | DESCRIPTION +## --------------------------------------------------------------------------------------------------------------------------------- +## extract_ISA | Extract ISA from a RISC-V based processor core and store data in a processor database. +## -core_instance <> | Specify instance name of the core in the DUV to instantiate the VIP on. +## -csr_addr <> | Specify CSR address signal that might be used to assist extraction. +## -csr_rdata <> | Specify CSR read data signal that might be used to assist extraction. +## merge_data | Merge JSON data into the database. +## -file <> | Specify JSON file to be merged. +## -configuration <> | Specify predefined JSON configuration to be merged. +## generate_assertions | Generate assertions for verifying the RISC-V core based on the database. +## -create_individual_checks <> | Specify extensions for which assertions are generated per instruction. +## -exclude_extensions <> | Specify extensions for which assertions generation is supressed. +## -include_extensions <> | Specify extensions only for which assertions are generated. +## generate_IVA | Perform initial value abstraction of architecture state. +## -candidates <> | Specify architecture register fields to be abstracted. +## analyze_trace | Perform detailed trace analysis of run assertions. +## save_data | Write the processor database, or part of it, to a JSON file. +## clear_data | Clear JSON data from the processor database. +## --------------------------------------------------------------------------------------------------------------------------------- +## For full app documentation run "help *processor_integrity::*" or refer to Chapter 14. of the User Manual. +## --------------------------------------------------------------------------------------------------------------------------------- + +## 0. APP SETUP ## + +package require processor_integrity + +### APPEND THE FOLLOWING SET OF DEFINES (ONLY IF NECESSARY) ### +## --------------------------------------------------------------------------------------------------------------------------------- +## DEFINE | USE CASE IF SET +## --------------------------------------------------------------------------------------------------------------------------------- +## GRADUAL VERIFICATION ## +## SKIP_PC_CHECK | Skip checking PC register updates. +## SKIP_RF_CHECK | Skip checking register file updates. +## SKIP_CSR_CHECK | Skip checking CSR updates and reads. +## SKIP_DMEM_CHECK | Skip checking data memory requests. +## LIMIT_TOTAL_INSTR_COUNT | Limit total # of instructions allowed in the pipeline. +## PERFORMANCE ENHANCEMENT ## +## RESTRICT_REGS | Restrict instruction decoding & register file verification to a subset of registers. +## RESTRICT_REGISTER_INDEX | Restrict register file verification to one register only, instruction decoding is not affected. +## RESTRICT_CHECK_DATA_SLICE | Restrict register file data and memory write data verification to a slice or even a bit. +## RESTRICT_MUL_OPS_FREE_BITS | Restrict # of operand bits allowed to toggle checking multiplication/ division instruction datapath. +## RESTRICT_DMEM_STALL_CYCLES | Restrict data memory stall cycles to specific number. Has an effect w/ protocol VIPs' usage. +## TAILORED VERIFICATION ## +## PVE_M_SUPPORT | Enable checking M extension data path. By default, only the control path is checked. +## PVE_FPU_SUPPORT | Enable checking F extension data path. By default, only the control path is checked. +## CHECK_ACCESS_FAULTS | Enable checking all access faults fully according to the privileged specification or Smepmp. +## CUSTOM_MEM_INTERFACES | Constrain memory interfaces. Use only in case bus protocols implemented are not tool supported. +## --------------------------------------------------------------------------------------------------------------------------------- +lappend defines {*}[dict get $configs $cfg define] {*}[dict get $pve_modes $pve_mode define] RESTRICT_REGS RESTRICT_DMEM_STALL_CYCLES=2 +## + +### RE-SET THE FOLLOWING SET OF VARIABLES (ONLY IF NECESSARY) ### +lappend pre_analysis_json_files_to_merge spec.json {*}[dict get $configs $cfg json] +set csr_addr_to_assist_analysis {} +set csr_rdata_to_assist_analysis {} +set core_instance_to_instantiate_vip_on ${core_inst} +lappend post_analysis_json_files_to_merge spec.json {*}[dict get $configs $cfg json] core.json +lappend extensions_to_generate_individual_checks_for F Zfinx +set extensions_to_exclude_assertion_generation_for {} +if {"CV_LOOP" in $defines} { + lappend pre_analysis_json_files_to_merge Xpulp_hwlp.json + lappend post_analysis_json_files_to_merge Xpulp_hwlp.json +} +## + +### EXTEND THE FOLLOWING LISTS BY THE RESPECTIVE RTL SIGNALS (ONLY IF NECESSARY) ### +lappend mul_signals_to_cut ${prefix}ex_stage_i.mult_i.result_o ${prefix}ex_stage_i.alu_i.alu_div_i.Res_DO ${prefix}ex_stage_i.alu_i.alu_div_i.Cnt_DP +lappend fpu_signals_to_cut ${prefix}apu_result_i ${prefix}apu_flags_i +lappend rtl_signals_to_cut +lappend rtl_signals_to_disassemble ${prefix}instr_rdata_i ${prefix}instr_rdata_id ${prefix}if_stage_i.instr_aligned +## + +if {![info exists reuse_files] || !$reuse_files} { + +## 1. PRE-ANALYSIS CONFIGURATION ## + + foreach i ${pre_analysis_json_files_to_merge} { + processor_integrity::merge_data -file ${i} + } + +## 2. DESIGN ANALYSIS ## + + processor_integrity::extract_ISA -csr_addr $csr_addr_to_assist_analysis -csr_rdata $csr_rdata_to_assist_analysis -core_instance $core_instance_to_instantiate_vip_on + +## 3. POST-ANALYSIS CONFIGURATION ## + + foreach i ${post_analysis_json_files_to_merge} { + processor_integrity::merge_data -file ${i} + } + + if {"CFG_ZFINX" in $defines} { + onespin::data::set ISA/Z/Zfinx true + } + + if {$pve_mode ne "DEF"} { + onespin::data::set PVE/checker_instance "RV_chk_DP" + } + +## 4. ASSERTION GENERATION ## + + cd $pve_mode_dir + processor_integrity::generate_assertions -create_individual_checks $extensions_to_generate_individual_checks_for -exclude_extensions $extensions_to_exclude_assertion_generation_for -force + cd $cwd +} else { + puts "-W- Re-using previously generated files! Make sure to re-generate all files on adopting a new tool version or changing the JSON configuration!" + source $pve_mode_dir/RISCV_disass.tcl + source RISCV_disass.tcl +} + +## 5. ASSERTION READING & RETUNING ## + +### USE TO CONSTRAIN MEMORY INTERFACES (ONLY IF BUS PROTOCOLS IMPLEMENTED ARE TOOL SUPPORTED) ### +## Instantiate the respective bus protocol VIP for each of the fetch and data memory interfaces +## The VIPs in this case are used to check and more importantly constrain memory interfaces +## Read in the instantiated VIPs, my_{}.sv, using the read_sva command below +#instantiate_vip -addr_sig instr_addr_o -generated_instance_name obi_imem_checker -filename obi_imem.sv obi +#instantiate_vip -addr_sig data_addr_o -generated_instance_name obi_dmem_checker -filename obi_dmem.sv obi +## + +read_sva -define $defines -include_path $pve_mode_dir {core_checker.sv $pve_mode_dir/bind.sv vips/obi_?mem.sv} + +## 7.1 ASSERTION RUNNING & DEBUGGING ## + +### USE TO RUN INITIAL SET OF ASSERTIONS ### +set_check_option -prover_exec_order { { approver1 approver4 prover2:0 prover2:8 prover2:11 disprover1 disprover3 } } -disprover1_steps 40 -disprover3_steps 40 +check [get_checks -filter name=~"*invariant_a"||name=~"*legal_CSR_reset_state_a"||name=~"*RESET_a"] +## + +## 6. PERFORMANCE ENHANCEMENT ## + +### USE TO COMPUTE INVARIANTS (IF NECESSARY) ### +compute_invariants +## + +if {$app eq "PRC"} { + ### USE TO PERFORM AUTOMATIC INITIAL VALUE ABSTRACTION (IVA) OF ARCHITECTURE STATE (IF NECESSARY) ### + lappend candidates X F frm + if {"CFG_XP" in $defines} { + lappend candidates lpstart0 lpstart1 lpend0 lpend1 + } + processor_integrity::generate_IVA -candidates $candidates + ## +} + +### USE TO CUT DESIGN COMPLEX SIGNALS (IF NECESSARY) ### +if {$pve_mode ne "DPM"} { + lappend rtl_signals_to_cut {*}$mul_signals_to_cut +} +if {($pve_mode ne "DPF") && ("CFG_F" in $defines || "CFG_ZFINX" in $defines)} { + lappend rtl_signals_to_cut {*}$fpu_signals_to_cut +} +add_cut_signals $rtl_signals_to_cut +cut_signals +## + +## 7.2 ASSERTION RUNNING & DEBUGGING ## + +### USE TO EASE DEBUGGING BY DISASSEMBLING VALUES OF RTL SIGNALS HOLDING INSTRUCTION WORDS & RUN THE OTHER ASSERTIONS ### +foreach i ${rtl_signals_to_disassemble} { + use_value_printer ${i} PVE_disass +} +## + +#set nb_processes 2 +#set nb_processes 3 +#set nb_processes 4 +#set nb_processes 5 +#set nb_processes 6 +#set nb_processes 8 +#set nb_processes 12 +set nb_processes 16 +#set nb_processes 24 +#set nb_processes 32 + +set_check_option -verbose +set_check_option -local_processes $nb_processes +set_check_option -engine_licensing unlimited + +puts "\n-INFO- Launching $app app in $pve_mode mode with $nb_processes parallel processes.\n" + +#set_check_option -prover_exec_order { { approver1 approver4 prover2:0 prover2:8 prover2:11 disprover1 disprover3 } } +set_check_option -prover_exec_order { { approver1 prover2:0 prover2:8 prover2:11 } } +#set_check_option -disprover1_steps 40 -disprover3_steps 40 + +check_consistency -category model_building -effort maximum +exclude_check [get_checks -filter name=~"*hdl*"||name=~"*FSQRT_S_a*"||name=~"**FDIV_S_a*"] + +set DEF_checks [lsort -dictionary [get_checks -filter excluded==false&&(type==property||type==assertion)]] +set DPM_checks [lsort -dictionary [get_checks -filter excluded==false&&(name=~"*RV32M.*"||name=~"*RV32X.CV_XDOT*"||name=~"*RV32X.CV_MUL*"||name=~"*RV32X.CV_MAC*"||name=~"*RV32X.CV_CPLXMUL*")]] +set DPF_checks [lsort -dictionary [get_checks -filter excluded==false&&(name=~"*RV32F.*"||name=~"*RV32Zfinx.*")]] + +set group_1_checks [lsort -dictionary [concat core_i.RV_chk.ops.RESET_a [get_checks -filter excluded==false&&type==assertion]]] +set group_2_checks [lsort -dictionary [list core_i.RV_chk.ops.XCPT_IF_ID_a core_i.RV_chk.RV32C.ARITH_a core_i.RV_chk.RV32C.BRANCH_Taken_a core_i.RV_chk.RV32C.BRANCH_a core_i.RV_chk.RV32C.JUMP_a core_i.RV_chk.RV32I.EBREAK_BreakPoint_a core_i.RV_chk.RV32I.MEM_MultiAccess_a core_i.RV_chk.RV32I.xRET_a core_i.RV_chk.RV32X.CV_ADD_X_a core_i.RV_chk.RV32X.CV_BITMAN_OTHER_a core_i.RV_chk.RV32X.CV_EXTRACTX_X_a core_i.RV_chk.RV32X.CV_INSERTX_a core_i.RV_chk.RV32X.CV_PACKXX_X_a core_i.RV_chk.RV32X.CV_SETUPX_a core_i.RV_chk.RV32X.CV_SHUFFLE2_X_a core_i.RV_chk.RV32Zicsr.CSRx_a]] +set group_3_checks [lsort -dictionary [list core_i.RV_chk.ops.BUBBLE_a core_i.RV_chk.RV32I.ARITH_a core_i.RV_chk.RV32I.EBREAK_HaltReq_a core_i.RV_chk.RV32I.ECALL_a core_i.RV_chk.RV32I.FENCE_a core_i.RV_chk.RV32I.WFI_a core_i.RV_chk.RV32X.CV_ABS_X_a core_i.RV_chk.RV32X.CV_CLIPXX_a core_i.RV_chk.RV32X.CV_CMPEQ_X_a core_i.RV_chk.RV32X.CV_EXTRACTXX_a core_i.RV_chk.RV32X.CV_EXTXX_a core_i.RV_chk.RV32X.CV_INSERT_X_a core_i.RV_chk.RV32X.CV_SX_I_a core_i.RV_chk.RV32X.CV_SX_RI_a core_i.RV_chk.RV32X.CV_ADDXXNR_a core_i.RV_chk.RV32X.CV_SHUFFLEIX_SCI_B_a core_i.RV_chk.RV32X.CV_BSETX_a core_i.RV_chk.RV32X.CV_BXXIMM_Taken_a core_i.RV_chk.RV32X.CV_ENDX_a core_i.RV_chk.RV32X.CV_LXX_I_a core_i.RV_chk.RV32X.CV_LXX_RI_a core_i.RV_chk.RV32X.CV_SLL_X_a core_i.RV_chk.RV32X.CV_STARTX_a core_i.RV_chk.RV32X.CV_ADD_DIVX_a core_i.RV_chk.RV32X.CV_ADDXXN_a core_i.RV_chk.RV32X.CV_AVGU_X_a core_i.RV_chk.RV32X.CV_BCLRX_a core_i.RV_chk.RV32X.CV_SUB_DIVX_a core_i.RV_chk.RV32X.CV_SUBROTMJ_X_a core_i.RV_chk.RV32X.CV_SUBXXN_a core_i.RV_chk.RV32X.CV_SUBXXNR_a core_i.RV_chk.RV32X.CV_MAXU_X_a]] +set group_4_checks [lsort -dictionary [concat [get_checks -filter excluded==false&&name=~"*RV32X.CV_ELW*"] core_i.RV_chk.RV32I.EBREAK_ForcedEntry_a core_i.RV_chk.RV32X.CV_COUNTX_a core_i.RV_chk.RV32X.CV_LXX_R_a core_i.RV_chk.RV32X.CV_MAXX_a core_i.RV_chk.RV32X.CV_SX_R_a core_i.RV_chk.RV32C.MEM_a core_i.RV_chk.RV32C.MEM_MultiAccess_a core_i.RV_chk.RV32I.BRANCH_a core_i.RV_chk.RV32I.BRANCH_Taken_a core_i.RV_chk.RV32I.JUMP_a core_i.RV_chk.RV32I.MEM_a core_i.RV_chk.RV32X.CV_ABS_a core_i.RV_chk.RV32X.CV_AND_X_a core_i.RV_chk.RV32X.CV_AVG_X_a core_i.RV_chk.RV32X.CV_BXXIMM_a core_i.RV_chk.RV32X.CV_CMPGE_X_a core_i.RV_chk.RV32X.CV_CMPGEU_X_a core_i.RV_chk.RV32X.CV_CMPGT_X_a core_i.RV_chk.RV32X.CV_CMPGTU_X_a core_i.RV_chk.RV32X.CV_CMPLE_X_a core_i.RV_chk.RV32X.CV_CMPLEU_X_a core_i.RV_chk.RV32X.CV_CMPLT_X_a core_i.RV_chk.RV32X.CV_CMPLTU_X_a core_i.RV_chk.RV32X.CV_CMPNE_X_a core_i.RV_chk.RV32X.CV_CPLXCONJ_a core_i.RV_chk.RV32X.CV_LXX_I_MultiAccess_a core_i.RV_chk.RV32X.CV_LXX_R_MultiAccess_a core_i.RV_chk.RV32X.CV_LXX_RI_MultiAccess_a core_i.RV_chk.RV32X.CV_MAX_X_a core_i.RV_chk.RV32X.CV_MIN_X_a core_i.RV_chk.RV32X.CV_MINU_X_a core_i.RV_chk.RV32X.CV_MINX_a core_i.RV_chk.RV32X.CV_OR_X_a core_i.RV_chk.RV32X.CV_SHUFFLE_X_a core_i.RV_chk.RV32X.CV_SLEX_a core_i.RV_chk.RV32X.CV_SRA_X_a core_i.RV_chk.RV32X.CV_SRL_X_a core_i.RV_chk.RV32X.CV_SUB_X_a core_i.RV_chk.RV32X.CV_SX_I_MultiAccess_a core_i.RV_chk.RV32X.CV_SX_R_MultiAccess_a core_i.RV_chk.RV32X.CV_SX_RI_MultiAccess_a core_i.RV_chk.RV32X.CV_XOR_X_a core_i.RV_chk.RV32Zifencei.FENCE_I_a]] +set group_5_checks [lsort -dictionary [get_checks -filter excluded==false&&(name=~"*RV32M.DIV16_a*"||name=~"*RV32M.DIV32_a*"||name=~"*RV32M.MUL_a*"||name=~"*RV32X.CV_XDOT*"||name=~"*RV32X.CV_MUL*"||name=~"*RV32X.CV_MAC*"||name=~"*RV32X.CV_CPLXMUL*")]] +set group_6_checks [lsort -dictionary [get_checks -filter excluded==false&&(name=~"*RV32F.*"||name=~"*RV32Zfinx.*")]] + +set skipped_files "*/fpnew_* {} */gated_clk_cell* {} */lzc* {} */pa_fdsu_* {} */pa_fpu_* {} */rr_arb_tree* {}" + +puts "\n-INFO- Compile options::\n\n\t[dict get $apps $app compile]\n" +puts "\n-INFO- Elaborate options::\n\n\t[dict get $configs $cfg elab]\n" +puts "\n-INFO- Defines::\n\n\t$defines\n" +puts "\n-INFO- Cut signals::\n\n\t$rtl_signals_to_cut\n" + +if {$app eq "PRC"} { + +# set_check_option -prover_exec_order { { approver1 approver4 prover2:0 prover2:8 prover2:11 disprover1 disprover3 } } + set_check_option -prover_exec_order { { approver1 prover2:0 prover2:8 prover2:11 } } +# set_check_option -prover_exec_order { { disprover1 disprover3 } } -disprover1_steps 20 -disprover3_steps 20 + + set all_checks [set ${pve_mode}_checks] + set checks_nb [llength $all_checks] + set nb_round [expr $checks_nb / $nb_processes] + set nb_remain [expr $checks_nb % $nb_processes] + puts "nb_round = $nb_round, nb_remain = $nb_remain" + for {set i 0} {$i < $nb_round} {incr i} { + set checks [lrange $all_checks [expr $i * $nb_processes] [expr ((($i + 1) * $nb_processes) - 1)]] + puts "[expr $i * $nb_processes] [expr ((($i + 1) * $nb_processes) - 1)]" + puts "\n-INFO- Launching Check Command::\n\ncheck $checks\n" + check $checks + report_result -details + cd $app_dir + save_database -force round_[expr $i + 1] + cd $cwd + } + if {$nb_remain > 0} { + set checks [lrange $all_checks [expr $nb_round * $nb_processes] [expr (($nb_round * $nb_processes) + $nb_remain - 1)]] + puts "[expr $nb_round * $nb_processes] [expr (($nb_round * $nb_processes) + $nb_remain - 1)]" + puts "\n-INFO- Launching Check Command::\n\ncheck $checks\n" + check $checks + report_result -details + cd $app_dir + save_database -force round_[expr $nb_round + 1] + cd $cwd + } + + report_result -signoff -details + +# set_check_option -prover_exec_order { { disprover1 disprover3 } } +# puts "\n-INFO- Launching Check Command::\n\ncheck RV32M.DIV16_a\n" +# check [get_checks -filter name=~"*RV32M.DIV16_a*"] +# cd $app_dir +# save_database -force +# cd $cwd + +} + +if {$app eq "QTF"} { + + source basics.tcl.obf + + set_check_option -prover_exec_order { { disprover1 disprover3 } } -disprover1_steps 20 -disprover3_steps 20 + + set html "${app_dir}/html_results_${cfg}_${pve_mode}" + set results "${app_dir}/qtf_results_${cfg}_${pve_mode}_R" + set log "${app_dir}/${app}_${cfg}_${pve_mode}_R" + + if {$pve_mode eq "DEF"} { + + for {set i 1} {$i < 7} {incr i} { + puts "\nGroup (${i}) checks:\n\nTotal number of checks is: [llength [set group_${i}_checks]] \n" + foreach j [set group_${i}_checks] { + puts "$j" + } + } + + for {set i 1} {$i < 7} {incr i} { + puts "Group (${i}) checks: Total number of checks is: [llength [set group_${i}_checks]]" + } + +# for {set i 1} {$i < 7} {incr i} { + + set i 5 + + start_message_log ${log}${i}.log + if {$i == 1} { + quantify_run 0 $i {-no_cuts} 1.0 2 1 ${html}_L2_S1_R${i} ${results}${i} $group_1_checks {} {} + } elseif {$i == 2} { + quantify_run 0 $i {-no_cuts} 4.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_2_checks ${results}[expr $i-1] $skipped_files + } elseif {$i == 3} { + quantify_run 0 $i {-no_cuts} 2.0 4 3 ${html}_L4_S2_R${i} ${results}${i} $group_3_checks ${results}[expr $i-1] $skipped_files + } elseif {$i == 4} { + quantify_run 0 $i {-no_cuts} 2.0 4 3 ${html}_L4_S2_R${i} ${results}${i} $group_4_checks ${results}[expr $i-1] $skipped_files + } elseif {$i == 5} { +# quantify_run 0 $i {-no_cuts} 4.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_5_checks ${results}[expr $i-1] $skipped_files + quantify_run 0 $i {} 6.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_5_checks ${results}[expr $i-1] $skipped_files + } elseif {($i == 6) && ("CFG_F" in $defines || "CFG_ZFINX" in $defines)} { + quantify_run 0 $i {-no_cuts} 4.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_6_checks ${results}[expr $i-1] {} + } + stop_message_log +# } + + } elseif {$pve_mode eq "DPM"} { + + if {("CFG_F" in $defines || "CFG_ZFINX" in $defines)} { + set i 7 + } else { + set i 6 + } + + start_message_log ${log}${i}.log +# quantify_run 0 $i {-no_cuts} 4.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_5_checks {} $skipped_files +# file copy -force ${cfg_dir}/DEF/QTF/qtf_results_${cfg}_DEF_R[expr $i-1] ${cfg_dir}/DEF/QTF/qtf_results_${cfg}_DEF_R[expr $i-1]-Xr +# fileutil::updateInPlace ${cfg_dir}/DEF/QTF/qtf_results_${cfg}_DEF_R[expr $i-1] [list string map [list " Xr" " U0"]] +# quantify_run 0 $i {-no_cuts} 4.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_5_checks ${cfg_dir}/DEF/QTF/qtf_results_${cfg}_DEF_R[expr $i-1] $skipped_files + quantify_run 0 $i {} 6.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_5_checks ${cfg_dir}/DEF/QTF/qtf_results_${cfg}_DEF_R[expr $i-1] $skipped_files + stop_message_log + + } elseif {$pve_mode eq "DPF"} { + + set i 8 + + start_message_log ${log}${i}.log +# quantify_run 0 $i -no_cuts 2.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_6_checks {} {} +# file copy -force ${cfg_dir}/DPM/QTF/qtf_results_${cfg}_DPM_R[expr $i-1] ${cfg_dir}/DPM/QTF/qtf_results_${cfg}_DPM_R[expr $i-1]-Xr +# fileutil::updateInPlace ${cfg_dir}/DPM/QTF/qtf_results_${cfg}_DPM_R[expr $i-1] [list string map [list " Xr" " U0"]] + quantify_run 0 $i -no_cuts 2.0 4 3 ${html}_L4_S4_R${i} ${results}${i} $group_6_checks ${cfg_dir}/DPM/QTF/qtf_results_${cfg}_DPM_R[expr $i-1] {} + stop_message_log + + } + +} + +if {$app eq "VCI"} { + + set_check_option -prover_exec_order { { disprover1 disprover3 } } -disprover1_steps 20 -disprover3_steps 20 + + set output_dir "${app_dir}/qtf_coverage_${cfg}_${pve_mode}" + set checks "[set ${pve_mode}_checks]" + set results "${cfg_dir}/${pve_mode}/QTF/qtf_results_${cfg}_${pve_mode}_R" + set log "${app_dir}/${app}_${cfg}_${pve_mode}" + + if {$pve_mode eq "DEF"} { + if {("CFG_F" in $defines || "CFG_ZFINX" in $defines)} { + set i 6 + } else { + set i 5 + } + } elseif {$pve_mode eq "DPM"} { + if {("CFG_F" in $defines || "CFG_ZFINX" in $defines)} { + set i 7 + } else { + set i 6 + } + } elseif {$pve_mode eq "DPF"} { + set i 8 + } + + start_message_log ${log}.log + puts "\n-INFO- Launching VCI Command::\nexport_quantify_coverage -call_script t.sh -generate_flist -output_dir $output_dir -checks $checks ${results}${i}\n" + export_quantify_coverage -call_script t.sh -generate_flist -output_dir $output_dir -checks $checks ${results}${i} + stop_message_log +# report_quantify_result -quantify_result qtf_results_run_${run} -html html_results_run_${run} + +} diff --git a/scripts/riscv_isa_formal/common/setup_mv.tcl b/scripts/riscv_isa_formal/common/setup_mv.tcl new file mode 100755 index 000000000..84eb4523c --- /dev/null +++ b/scripts/riscv_isa_formal/common/setup_mv.tcl @@ -0,0 +1,8 @@ +if {![info exists ::env(DESIGN_RTL_DIR)]} { + set ::env(DESIGN_RTL_DIR) [pwd]/rtl +} +set_read_hdl_option -verilog_version sv2012 -pragma_ignore {translate_} +vlog -sv -f cv32e40p_fpu_manifest.flist +elaborate +compile +set_mode mv diff --git a/scripts/riscv_isa_formal/common/t.sh b/scripts/riscv_isa_formal/common/t.sh new file mode 100755 index 000000000..eca98e09f --- /dev/null +++ b/scripts/riscv_isa_formal/common/t.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# This script is a template representing a customization to integrate OneSpin 360 with VCS simulator +# +# onespin calls the script as follows: +# template_vcs_flow.sh +# +# In this script you need to set up the environment for the simulator, +# +ARG1=$1 + +vsim -64 -c -do "source ${ARG1}; quit -f" diff --git a/scripts/riscv_isa_formal/common/vips/obi_dmem.sv b/scripts/riscv_isa_formal/common/vips/obi_dmem.sv new file mode 100755 index 000000000..7ca5866e2 --- /dev/null +++ b/scripts/riscv_isa_formal/common/vips/obi_dmem.sv @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// // +// General remarks: // +// // +// Just replace below with the name of the module you want to connect the VIP to // +// and add the appropriate parameter values and DUT signals in braces. // +// // +// Leave unused signals (and parameters that just have the default value) simply unconnected // +// because optional signals are pulled up/down appropriately in the checker file. // +// // +// The VIP uses an active LOW reset. // +// If your DUT reset signal, called "rst", is active high, use "!rst" in the instantiation // +// // +// For external interfaces (bus signals are primary inputs/outputs), set parameter ASSUME=1. // +// In that case, make sure MASTER=1 in case the DUT is the bus master (driving the address signal output), // +// or MASTER=0 in case the DUT is the bus slave (address signal is input). // +// // +// In case you instantiate the VIP several times for different interfaces in the DUT, // +// make sure to pick individual instance names (line with comment "non-ambiguous instance name" below) // +// // +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bind cv32e40p_core obi_checker #( + .ADDR_WIDTH (), // (default 32) number of bits in addr + .DATA_WIDTH (), // (default 32) number of bits in wdata, rdata + .ASSUME (1), // (default 0) switch to create assumes + .MASTER (1), // (default 0) switch to select master/slave side (when switched off, i.e., slave side, important in case of ASSUME) + .ASSERT_ON (), // (default 1) switch to generate assertions, + // useful to switch off (ASSERT_ON=0) together with ASSUME=1 just to constrain a block for Inspect + .COVER_ON (), // (default 1) switch to additionally generate cover statements + .X_CHECKING_ON(), // (default 0) switch to create no-X assertions (to be used in conjunction with x_checking_setup) + .LIVENESS_ON (), // (default 0) switch to create liveness assertions + .MAX_WAIT (`RESTRICT_DMEM_STALL_CYCLES), // (default $) number of cycles for waiting period checks (for creating liveness checks in case LIVENESS_ON=1) + .AUSER_WIDTH (), // (default 32) number of bits in auser (if used) + .WUSER_WIDTH (), // (default 32) number of bits in wuser (if used) + .RUSER_WIDTH (), // (default 32) number of bits in ruser (if used) + .ID_WIDTH (), // (default 32) number of bits in aid, rid (if used) + .MAX_OUTSTANDING_TRANSACTIONS(), // (default 2) maximum number of outstanding transactions in the system + .RESPONSE_PREDICTOR(1) // (default 0) switch to introduce a signal to predict the response at the beginning of the data phase +) obi_dmem_checker ( // non-ambiguous instance name + .clk (clk_i), // required + .reset_n(rst_ni), // required +// Address channel + .req (data_req_o), // required + .gnt (data_gnt_i), // required + .addr (data_addr_o), // required /*ADDRESS*/ + .we (data_we_o), // optional, default is 1'b0 + .be (data_be_o), // optional, default is '1 + .wdata (data_wdata_o), // required /*DATA*/ + .auser (), // optional, default is '0 + .wuser (), // optional, default is '0 + .aid (), // optional, default is '0 +// Response channel + .rvalid (data_rvalid_i), // required + .rready (), // optional, default is 1'b1 + .rdata (data_rdata_i), // required /*DATA*/ + .err (), // optional, default is 1'b0 + .ruser (), // optional, default is '0 + .rid () // optional, default is '0 +); diff --git a/scripts/riscv_isa_formal/common/vips/obi_imem.sv b/scripts/riscv_isa_formal/common/vips/obi_imem.sv new file mode 100755 index 000000000..126152246 --- /dev/null +++ b/scripts/riscv_isa_formal/common/vips/obi_imem.sv @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// // +// General remarks: // +// // +// Just replace below with the name of the module you want to connect the VIP to // +// and add the appropriate parameter values and DUT signals in braces. // +// // +// Leave unused signals (and parameters that just have the default value) simply unconnected // +// because optional signals are pulled up/down appropriately in the checker file. // +// // +// The VIP uses an active LOW reset. // +// If your DUT reset signal, called "rst", is active high, use "!rst" in the instantiation // +// // +// For external interfaces (bus signals are primary inputs/outputs), set parameter ASSUME=1. // +// In that case, make sure MASTER=1 in case the DUT is the bus master (driving the address signal output), // +// or MASTER=0 in case the DUT is the bus slave (address signal is input). // +// // +// In case you instantiate the VIP several times for different interfaces in the DUT, // +// make sure to pick individual instance names (line with comment "non-ambiguous instance name" below) // +// // +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bind cv32e40p_core obi_checker #( + .ADDR_WIDTH (), // (default 32) number of bits in addr + .DATA_WIDTH (), // (default 32) number of bits in wdata, rdata + .ASSUME (1), // (default 0) switch to create assumes + .MASTER (1), // (default 0) switch to select master/slave side (when switched off, i.e., slave side, important in case of ASSUME) + .ASSERT_ON (), // (default 1) switch to generate assertions, + // useful to switch off (ASSERT_ON=0) together with ASSUME=1 just to constrain a block for Inspect + .COVER_ON (), // (default 1) switch to additionally generate cover statements + .X_CHECKING_ON(), // (default 0) switch to create no-X assertions (to be used in conjunction with x_checking_setup) + .LIVENESS_ON (), // (default 0) switch to create liveness assertions + .MAX_WAIT (), // (default $) number of cycles for waiting period checks (for creating liveness checks in case LIVENESS_ON=1) + .AUSER_WIDTH (), // (default 32) number of bits in auser (if used) + .WUSER_WIDTH (), // (default 32) number of bits in wuser (if used) + .RUSER_WIDTH (), // (default 32) number of bits in ruser (if used) + .ID_WIDTH (), // (default 32) number of bits in aid, rid (if used) + .MAX_OUTSTANDING_TRANSACTIONS() // (default 2) maximum number of outstanding transactions in the system +) obi_imem_checker ( // non-ambiguous instance name + .clk (clk_i), // required + .reset_n(rst_ni), // required +// Address channel + .req (instr_req_o), // required + .gnt (instr_gnt_i), // required + .addr (instr_addr_o), // required /*ADDRESS*/ + .we (), // optional, default is 1'b0 + .be (), // optional, default is '1 + .wdata ('0), // required /*DATA*/ + .auser (), // optional, default is '0 + .wuser (), // optional, default is '0 + .aid (), // optional, default is '0 +// Response channel + .rvalid (instr_rvalid_i), // required + .rready (), // optional, default is 1'b1 + .rdata (instr_rdata_i), // required /*DATA*/ + .err (), // optional, default is 1'b0 + .ruser (), // optional, default is '0 + .rid () // optional, default is '0 +); diff --git a/scripts/riscv_isa_formal/launch_command example b/scripts/riscv_isa_formal/launch_command example new file mode 100755 index 000000000..6b7f3a0a3 --- /dev/null +++ b/scripts/riscv_isa_formal/launch_command example @@ -0,0 +1,58 @@ +# Setup tool and licenses +#source SourceMe + +set instructions="v1_8_0"; set name_cmd="NAME=${instructions} ; + +set config=XP ; set config_cmd="CONF=${config}" +set config=XPF0 ; set config_cmd="CONF=${config}" +set config=XPF1 ; set config_cmd="CONF=${config}" +set config=XPF2 ; set config_cmd="CONF=${config}" +set config=XPZF0 ; set config_cmd="CONF=${config}" +set config=XPZF1 ; set config_cmd="CONF=${config}" +set config=XPZF2 ; set config_cmd="CONF=${config}" + +set app=PRC ; set app_cmd="APP=${app}" +set app=QTF ; set app_cmd="APP=${app}" +set app=VCI ; set app_cmd="APP=${app}" + +set mode=DEF ; set mode_cmd="MODE=${mode}" +set mode=DPM ; set mode_cmd="MODE=${mode}" +set mode=DPF ; set mode_cmd="MODE=${mode}" + +# Prepare the working directory (common files and design copy) or reuse existing one (no copy) +set prepare="" +set prepare="PREPARE=1" + +set verbose="" +set verbose="VERBOSE=1" + +set timeout="" +set timeout="DBG=1800" + +# Interactive or batch run on local server +set gui="gui" ; set gui_cmd="GUI=1" +set gui="batch" ; set gui_cmd="" + +set my_time = `date '+%Y-%m-%d-%Hh%Mm%Ss'` ; set logname=run_${gui}-${app}-cfg_${config}-mode_${mode}-${instructions}-${my_time}.log ; echo "\n vi ${logname}\n" ; \ +echo "make ${gui_cmd} ${app_cmd} ${config_cmd} ${mode_cmd} ${name_cmd} ${verbose} ${prepare} ${timeout} all\n" > ${logname} && echo "" >>& ${logname} ; \ +/usr/bin/time make ${gui_cmd} ${app_cmd} ${config_cmd} ${mode_cmd} ${name_cmd} ${verbose} ${prepare} ${timeout} all >> & ! ${logname} & + +# Interactive or batch run on compute farm server using LSF +set gui="lsf" ; set gui_cmd="" ; set queue="long" +set gui="lsf_gui" ; set gui_cmd="GUI=1" ; set queue="gui -XF" +set gui="lsf_gui" ; set gui_cmd="GUI=1" ; set queue="gui -XF -Is -tty" + +set nb_cpus="1" +set nb_cpus="2" +set nb_cpus="4" +set nb_cpus="8" +set nb_cpus="12" +set nb_cpus="16" +set nb_cpus="24" +set nb_cpus="32" +set nb_cpus="36" +set nb_cpus="48" + +set my_time = `date '+%Y-%m-%d-%Hh%Mm%Ss'` ; set logname=run_${gui}-${app}-cfg_${config}-mode_${mode}-${instructions}-${my_time}.log ; echo "\n vi ${logname}\n" ; \ +echo "make ${gui_cmd} ${app_cmd} ${config_cmd} ${mode_cmd} ${name_cmd} ${verbose} ${prepare} ${timeout} all\n" > ${logname} && echo "" >>& ${logname} ; \ +bsub -J ${app}-cfg_${config}-mode_${mode}-${instructions} -P cv32e40p -q ${queue} -oo ${logname} -n ${nb_cpus} -R "select[cpuf>=15.0] span[hosts=1] rusage[mem=64G]" make ${gui_cmd} ${app_cmd} ${config_cmd} ${mode_cmd} ${name_cmd} ${verbose} ${prepare} ${timeout} all From 1dbddd882e33df3012f80f56a215e74a3a5adbee Mon Sep 17 00:00:00 2001 From: Pascal Gouedo Date: Mon, 3 Jun 2024 16:58:22 +0200 Subject: [PATCH 2/4] Table update for markdown rendering Signed-off-by: Pascal Gouedo --- scripts/riscv_isa_formal/README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/scripts/riscv_isa_formal/README.md b/scripts/riscv_isa_formal/README.md index 3786eebef..b9cc77557 100755 --- a/scripts/riscv_isa_formal/README.md +++ b/scripts/riscv_isa_formal/README.md @@ -4,23 +4,14 @@ RISC-V ISA Formal Verification methodology has been used with Siemens EDA Onespi ## Configurations - +--------------------+-----------------------------------------------------------------------------+ - | | **Verified Configurations** | - +====================+========+==========+==========+==========+===========+===========+===========+ | **Top Parameters** | **XP** | **XPF0** | **XPF1** | **XPF2** | **XPZF0** | **XPZF1** | **XPZF2** | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ + |--------------------|-----------------------------------------------------------------------------| | COREV_PULP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ | COREV_CLUSTER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ | FPU | 0 | 1 | 1 | 1 | 1 | 1 | 1 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ | ZFINX | 0 | 0 | 0 | 0 | 1 | 1 | 1 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ | FPU_ADDMUL_LAT | 0 | 0 | 1 | 2 | 0 | 1 | 2 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ | FPU_OTHERS_LAT | 0 | 0 | 1 | 2 | 0 | 1 | 2 | - +--------------------+--------+----------+----------+----------+-----------+-----------+-----------+ ## Tool apps From cf658a074f67b566fdd1038c7cf4658a44ce08f6 Mon Sep 17 00:00:00 2001 From: Pascal Gouedo Date: Mon, 3 Jun 2024 17:03:37 +0200 Subject: [PATCH 3/4] Table rendering Signed-off-by: Pascal Gouedo --- scripts/riscv_isa_formal/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/riscv_isa_formal/README.md b/scripts/riscv_isa_formal/README.md index b9cc77557..5fa41a7aa 100755 --- a/scripts/riscv_isa_formal/README.md +++ b/scripts/riscv_isa_formal/README.md @@ -4,8 +4,8 @@ RISC-V ISA Formal Verification methodology has been used with Siemens EDA Onespi ## Configurations - | **Top Parameters** | **XP** | **XPF0** | **XPF1** | **XPF2** | **XPZF0** | **XPZF1** | **XPZF2** | - |--------------------|-----------------------------------------------------------------------------| + | Top Parameters | XP | XPF0 | XPF1 | XPF2 | XPZF0 | XPZF1 | XPZF2 | + | :----------------- | :----: |:-------: | :------: | :------: | :-------: | :-------: | :-------: | | COREV_PULP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | COREV_CLUSTER | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | FPU | 0 | 1 | 1 | 1 | 1 | 1 | 1 | From 86c0ed676b3ea631ce4b973e1a79996a07eaa8c7 Mon Sep 17 00:00:00 2001 From: Pascal Gouedo Date: Mon, 3 Jun 2024 17:05:49 +0200 Subject: [PATCH 4/4] Cleanup Signed-off-by: Pascal Gouedo --- scripts/riscv_isa_formal/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/riscv_isa_formal/README.md b/scripts/riscv_isa_formal/README.md index 5fa41a7aa..3cb124dce 100755 --- a/scripts/riscv_isa_formal/README.md +++ b/scripts/riscv_isa_formal/README.md @@ -36,7 +36,8 @@ Contains all files to create assertions and to launch different tool apps on dif ## How to launch a run - Locally clone cv32e40p github repository or make a symbolic link to an existing repo. -- launch following command: make GUI=1 APP=PRC CONF=XP MODE=DEF NAME=v1_8_0 VERBOSE=1 PREPARE=1 all >&! run_gui-PRC-cfg_XP-mode_DEF-v1_8_0.log & +- launch following command: + make GUI=1 APP=PRC CONF=XP MODE=DEF NAME=v1_8_0 VERBOSE=1 PREPARE=1 all >&! run_gui-PRC-cfg_XP-mode_DEF-v1_8_0.log & - or use launch_command_example to launch different runs in parallel. ## Commands to launch for each configuration